/// <summary> /// Generate KDF. /// </summary> /// <param name="securitySuite">Security suite.</param> /// <param name="z">z Shared Secret.</param> /// <param name="otherInfo">Other info.</param> /// <returns></returns> public static byte[] GenerateKDF(SecuritySuite securitySuite, byte[] z, byte[] otherInfo) { GXByteBuffer bb = new GXByteBuffer(); bb.SetUInt32(1); bb.Set(z); bb.Set(otherInfo); if (securitySuite == SecuritySuite.Ecdsa256) { using (SHA256 sha = new SHA256CryptoServiceProvider()) { return(sha.ComputeHash(bb.Array())); } } else if (securitySuite == SecuritySuite.Ecdsa384) { using (SHA384 sha = new SHA384CryptoServiceProvider()) { return(sha.ComputeHash(bb.Array())); } } else { throw new ArgumentOutOfRangeException("Invalid sevurity suite."); } }
/// <summary> /// Generate User information initiate request. /// </summary> /// <param name="settings">DLMS settings.</param> /// <param name="cipher"></param> /// <param name="data"></param> private static void GetInitiateRequest(GXDLMSSettings settings, GXICipher cipher, GXByteBuffer data) { // Tag for xDLMS-Initiate request data.SetUInt8(GXCommon.InitialRequest); // Usage field for dedicated-key component. Not used data.SetUInt8(0x00); //encoding of the response-allowed component (BOOLEAN DEFAULT TRUE) // usage flag (FALSE, default value TRUE conveyed) data.SetUInt8(0); // Usage field of the proposed-quality-of-service component. Not used data.SetUInt8(0x00); data.SetUInt8(settings.DLMSVersion); // Tag for conformance block data.SetUInt8(0x5F); data.SetUInt8(0x1F); // length of the conformance block data.SetUInt8(0x04); // encoding the number of unused bits in the bit string data.SetUInt8(0x00); if (settings.UseLogicalNameReferencing) { data.Set(settings.LnSettings.ConformanceBlock); } else { data.Set(settings.SnSettings.ConformanceBlock); } data.SetUInt16(settings.MaxReceivePDUSize); }
/// <summary> /// Agree on global unicast encryption key. /// </summary> /// <param name="client"> DLMS client that is used to generate action.</param> /// <param name="key"> List of keys.</param> /// <returns>Generated action.</returns> public byte[][] KeyAgreement(GXDLMSSecureClient client) { if (Version == 0) { throw new ArgumentException("Public and private key isn't implemented for version 0."); } if (client.Ciphering.EphemeralKeyPair.Value == null) { throw new ArgumentException("Invalid Ephemeral key."); } if (client.Ciphering.SigningKeyPair.Value == null) { throw new ArgumentException("Invalid Signiture key."); } GXByteBuffer bb = new GXByteBuffer(); //Add Ephemeral public key. bb.Set(client.Ciphering.EphemeralKeyPair.Value.RawValue, 1, client.Ciphering.EphemeralKeyPair.Value.RawValue.Length - 1); //Add signature. byte[] sign = GXSecure.GetEphemeralPublicKeySignature(0, client.Ciphering.EphemeralKeyPair.Value, client.Ciphering.SigningKeyPair.Key); bb.Set(sign); List <KeyValuePair <GlobalKeyType, byte[]> > list = new List <KeyValuePair <GlobalKeyType, byte[]> >(); list.Add(new KeyValuePair <GlobalKeyType, byte[]>(GlobalKeyType.UnicastEncryption, bb.Array())); return(KeyAgreement(client, list)); }
void OnShowDlg(GXActionArgs arg) { if (InvokeRequired) { BeginInvoke(new ShowDlgEventHandler(OnShowDlg), arg).AsyncWaitHandle.WaitOne(); } else { GXDLMSIp6Setup target = Target as GXDLMSIp6Setup; if (arg.Index == 5) { GXClockPresetTimeDlg dlg = new GXClockPresetTimeDlg(); if (dlg.ShowDialog(this) == DialogResult.OK) { GXByteBuffer bb = new GXByteBuffer(); bb.SetUInt8((byte)DataType.Structure); bb.SetUInt8(4); //Add data type and length. bb.SetUInt8((byte)DataType.OctetString); bb.SetUInt8(12); bb.Set(GXDLMSTranslator.HexToBytes(dlg.PresetTime.ToHex(false, GXDlmsUi.UseMeterTimeZone))); //Add data type and length. bb.SetUInt8((byte)DataType.OctetString); bb.SetUInt8(12); bb.Set(GXDLMSTranslator.HexToBytes(dlg.IntervalStart.ToHex(false, GXDlmsUi.UseMeterTimeZone))); //Add data type and length. bb.SetUInt8((byte)DataType.OctetString); bb.SetUInt8(12); bb.Set(GXDLMSTranslator.HexToBytes(dlg.IntervalEnd.ToHex(false, GXDlmsUi.UseMeterTimeZone))); arg.Value = bb.Array(); } else { arg.Handled = true; } } else if (arg.Index == 6) { GXTextDlg dlg = new GXTextDlg("Shift Time", "Shift Time (s):", "", typeof(Int16)); if (dlg.ShowDialog(this) == DialogResult.OK) { arg.Value = Int16.Parse(dlg.GetValue()); } else { arg.Handled = true; } } else { arg.Handled = true; } } }
/// <summary> /// Code application context name. /// </summary> /// <param name="settings">DLMS settings.</param> /// <param name="data">Byte buffer where data is saved.</param> /// <param name="cipher">Is ciphering settings.</param> private static void GenerateApplicationContextName(GXDLMSSettings settings, GXByteBuffer data, GXICipher cipher) { //Application context name tag data.SetUInt8(((byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.ApplicationContextName)); //Len data.SetUInt8(0x09); data.SetUInt8(BerType.ObjectIdentifier); //Len data.SetUInt8(0x07); bool ciphered = cipher != null && cipher.IsCiphered(); if (settings.UseLogicalNameReferencing) { if (ciphered) { data.Set(GXCommon.LogicalNameObjectIdWithCiphering); } else { data.Set(GXCommon.LogicalNameObjectID); } } else { if (ciphered) { data.Set(GXCommon.ShortNameObjectIdWithCiphering); } else { data.Set(GXCommon.ShortNameObjectID); } } //Add system title if cipher or GMAC authentication is used.. if (!settings.IsServer && (ciphered || settings.Authentication == Authentication.HighGMAC)) { if (cipher.SystemTitle == null || cipher.SystemTitle.Length == 0) { throw new ArgumentNullException("SystemTitle"); } //Add calling-AP-title data.SetUInt8(((byte)BerType.Context | (byte)BerType.Constructed | 6)); //LEN data.SetUInt8((byte)(2 + cipher.SystemTitle.Length)); data.SetUInt8((byte)BerType.OctetString); //LEN data.SetUInt8((byte)cipher.SystemTitle.Length); data.Set(cipher.SystemTitle); } }
///<summary> ///Retrieves the string that indicates the level of authentication, if any. ///</summary> private static void GetAuthenticationString(GXDLMSSettings settings, GXByteBuffer data) { //If authentication is used. if (settings.Authentication != Authentication.None) { //Add sender ACSE-requirements field component. data.SetUInt8((byte)BerType.Context | (byte)PduType.SenderAcseRequirements); data.SetUInt8(2); data.SetUInt8(BerType.BitString | BerType.OctetString); data.SetUInt8(0x80); data.SetUInt8((byte)BerType.Context | (byte)PduType.MechanismName); //Len data.SetUInt8(7); // OBJECT IDENTIFIER byte[] p = { (byte)0x60, (byte)0x85, (byte)0x74, (byte)0x05, (byte)0x08, (byte)0x02, (byte)settings.Authentication }; data.Set(p); //Add Calling authentication information. int len = 0; byte[] pw = null; if (settings.Authentication < Authentication.HighMD5) { pw = settings.Password; if (pw != null) { len = pw.Length; } } else { pw = settings.CtoSChallenge; if (pw != null) { len = pw.Length; } } data.SetUInt8((byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.CallingAuthenticationValue); //0xAC //Len data.SetUInt8((byte)(2 + len)); //Add authentication information. data.SetUInt8((byte)BerType.Context); //Len. data.SetUInt8((byte)len); if (pw != null) { data.Set(pw); } } }
/// <summary> /// Sign given data using public and private key. /// </summary> /// <param name="data">Data to sign.</param> /// <returns>Signature</returns> public byte[] Sign(byte[] data) { if (PrivateKey == null) { throw new ArgumentException("Invalid private key."); } GXBigInteger msg; if (PrivateKey.Scheme == Ecc.P256) { using (SHA256 sha = new SHA256CryptoServiceProvider()) { msg = new GXBigInteger(sha.ComputeHash(data)); } } else { using (SHA384 sha = new SHA384CryptoServiceProvider()) { msg = new GXBigInteger(sha.ComputeHash(data)); } } GXBigInteger pk = new GXBigInteger(PrivateKey.RawValue); GXEccPoint p; GXBigInteger n; GXBigInteger r; GXBigInteger s; do { n = GetRandomNumber(PrivateKey.Scheme); p = new GXEccPoint(curve.G.x, curve.G.y, new GXBigInteger(1)); Multiply(p, n, curve.N, curve.A, curve.P); r = p.x; r.Mod(curve.N); n.Inv(curve.N); //s s = new GXBigInteger(r); s.Multiply(pk); s.Add(msg); s.Multiply(n); s.Mod(curve.N); } while (r.IsZero || s.IsZero); GXByteBuffer signature = new GXByteBuffer(); signature.Set(r.ToArray()); signature.Set(s.ToArray()); return(signature.Array()); }
internal static void SetValue(GXByteBuffer buff, object data) { GXByteBuffer tmp = new GXByteBuffer(); tmp.Add(data); buff.Add((byte)tmp.Size); buff.Set(tmp.Array()); }
static public void WriteLog(string text, byte[] value) { string str = DateTime.Now.ToLongTimeString() + " " + text; //Show data as hex. if ((LogLevel & 1) != 0) { if (value != null) { str += "\r\n" + GXCommon.ToHex(value, true); } System.Diagnostics.Trace.WriteLine(str); } //Show data as xml. if ((LogLevel & 2) != 0) { receivedTraceData.Set(value); try { GXByteBuffer pdu = new GXByteBuffer(); InterfaceType type = GXDLMSTranslator.GetDlmsFraming(receivedTraceData); if (translator.FindNextFrame(receivedTraceData, pdu, type)) { System.Diagnostics.Trace.WriteLine(translator.MessageToXml(receivedTraceData)); receivedTraceData.Clear(); } } catch (Exception) { receivedTraceData.Clear(); } } }
/// <summary> /// Generate user information. /// </summary> /// <param name="settings">DLMS settings.</param> /// <param name="cipher"></param> /// <param name="data">Generated user information.</param> static internal void GenerateUserInformation(GXDLMSSettings settings, GXICipher cipher, GXByteBuffer data) { data.SetUInt8((byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.UserInformation); if (cipher == null || !cipher.IsCiphered()) { //Length for AARQ user field data.SetUInt8(0x10); //Coding the choice for user-information (Octet STRING, universal) data.SetUInt8(BerType.OctetString); //Length data.SetUInt8(0x0E); GetInitiateRequest(settings, cipher, data); } else { GXByteBuffer tmp = new GXByteBuffer(); GetInitiateRequest(settings, cipher, tmp); byte[] crypted = cipher.Encrypt(0x21, cipher.SystemTitle, tmp.Array()); //Length for AARQ user field data.SetUInt8((byte)(2 + crypted.Length)); //Coding the choice for user-information (Octet STRING, universal) data.SetUInt8(BerType.OctetString); data.SetUInt8((byte)crypted.Length); data.Set(crypted); } }
/// <summary> /// Read DLMS Data from the device. /// </summary> /// <remarks> /// If access is denied return null. /// </remarks> /// <param name="data">Data to send.</param> /// <returns>Received data.</returns> public void ReadDLMSPacket(byte[] data, GXReplyData reply) { if ((data == null || data.Length == 0) && !reply.IsStreaming()) { return; } GXReplyData notify = new GXReplyData(); reply.Error = 0; object eop = (byte)0x7E; //In network connection terminator is not used. if (client.InterfaceType == InterfaceType.WRAPPER && !parent.UseRemoteSerial) { eop = null; } ReceiveParameters <byte[]> p = new ReceiveParameters <byte[]>() { AllData = false, Eop = eop, Count = 5, WaitTime = parent.WaitTime * 1000, }; var answer = Send(data); GXByteBuffer rd = new GXByteBuffer(answer.Body); try { //Loop until whole COSEM packet is received. while (!client.GetData(rd, reply, notify)) { p.Reply = null; if (notify.Data.Size != 0) { // Handle notify. if (!notify.IsMoreData) { rd.Trim(); notify.Clear(); p.Eop = eop; } continue; } //If Eop is not set read one byte at time. if (p.Eop == null) { p.Count = client.GetFrameSize(rd); } rd.Set(p.Reply); } } catch (Exception ex) { throw ex; } if (reply.Error != 0) { throw new GXDLMSException(reply.Error); } }
public override sealed string ToString() { string str; switch (Value.Length) { case 1: str = Convert.ToString(ToByte()); break; case 2: str = Convert.ToString(ToShort()); break; case 4: str = Convert.ToString(ToInt()); break; case 8: str = Convert.ToString(ToLong()); break; default: GXByteBuffer bb = new GXByteBuffer(); bb.Set(Value); str = bb.GetUInt64().ToString(); break; } return(str); }
internal static byte[] Decrypt(AesGcmParameter p, GXByteBuffer data) { byte[] tmp = GXDLMSChippering.DecryptAesGcm(p, data); data.Clear(); data.Set(tmp); return(tmp); }
/// <summary> /// Update template description. /// </summary> public void UpdateTemplateDescription() { lock (this) { GXByteBuffer bb = new GXByteBuffer(); Buffer = null; bb.SetUInt8((byte)DataType.Structure); GXCommon.SetObjectCount(CaptureObjects.Count, bb); foreach (GXKeyValuePair <GXDLMSObject, GXDLMSCaptureObject> it in CaptureObjects) { DataType dt = (it.Key as IGXDLMSBase).GetDataType(it.Value.AttributeIndex); if (dt == DataType.Array || dt == DataType.Structure) { ValueEventArgs e = new ValueEventArgs(null, it.Value.AttributeIndex, 0, null); GXByteBuffer data = new GXByteBuffer(); object v = ((IGXDLMSBase)it.Key).GetValue(null, e); if (v is byte[]) { data.Set((byte[])v); } else { data = (GXByteBuffer)v; } UpdateTemplateDescription(bb, data, ((GXDLMSCaptureObject)it.Value).DataIndex - 1); } else { bb.SetUInt8(dt); } } TemplateDescription = bb.Array(); } }
/// <summary> /// Constructor. /// </summary> /// <param name="forTarget"></param> /// <param name="forCommand"></param> /// <param name="forType"></param> public GXDLMSLongTransaction(ValueEventArgs[] forTargets, Command forCommand, GXByteBuffer forData) { targets = forTargets; command = forCommand; data = new GXByteBuffer(); data.Set(forData.Data, forData.Position, forData.Size - forData.Position); }
/// <summary> /// Constructor. /// </summary> /// <param name="forTarget"></param> /// <param name="forCommand"></param> /// <param name="forData"></param> public GXDLMSLongTransaction(ValueEventArgs[] forTargets, Command forCommand, GXByteBuffer forData) { targets = forTargets; command = forCommand; data = new GXByteBuffer(); data.Set(forData.Data, forData.Position, forData.Size - forData.Position); }
/// <summary> /// Check that this is correct public key. /// </summary> /// <remarks> /// This method can be used to verify that public and private key are on the curve. /// </remarks> public static void Validate(GXPublicKey publicKey) { if (publicKey == null) { throw new ArgumentNullException("Invalid public key."); } GXByteBuffer bb = new GXByteBuffer(); bb.Set(publicKey.RawValue); int size = SchemeSize(publicKey.Scheme); GXBigInteger x = new GXBigInteger(bb.SubArray(1, size)); GXBigInteger y = new GXBigInteger(bb.SubArray(1 + size, size)); GXCurve curve = new GXCurve(publicKey.Scheme); y.Multiply(y); y.Mod(curve.P); GXBigInteger tmpX = new GXBigInteger(x); tmpX.Multiply(x); tmpX.Mod(curve.P); tmpX.Add(curve.A); tmpX.Multiply(x); tmpX.Add(curve.B); tmpX.Mod(curve.P); if (y.Compare(tmpX) != 0) { throw new ArgumentException("Public key validate failed. Public key is not valid ECDSA public key."); } }
/// <summary> /// Constructor value. /// </summary> /// <param name="value">Byte array Data in MSB format.</param> public GXBigInteger(byte[] value) { GXByteBuffer bb = new GXByteBuffer(); bb.Set(value); FromByteBuffer(bb); }
/// <summary> /// Try to find client and server address from the meter. /// </summary> private void DiscoverMeters(object sender, GXAsyncWork work, object[] parameters) { GXDLMSClient cl = new GXDLMSClient(true, 16, 1, Authentication.None, null, (InterfaceType)Settings.Default.PlcInterface); byte[] data = cl.Plc.DiscoverRequest(); ReceiveParameters <byte[]> p = new ReceiveParameters <byte[]>() { AllData = false, Count = 8, WaitTime = 10000, }; DateTime start = DateTime.Now; GXByteBuffer rd = new GXByteBuffer(); lock (media.Synchronous) { if (data != null) { media.Send(data, null); start = DateTime.Now; } GXReplyData reply = new GXReplyData(); rd = new GXByteBuffer(p.Reply); try { while (!work.IsCanceled) { p.Reply = null; //If Eop is not set read one byte at time. if (p.Eop == null) { p.Count = cl.GetFrameSize(rd); } if (!media.IsOpen) { throw new InvalidOperationException("Media is closed."); } if (!media.Receive(p)) { //It's OK if there is no reply. Read again continue; } rd.Position = 0; rd.Set(p.Reply); if (cl.GetData(rd, reply)) { List <GXDLMSPlcMeterInfo> list = cl.Plc.ParseDiscover(reply.Data, (UInt16)reply.TargetAddress, (UInt16)reply.SourceAddress); BeginInvoke(new AppendMeterEventHandler(OnAppendMeter), list); } } } catch (Exception) { //Throw original exception. throw; } } }
Security GXICipher.Decrypt(byte[] title, GXByteBuffer data) { AesGcmParameter p = new AesGcmParameter(title, BlockCipherKey, AuthenticationKey); byte[] tmp = GXDLMSChippering.DecryptAesGcm(p, data); data.Clear(); data.Set(tmp); return(p.Security); }
/// <summary> /// Copies the values of the objects to capture /// into the buffer by reading capture objects. /// </summary> internal void Capture(GXDLMSServer server) { lock (this) { GXByteBuffer bb = new GXByteBuffer(); ValueEventArgs[] args = new ValueEventArgs[] { new ValueEventArgs(server, this, 2, 0, null) }; Buffer = null; if (server != null) { server.PreGet(args); } if (!args[0].Handled) { foreach (GXKeyValuePair <GXDLMSObject, GXDLMSCaptureObject> it in CaptureObjects) { ValueEventArgs e = new ValueEventArgs(server, it.Key, it.Value.AttributeIndex, 0, null); object value = (it.Key as IGXDLMSBase).GetValue(server == null ? null : server.Settings, e); DataType dt = (it.Key as IGXDLMSBase).GetDataType(it.Value.AttributeIndex); if ((value is byte[] || value is GXByteBuffer[]) && (dt == DataType.Structure || dt == DataType.Array)) { GXByteBuffer tmp; if (value is byte[]) { tmp = new GXByteBuffer((byte[])value); } else { tmp = (GXByteBuffer)value; } CaptureArray(server, tmp, bb, it.Value.DataIndex - 1); } else { GXByteBuffer tmp = new GXByteBuffer(); GXCommon.SetData(server == null ? null : server.Settings, tmp, dt, value); //If data is empty. if (tmp.Size == 1) { bb.SetUInt8(0); } else { tmp.Position = 1; bb.Set(tmp); } } } Buffer = bb.Array(); } if (server != null) { server.PostGet(args); server.NotifyAction(args); server.NotifyPostAction(args); } } }
/// <summary> /// Convert compact data buffer to array of values. /// </summary> /// <param name="templateDescription">Template description byte array.</param> /// <param name="buffer">Buffer byte array.</param> /// <returns>Values from byte buffer.</returns> public List <object> GetValues(byte[] templateDescription, byte[] buffer) { //If templateDescription or buffer is not given. if (templateDescription == null || buffer == null || templateDescription.Length == 0 || buffer.Length == 0) { throw new ArgumentException(); } GXDataInfo info = new GXDataInfo(); object tmp; GXByteBuffer data = new GXByteBuffer(); data.Set(templateDescription); GXCommon.SetObjectCount(buffer.Length, data); data.Set(buffer); info.Type = DataType.CompactArray; tmp = GXCommon.GetData(null, data, info); return((List <object>)tmp); }
/// <summary> /// Get public key from private key. /// </summary> /// <param name="scheme">Used scheme.</param> /// <param name="privateKey">Private key bytes.</param> /// <returns>Public key.</returns> public GXPublicKey GetPublicKey() { GXBigInteger secret = new GXBigInteger(RawValue); GXCurve curve = new GXCurve(Scheme); GXEccPoint p = new GXEccPoint(curve.G.x, curve.G.y, new GXBigInteger(1)); p = GXEcdsa.JacobianMultiply(p, secret, curve.N, curve.A, curve.P); GXEcdsa.FromJacobian(p, curve.P); GXByteBuffer key = new GXByteBuffer(65); //Public key is un-compressed format. key.SetUInt8(4); byte[] tmp = p.x.ToArray(); key.Set(tmp, tmp.Length % 32, 32); tmp = p.y.ToArray(); key.Set(tmp, tmp.Length % 32, 32); return(GXPublicKey.FromRawBytes(key.Array())); }
public static List <object> GetData(byte[] columns, byte[] value, bool AppendAA) { if (columns == null || columns.Length == 0 || value == null || value.Length == 0) { return(new GXArray()); } List <DataType> list = new List <DataType>(); GXDataInfo info = new GXDataInfo(); info.AppendAA = AppendAA; GXByteBuffer bb = new GXByteBuffer(); bb.Set(columns); GXCommon.SetObjectCount(value.Length, bb); bb.Set(value); List <object> tmp = (List <object>)GXCommon.GetCompactArray(null, bb, info, false); return(tmp); }
/// <summary> /// Get public key from private key. /// </summary> /// <param name="scheme">Used scheme.</param> /// <param name="privateKey">Private key bytes.</param> /// <returns>Public key.</returns> public GXPublicKey GetPublicKey() { if (publicKey == null) { GXBigInteger pk = new GXBigInteger(RawValue); GXCurve curve = new GXCurve(Scheme); GXEccPoint p = new GXEccPoint(curve.G.x, curve.G.y, new GXBigInteger(1)); p = GXEcdsa.JacobianMultiply(p, pk, curve.N, curve.A, curve.P); GXEcdsa.FromJacobian(p, curve.P); GXByteBuffer key = new GXByteBuffer(65); //Public key is un-compressed format. key.SetUInt8(4); byte[] tmp = p.x.ToArray(); int size = Scheme == Ecc.P256 ? 32 : 48; key.Set(tmp, tmp.Length % size, size); tmp = p.y.ToArray(); key.Set(tmp, tmp.Length % size, size); publicKey = GXPublicKey.FromRawBytes(key.Array()); } return(publicKey); }
/// <summary> /// Sends data to the M-Bus slave device. /// </summary> /// <param name="client">DLMS client settings.</param> /// <param name="data">data to send</param> /// <returns>Generated DLMS data.</returns> public byte[][] SendData(GXDLMSClient client, GXMBusClientData[] data) { GXByteBuffer bb = new GXByteBuffer(); bb.SetUInt8(DataType.Array); bb.SetUInt8(DataType.Structure); GXCommon.SetObjectCount(data.Length, bb); foreach (GXMBusClientData it in data) { bb.SetUInt8(DataType.Structure); bb.SetUInt8(3); bb.SetUInt8(DataType.OctetString); GXCommon.SetObjectCount(it.DataInformation.Length, bb); bb.Set(it.DataInformation); bb.SetUInt8(DataType.OctetString); GXCommon.SetObjectCount(it.ValueInformation.Length, bb); bb.Set(it.ValueInformation); GXCommon.SetData(client.Settings, bb, GXDLMSConverter.GetDLMSDataType(it.Data), it.Data); } return(client.Method(this, 6, bb.Array(), DataType.Array)); }
/// <summary> /// Generate GMAC password from given challenge. /// </summary> /// <param name="challenge"></param> /// <returns></returns> public byte[] GenerateGmacPassword(byte[] challenge) { AesGcmParameter p = new AesGcmParameter(0x10, Gurux.DLMS.Enums.Security.Authentication, InvocationCounter, systemTitle, BlockCipherKey, AuthenticationKey); GXByteBuffer bb = new GXByteBuffer(); GXDLMSChippering.EncryptAesGcm(p, challenge); bb.SetUInt8(0x10); bb.SetUInt32(InvocationCounter); bb.Set(p.CountTag); return(bb.Array()); }
/// <summary> /// Generate KDF. /// </summary> /// <param name="securitySuite">Used security suite.</param> /// <param name="z">Shared Secret.</param> /// <param name="algorithmID">Algorithm ID.</param> /// <param name="partyUInfo">Sender system title.</param> /// <param name="partyVInfo">Receiver system title.</param> /// <param name="suppPubInfo">Not used in DLMS.</param> /// <param name="suppPrivInfo">Not used in DLMS.</param> /// <returns></returns> public static byte[] GenerateKDF(SecuritySuite securitySuite, byte[] z, AlgorithmId algorithmID, byte[] partyUInfo, byte[] partyVInfo, byte[] suppPubInfo, byte[] suppPrivInfo) { GXByteBuffer bb = new GXByteBuffer(); bb.Set(new byte[] { 0x60, 0x85, 0x74, 0x05, 0x08, 0x03, (byte)algorithmID }); bb.Set(partyUInfo); bb.Set(partyVInfo); if (suppPubInfo != null) { bb.Set(suppPubInfo); } if (suppPrivInfo != null) { bb.Set(suppPrivInfo); } return(GenerateKDF(securitySuite, z, bb.Array())); }
public static object[][] GetData(byte[] columns, byte[] value, bool AppendAA) { List <object[]> row = new List <object[]>(); if (columns == null || columns.Length == 0 || value == null || value.Length == 0) { return(row.ToArray()); } List <DataType> list = new List <DataType>(); GXDataInfo info = new GXDataInfo(); info.AppendAA = AppendAA; GXByteBuffer bb = new GXByteBuffer(); bb.Set(columns); GXCommon.SetObjectCount(value.Length, bb); bb.Set(value); object[] tmp = (object[])GXCommon.GetCompactArray(null, bb, info, false); row.Add((object[])tmp[0]); return(row.ToArray()); }
byte[] IGXDLMSBase.Invoke(GXDLMSSettings settings, int index, Object parameters) { //Check reply_to_HLS_authentication if (index == 1) { UInt32 ic = 0; byte[] secret; if (settings.Authentication == Authentication.HighGMAC) { secret = settings.SourceSystemTitle; GXByteBuffer bb = new GXByteBuffer(parameters as byte[]); bb.GetUInt8(); ic = bb.GetUInt32(); } else { secret = Secret; } byte[] serverChallenge = GXSecure.Secure(settings, settings.Cipher, ic, settings.StoCChallenge, secret); byte[] clientChallenge = (byte[])parameters; if (GXCommon.Compare(serverChallenge, clientChallenge)) { if (settings.Authentication == Authentication.HighGMAC) { secret = settings.Cipher.SystemTitle; } else { secret = Secret; } ic = settings.Cipher.FrameCounter; byte[] tmp = GXSecure.Secure(settings, settings.Cipher, ic, settings.CtoSChallenge, secret); GXByteBuffer challenge = new GXByteBuffer(); // ReturnParameters. challenge.SetUInt8(1); challenge.SetUInt8(0); challenge.SetUInt8((byte)DataType.OctetString); GXCommon.SetObjectCount(tmp.Length, challenge); challenge.Set(tmp); return(challenge.Array()); } else { throw new ArgumentException("Invoke failed. Invalid attribute index."); } } else { throw new ArgumentException("Invoke failed. Invalid attribute index."); } }
object IGXDLMSBase.GetValue(GXDLMSSettings settings, ValueEventArgs e) { GXByteBuffer bb; switch (e.Index) { case 1: return(GXCommon.LogicalNameToBytes(LogicalName)); case 2: return(Token); case 3: return(Time); case 4: bb = new GXByteBuffer(); bb.SetUInt8(DataType.Array); if (Descriptions == null) { bb.SetUInt8(0); } else { bb.SetUInt8((byte)Descriptions.Count); foreach (string it in Descriptions) { bb.SetUInt8(DataType.OctetString); bb.SetUInt8((byte)it.Length); bb.Set(ASCIIEncoding.ASCII.GetBytes(it)); } } return(bb.Array()); case 5: return(DeliveryMethod); case 6: bb = new GXByteBuffer(); bb.SetUInt8(DataType.Structure); bb.SetUInt8(2); GXCommon.SetData(settings, bb, DataType.Enum, StatusCode); GXCommon.SetData(settings, bb, DataType.BitString, DataValue); return(bb.Array()); default: e.Error = ErrorCode.ReadWriteDenied; break; } return(null); }
///<summary> ///Retrieves the string that indicates the level of authentication, if any. ///</summary> private static void GetAuthenticationString(GXDLMSSettings settings, GXByteBuffer data) { //If authentication is used. if (settings.Authentication != Authentication.None) { //Add sender ACSE-requirements field component. data.SetUInt8((byte)BerType.Context | (byte)PduType.SenderAcseRequirements); data.SetUInt8(2); data.SetUInt8(BerType.BitString | BerType.OctetString); data.SetUInt8(0x80); data.SetUInt8((byte)BerType.Context | (byte)PduType.MechanismName); //Len data.SetUInt8(7); // OBJECT IDENTIFIER byte[] p = { (byte)0x60, (byte)0x85, (byte)0x74, (byte)0x05, (byte)0x08, (byte)0x02, (byte)settings.Authentication }; data.Set(p); //Add Calling authentication information. int len = 0; byte[] callingAuthenticationValue = null; if (settings.Authentication == Authentication.Low) { if (settings.Password != null) { callingAuthenticationValue = settings.Password; len = callingAuthenticationValue.Length; } } else { callingAuthenticationValue = settings.CtoSChallenge; len = callingAuthenticationValue.Length; } //0xAC data.SetUInt8((byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.CallingAuthenticationValue); //Len data.SetUInt8((byte)(2 + len)); //Add authentication information. data.SetUInt8((byte)BerType.Context); //Len. data.SetUInt8((byte)len); if (len != 0) { data.Set(callingAuthenticationValue); } } }
/// <summary> /// Generate User information initiate request. /// </summary> /// <param name="settings">DLMS settings.</param> /// <param name="cipher"></param> /// <param name="data"></param> private static void GetInitiateRequest(GXDLMSSettings settings, GXICipher cipher, GXByteBuffer data) { // Tag for xDLMS-Initiate request data.SetUInt8((byte)Command.InitiateRequest); // Usage field for dedicated-key component. Not used data.SetUInt8(0x00); //encoding of the response-allowed component (BOOLEAN DEFAULT TRUE) // usage flag (FALSE, default value TRUE conveyed) data.SetUInt8(0); // Usage field of the proposed-quality-of-service component. Not used data.SetUInt8(0x00); data.SetUInt8(settings.DLMSVersion); // Tag for conformance block data.SetUInt8(0x5F); data.SetUInt8(0x1F); // length of the conformance block data.SetUInt8(0x04); // encoding the number of unused bits in the bit string data.SetUInt8(0x00); if (settings.UseLogicalNameReferencing) { data.Set(settings.LnSettings.ConformanceBlock); } else { data.Set(settings.SnSettings.ConformanceBlock); } data.SetUInt16(settings.MaxPduSize); }
/// <summary> /// Generate user information. /// </summary> /// <param name="settings">DLMS settings.</param> /// <param name="cipher"></param> /// <param name="data">Generated user information.</param> static internal void GenerateUserInformation(GXDLMSSettings settings, GXICipher cipher, GXByteBuffer encryptedData, GXByteBuffer data) { data.SetUInt8((byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.UserInformation); if (cipher == null || !cipher.IsCiphered()) { //Length for AARQ user field data.SetUInt8(0x10); //Coding the choice for user-information (Octet STRING, universal) data.SetUInt8(BerType.OctetString); //Length data.SetUInt8(0x0E); GetInitiateRequest(settings, cipher, data); } else { if (encryptedData != null && encryptedData.Size != 0) { //Length for AARQ user field data.SetUInt8((byte)(4 + encryptedData.Size)); //Tag data.SetUInt8(BerType.OctetString); data.SetUInt8((byte)(2 + encryptedData.Size)); //Coding the choice for user-information (Octet STRING, universal) data.SetUInt8((byte)Command.GloInitiateRequest); data.SetUInt8((byte)encryptedData.Size); data.Set(encryptedData); } else { GXByteBuffer tmp = new GXByteBuffer(); GetInitiateRequest(settings, cipher, tmp); byte[] crypted = cipher.Encrypt((byte)Command.GloInitiateRequest, cipher.SystemTitle, tmp.Array()); //Length for AARQ user field data.SetUInt8((byte)(2 + crypted.Length)); //Coding the choice for user-information (Octet STRING, universal) data.SetUInt8(BerType.OctetString); data.SetUInt8((byte)crypted.Length); data.Set(crypted); } } }
/// <summary> /// Parse User Information from PDU. /// </summary> public static void ParseUserInformation(GXDLMSSettings settings, GXICipher cipher, GXByteBuffer data, GXDLMSTranslatorStructure xml) { byte len = data.GetUInt8(); GXByteBuffer tmp2 = new GXByteBuffer(); tmp2.SetUInt8(0); if (data.Size - data.Position < len) { throw new Exception("Not enough data."); } if (xml != null && xml.OutputType == TranslatorOutputType.StandardXml) { len = (byte)(data.Size - data.Position); xml.AppendLine(Command.InitiateRequest, null, GXCommon .ToHex(data.Data, false, data.Position, len)); data.Position = data.Position + len; return; } //Excoding the choice for user information int tag = data.GetUInt8(); if (tag != 0x4) { throw new Exception("Invalid tag."); } len = data.GetUInt8(); //Tag for xDLMS-Initate.response tag = data.GetUInt8(); if (tag == (byte)Command.GloInitiateResponse) { if (xml != null) { int cnt = GXCommon.GetObjectCount(data); byte[] tmp = new byte[cnt]; data.Get(tmp); //<glo_InitiateResponse> xml.AppendLine(Command.GloInitiateResponse, "Value", GXCommon.ToHex(tmp, false)); return; } --data.Position; cipher.Security = cipher.Decrypt(settings.SourceSystemTitle, data); tag = data.GetUInt8(); } else if (tag == (byte)Command.GloInitiateRequest) { if (xml != null) { int cnt = GXCommon.GetObjectCount(data); byte[] tmp = new byte[cnt]; data.Get(tmp); //<glo_InitiateRequest> xml.AppendLine(Command.GloInitiateRequest, "Value", GXCommon.ToHex(tmp, false)); return; } --data.Position; cipher.Security = cipher.Decrypt(settings.SourceSystemTitle, data); tag = data.GetUInt8(); } bool response = tag == (byte)Command.InitiateResponse; if (response) { if (xml != null) { //<InitiateResponse> xml.AppendStartTag(Command.InitiateResponse); } //Optional usage field of the negotiated quality of service component tag = data.GetUInt8(); len = 0; if (tag != 0)//Skip if used. { len = data.GetUInt8(); data.Position += len; if (len == 0 && xml != null) { //NegotiatedQualityOfService xml.AppendLine(TranslatorGeneralTags.NegotiatedQualityOfService, "Value", "00"); } } } else if (tag == (byte)Command.InitiateRequest) { if (xml != null) { //<InitiateRequest> xml.AppendStartTag(Command.InitiateRequest); } //Optional usage field of the negotiated quality of service component tag = data.GetUInt8(); //CtoS. if (tag != 0) { len = data.GetUInt8(); settings.CtoSChallenge = new byte[len]; data.Get(settings.CtoSChallenge); } //Optional usage field of the negotiated quality of service component tag = data.GetUInt8(); if (tag != 0)//Skip if used. { len = data.GetUInt8(); data.Position += len; } //Optional usage field of the proposed quality of service component tag = data.GetUInt8(); if (tag != 0)//Skip if used. { len = data.GetUInt8(); data.Position += len; } } else { throw new Exception("Invalid tag."); } //Get DLMS version number. if (!response) { if (data.GetUInt8() != 6) { throw new Exception("Invalid DLMS version number."); } //ProposedDlmsVersionNumber if (xml != null) { xml.AppendLine(TranslatorGeneralTags.ProposedDlmsVersionNumber, "Value", xml.IntegerToHex(settings.DLMSVersion, 2)); } } else { if (data.GetUInt8() != 6) { throw new Exception("Invalid DLMS version number."); } if (xml != null) { xml.AppendLine(TranslatorGeneralTags.NegotiatedDlmsVersionNumber, "Value", xml.IntegerToHex(settings.DLMSVersion, 2)); } } //Tag for conformance block tag = data.GetUInt8(); if (tag != 0x5F) { throw new Exception("Invalid tag."); } //Old Way... if (data.GetUInt8(data.Position) == 0x1F) { data.GetUInt8(); } len = data.GetUInt8(); //The number of unused bits in the bit string. tag = data.GetUInt8(); if (!response) { //ProposedConformance if (xml != null) { xml.AppendStartTag(TranslatorGeneralTags.ProposedConformance); } data.Get(settings.ConformanceBlock); tmp2.Set(settings.ConformanceBlock); } else { //NegotiatedConformance if (xml != null) { xml.AppendStartTag(TranslatorGeneralTags.NegotiatedConformance); } if (settings.UseLogicalNameReferencing) { data.Get(settings.LnSettings.ConformanceBlock); tmp2.Set(settings.LnSettings.ConformanceBlock); } else { data.Get(settings.SnSettings.ConformanceBlock); tmp2.Set(settings.SnSettings.ConformanceBlock); } } if (xml != null) { GetConformance(tmp2.GetUInt32(), xml); } if (!response) { //Proposed max PDU size. settings.MaxPduSize = data.GetUInt16(); if (xml != null) { //ProposedConformance closing xml.AppendEndTag(TranslatorGeneralTags.ProposedConformance); //ProposedMaxPduSize xml.AppendLine(TranslatorGeneralTags.ProposedMaxPduSize, "Value", xml.IntegerToHex(settings.MaxPduSize, 4)); } //If client asks too high PDU. if (settings.MaxPduSize > settings.MaxServerPDUSize) { settings.MaxPduSize = settings.MaxServerPDUSize; } } else { //Max PDU size. settings.MaxPduSize = data.GetUInt16(); if (xml != null) { //NegotiatedConformance closing xml.AppendEndTag(TranslatorGeneralTags.NegotiatedConformance); //NegotiatedMaxPduSize xml.AppendLine(TranslatorGeneralTags.NegotiatedMaxPduSize, "Value", xml.IntegerToHex(settings.MaxPduSize, 4)); } } if (response) { //VAA Name tag = data.GetUInt16(); if (xml != null) { xml.AppendLine(TranslatorGeneralTags.VaaName, "Value", xml.IntegerToHex(tag, 4)); } if (tag == 0x0007) { // If LN if (!settings.UseLogicalNameReferencing) { throw new ArgumentException("Invalid VAA."); } } else if (tag == 0xFA00) { // If SN if (settings.UseLogicalNameReferencing) { throw new ArgumentException("Invalid VAA."); } } else { // Unknown VAA. throw new ArgumentException("Invalid VAA."); } if (xml != null) { //<InitiateResponse> xml.AppendEndTag(Command.InitiateResponse); } } else if (xml != null) { //</InitiateRequest> xml.AppendEndTag(Command.InitiateRequest); } }
private static byte[] GetUserInformation(GXDLMSSettings settings, GXICipher cipher) { GXByteBuffer data = new GXByteBuffer(); data.SetUInt8(Command.InitiateResponse); // Tag for xDLMS-Initiate response // NegotiatedQualityOfService (not used) data.SetUInt8(0x1); data.SetUInt8(0x00); // DLMS Version Number data.SetUInt8(06); data.SetUInt8(0x5F); data.SetUInt8(0x1F); data.SetUInt8(0x04);// length of the conformance block data.SetUInt8(0x00);// encoding the number of unused bits in the bit string if (settings.UseLogicalNameReferencing) { data.Set(settings.LnSettings.ConformanceBlock); } else { data.Set(settings.SnSettings.ConformanceBlock); } data.SetUInt16(settings.MaxPduSize); //VAA Name VAA name (0x0007 for LN referencing and 0xFA00 for SN) if (settings.UseLogicalNameReferencing) { data.SetUInt16(0x0007); } else { data.SetUInt16(0xFA00); } if (cipher != null && cipher.IsCiphered()) { return cipher.Encrypt((byte)Command.GloInitiateResponse, cipher.SystemTitle, data.Array()); } return data.Array(); }
static internal byte[] EncryptAesGcm(AesGcmParameter param, byte[] plainText) { System.Diagnostics.Debug.WriteLine("Encrypt settings: " + param.ToString()); param.CountTag = null; GXByteBuffer data = new GXByteBuffer(); if (param.Type == CountType.Packet) { data.SetUInt8((byte)param.Security); } byte[] tmp = BitConverter.GetBytes(param.FrameCounter).Reverse().ToArray(); byte[] aad = GetAuthenticatedData(param.Security, param.AuthenticationKey, plainText); GXDLMSChipperingStream gcm = new GXDLMSChipperingStream(param.Security, true, param.BlockCipherKey, aad, GetNonse(param.FrameCounter, param.SystemTitle), null); // Encrypt the secret message if (param.Security != Gurux.DLMS.Enums.Security.Authentication) { gcm.Write(plainText); } byte[] ciphertext = gcm.FlushFinalBlock(); if (param.Security == Gurux.DLMS.Enums.Security.Authentication) { if (param.Type == CountType.Packet) { data.Set(tmp); } if ((param.Type & CountType.Data) != 0) { data.Set(plainText); } if ((param.Type & CountType.Tag) != 0) { param.CountTag = gcm.GetTag(); data.Set(param.CountTag); } } else if (param.Security == Gurux.DLMS.Enums.Security.Encryption) { if (param.Type == CountType.Packet) { data.Set(tmp); } data.Set(ciphertext); } else if (param.Security == Gurux.DLMS.Enums.Security.AuthenticationEncryption) { if (param.Type == CountType.Packet) { data.Set(tmp); } if ((param.Type & CountType.Data) != 0) { data.Set(ciphertext); } if ((param.Type & CountType.Tag) != 0) { param.CountTag = gcm.GetTag(); data.Set(param.CountTag); } } else { throw new ArgumentOutOfRangeException("security"); } if (param.Type == CountType.Packet) { GXByteBuffer tmp2 = new GXByteBuffer((ushort)(10 + data.Size)); tmp2.SetUInt8(param.Tag); GXCommon.SetObjectCount(data.Size, tmp2); tmp2.Set(data.Array()); return tmp2.Array(); } byte[] crypted = data.Array(); System.Diagnostics.Debug.WriteLine("Crypted: " + GXCommon.ToHex(crypted, true)); return crypted; }
///<summary> ///Convert Octet string to DLMS bytes. ///</summary> ///<param name="buff"> ///Byte buffer where data is write. ///</param> ///<param name="value"> ///Added value. ///</param> private static void SetOctetString(GXByteBuffer buff, object value) { // Example Logical name is octet string, so do not change to // string... if (value is string) { string[] items = ((string)value).Split('.'); // If data is string. if (items.Length == 1) { byte[] tmp = ASCIIEncoding.ASCII.GetBytes((string)value); SetObjectCount(tmp.Length, buff); buff.Set(tmp); } else { SetObjectCount(items.Length, buff); foreach (string it in items) { buff.SetUInt8(Convert.ToByte(it)); } } } else if (value is sbyte[]) { SetObjectCount(((byte[])value).Length, buff); buff.Set((byte[])value); } else if (value == null) { SetObjectCount(0, buff); } else { throw new Exception("Invalid data type."); } }
///<summary> ///Convert UTC string to DLMS bytes. ///</summary> ///<param name="buff"> ///Byte buffer where data is write. ///</param> ///<param name="value"> ///Added value. ///</param> private static void SetUtcString(GXByteBuffer buff, object value) { if (value != null) { byte[] tmp = ASCIIEncoding.UTF8.GetBytes(Convert.ToString(value)); SetObjectCount(tmp.Length, buff); buff.Set(tmp); } else { buff.SetUInt8(0); } }
///<summary> ///Convert ASCII string to DLMS bytes. ///</summary> ///<param name="buff"> ///Byte buffer where data is write. ///</param> ///<param name="value"> ///Added value. ///</param> private static void SetString(GXByteBuffer buff, object value) { if (value != null) { string str = Convert.ToString(value); SetObjectCount(str.Length, buff); buff.Set(ASCIIEncoding.ASCII.GetBytes(str)); } else { buff.SetUInt8(0); } }
///<summary> ///Convert Bit string to DLMS bytes. ///</summary> ///<param name="buff"> ///Byte buffer where data is write. ///</param> ///<param name="value"> ///Added value. ///</param> private static void SetBitString(GXByteBuffer buff, object value) { if (value is string) { GXByteBuffer tmp = new GXByteBuffer(); byte val = 0; int index = 0; string str = ((string)value); SetObjectCount(str.Length, buff); foreach (char it in str.Reverse()) { if (it == '1') { val |= (byte)(1 << index); ++index; } else if (it == '0') { ++index; } else { throw new Exception("Not a bit string."); } if (index == 8) { index = 0; tmp.SetUInt8(val); val = 0; } } if (index != 0) { tmp.SetUInt8(val); } for (int pos = tmp.Size - 1; pos != -1; --pos) { buff.SetUInt8(tmp.GetUInt8(pos)); } } else if (value is sbyte[]) { byte[] arr = (byte[])value; SetObjectCount(arr.Length, buff); buff.Set(arr); } else if (value == null) { buff.SetUInt8(0); } else { throw new Exception("BitString must give as string."); } }
/// <summary> /// Add string to byte buffer. /// </summary> /// <param name="value">String to add.</param> /// <param name="bb">Byte buffer where string is added.</param> public static void AddString(string value, GXByteBuffer bb) { bb.SetUInt8((byte)DataType.OctetString); if (value == null) { GXCommon.SetObjectCount(0, bb); } else { GXCommon.SetObjectCount(value.Length, bb); bb.Set(ASCIIEncoding.ASCII.GetBytes(value)); } }
private static byte[] GetAuthenticatedData(Gurux.DLMS.Enums.Security security, byte[] AuthenticationKey, byte[] plainText) { if (security == Gurux.DLMS.Enums.Security.Authentication) { GXByteBuffer tmp2 = new GXByteBuffer(); tmp2.SetUInt8((byte)security); tmp2.Set(AuthenticationKey); tmp2.Set(plainText); return tmp2.Array(); } else if (security == Gurux.DLMS.Enums.Security.Encryption) { return AuthenticationKey; } else if (security == Gurux.DLMS.Enums.Security.AuthenticationEncryption) { GXByteBuffer tmp2 = new GXByteBuffer(); tmp2.SetUInt8((byte)security); tmp2.Set(AuthenticationKey); return tmp2.Array(); } return null; }
///<summary> ///Server generates AARE message. ///</summary> internal static void GenerateAARE(GXDLMSSettings settings, GXByteBuffer data, AssociationResult result, SourceDiagnostic diagnostic, GXICipher cipher, GXByteBuffer encryptedData) { int offset = data.Size; // Set AARE tag and length data.SetUInt8(((byte)BerType.Application | (byte)BerType.Constructed | (byte)PduType.ApplicationContextName)); //0x61 // Length is updated later. data.SetUInt8(0); GenerateApplicationContextName(settings, data, cipher); //Result data.SetUInt8((byte)BerType.Context | (byte)BerType.Constructed | (byte)BerType.Integer);//0xA2 data.SetUInt8(3); //len data.SetUInt8(BerType.Integer); //Tag //Choice for result (INTEGER, universal) data.SetUInt8(1); //Len data.SetUInt8((byte)result); //ResultValue //SourceDiagnostic data.SetUInt8(0xA3); data.SetUInt8(5); //len data.SetUInt8(0xA1); //Tag data.SetUInt8(3); //len data.SetUInt8(2); //Tag //Choice for result (INTEGER, universal) data.SetUInt8(1); //Len data.SetUInt8((byte)diagnostic); //diagnostic //SystemTitle if (cipher != null && (cipher.IsCiphered() || settings.Authentication == Authentication.HighGMAC)) { data.SetUInt8((byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.CalledApInvocationId); data.SetUInt8((byte)(2 + cipher.SystemTitle.Length)); data.SetUInt8((byte)BerType.OctetString); data.SetUInt8((byte)cipher.SystemTitle.Length); data.Set(cipher.SystemTitle); } if (result != AssociationResult.PermanentRejected && diagnostic == SourceDiagnostic.AuthenticationRequired) { //Add server ACSE-requirenents field component. data.SetUInt8(0x88); data.SetUInt8(0x02); //Len. data.SetUInt16(0x0780); //Add tag. data.SetUInt8(0x89); data.SetUInt8(0x07);//Len data.SetUInt8(0x60); data.SetUInt8(0x85); data.SetUInt8(0x74); data.SetUInt8(0x05); data.SetUInt8(0x08); data.SetUInt8(0x02); data.SetUInt8((byte)settings.Authentication); //Add tag. data.SetUInt8(0xAA); data.SetUInt8((byte)(2 + settings.StoCChallenge.Length));//Len data.SetUInt8((byte)BerType.Context); data.SetUInt8((byte)settings.StoCChallenge.Length); data.Set(settings.StoCChallenge); } byte[] tmp; //Add User Information //Tag 0xBE data.SetUInt8((byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.UserInformation); if (encryptedData != null && encryptedData.Size != 0) { GXByteBuffer tmp2 = new GXByteBuffer((UInt16)(2 + encryptedData.Size)); tmp2.SetUInt8((byte)Command.GloInitiateResponse); GXCommon.SetObjectCount(encryptedData.Size, tmp2); tmp2.Set(encryptedData); tmp = tmp2.Array(); } else { tmp = GetUserInformation(settings, cipher); } data.SetUInt8((byte)(2 + tmp.Length)); //Coding the choice for user-information (Octet STRING, universal) data.SetUInt8(BerType.OctetString); //Length data.SetUInt8((byte)tmp.Length); data.Set(tmp); data.SetUInt8((UInt16)(offset + 1), (byte)(data.Size - offset - 2)); }
///<summary> ///Convert object to DLMS bytes. ///</summary> ///<param name="settings">DLMS settings.</param> ///<param name="buff">Byte buffer where data is write.</param> ///<param name="dataType">Data type.</param> ///<param name="value">Added Value.</param> public static void SetData(GXDLMSSettings settings, GXByteBuffer buff, DataType type, object value) { if ((type == DataType.Array || type == DataType.Structure) && value is byte[]) { // If byte array is added do not add type. buff.Set((byte[])value); return; } buff.SetUInt8((byte)type); switch (type) { case DataType.None: break; case DataType.Boolean: if (Convert.ToBoolean(value)) { buff.SetUInt8(1); } else { buff.SetUInt8(0); } break; case DataType.Int8: buff.SetUInt8((byte)Convert.ToSByte(value)); break; case DataType.UInt8: case DataType.Enum: buff.SetUInt8(Convert.ToByte(value)); break; case DataType.Int16: if (value is UInt16) { buff.SetUInt16((UInt16)value); } else { buff.SetUInt16((UInt16)(Convert.ToInt16(value) & 0xFFFF)); } break; case DataType.UInt16: buff.SetUInt16(Convert.ToUInt16(value)); break; case DataType.Int32: buff.SetUInt32((UInt32)Convert.ToInt32(value)); break; case DataType.UInt32: buff.SetUInt32(Convert.ToUInt32(value)); break; case DataType.Int64: buff.SetUInt64((UInt64)Convert.ToInt64(value)); break; case DataType.UInt64: buff.SetUInt64(Convert.ToUInt64(value)); break; case DataType.Float32: buff.SetFloat((float)value); break; case DataType.Float64: buff.SetDouble((double)value); break; case DataType.BitString: SetBitString(buff, value); break; case DataType.String: SetString(buff, value); break; case DataType.StringUTF8: SetUtcString(buff, value); break; case DataType.OctetString: if (value is GXDate) { //Add size buff.SetUInt8(5); SetDate(buff, value); } else if (value is GXTime) { //Add size buff.SetUInt8(4); SetTime(buff, value); } else if (value is GXDateTime || value is DateTime) { //Add size buff.SetUInt8(12); SetDateTime(settings, buff, value); } else { SetOctetString(buff, value); } break; case DataType.Array: case DataType.Structure: SetArray(settings, buff, value); break; case DataType.Bcd: SetBcd(buff, value); break; case DataType.CompactArray: throw new Exception("Invalid data type."); case DataType.DateTime: SetDateTime(settings, buff, value); break; case DataType.Date: SetDate(buff, value); break; case DataType.Time: SetTime(buff, value); break; default: throw new Exception("Invalid data type."); } }
Gurux.DLMS.Enums.Security GXICipher.Decrypt(byte[] title, GXByteBuffer data) { AesGcmParameter p = new AesGcmParameter(title, BlockCipherKey, AuthenticationKey); byte[] tmp = GXDLMSChippering.DecryptAesGcm(p, data); data.Clear(); data.Set(tmp); return p.Security; }
///<summary> /// Chipher text. ///</summary> ///<param name="settings"> ///DLMS settings. ///</param> ///<param name="cipher"> ///Cipher. ///</param> ///<param name="ic"> ///Invocation counter. ///</param> ///<param name="data"> ///Text to chipher. ///</param> ///<param name="secret"> ///Secret. ///</param> ///<returns> ///Chiphered text. ///</returns> public static byte[] Secure(GXDLMSSettings settings, GXICipher cipher, UInt32 ic, byte[] data, byte[] secret) { byte[] tmp; if (settings.Authentication == Authentication.High) { int len = secret.Length; if (len % 16 != 0) { len += 16 - (secret.Length % 16); } byte[] p = new byte[len]; byte[] s = new byte[16]; byte[] x = new byte[16]; int i; data.CopyTo(p, 0); secret.CopyTo(s, 0); for (i = 0; i < p.Length; i += 16) { Buffer.BlockCopy(p, i, x, 0, 16); GXAes128.Encrypt(x, s); Buffer.BlockCopy(x, 0, p, i, 16); } Buffer.BlockCopy(p, 0, x, 0, 16); return x; } // Get server Challenge. GXByteBuffer challenge = new GXByteBuffer(); // Get shared secret if (settings.Authentication == Authentication.HighGMAC) { challenge.Set(data); } else { challenge.Set(data); challenge.Set(secret); } tmp = challenge.Array(); if (settings.Authentication == Authentication.HighMD5) { using (MD5 md5Hash = MD5.Create()) { tmp = md5Hash.ComputeHash(tmp); return tmp; } } else if (settings.Authentication == Authentication.HighSHA1) { using (SHA1 sha = new SHA1CryptoServiceProvider()) { tmp = sha.ComputeHash(tmp); return tmp; } } else if (settings.Authentication == Authentication.HighGMAC) { //SC is always Security.Authentication. AesGcmParameter p = new AesGcmParameter(0, Security.Authentication, ic, secret, cipher.BlockCipherKey, cipher.AuthenticationKey); p.Type = CountType.Tag; challenge.Clear(); challenge.SetUInt8((byte)Security.Authentication); challenge.SetUInt32(p.FrameCounter); challenge.Set(GXDLMSChippering.EncryptAesGcm(p, tmp)); tmp = challenge.Array(); return tmp; } return data; }