/// <summary> /// Reserved for internal use. /// </summary> /// <param name="buff"></param> /// <param name="index"></param> internal void EncodeData(byte[] buff, ref int index) { int tag = buff[index++]; if (tag != 0xA1) { throw new Exception("Invalid tag."); } //Get length. int len = buff[index++]; if (buff.Length - index < len) { throw new Exception("Encoding failed. Not enough data."); } if (buff[index++] != 0x6) { throw new Exception("Encoding failed. Not an Object ID."); } //Object ID length. len = buff[index++]; //Compare Object ID to check is Logical name used. UseLN = GXCommon.Compare(buff, ref index, GXCommon.LogicalNameObjectID); if (!UseLN) { index += GXCommon.ShortNameObjectID.Length; } }
public override bool Equals(object obj) { if (obj is GXPrivateKey pk) { return(GXCommon.Compare(RawValue, pk.RawValue)); } return(false); }
public override bool Equals(object obj) { if (obj is GXPublicKey o) { return(GXCommon.Compare(RawValue, o.RawValue)); } return(false); }
/// <summary> /// Decrypt data using AES RFC3394. /// </summary> /// <param name="input">Decrypted data.</param> internal byte[] DecryptAes(byte[] input) { int n = input.Length / 8; if ((n * 8) != input.Length) { throw new ArgumentOutOfRangeException("Invalid data."); } byte[] iv = { 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 }; byte[] block; if (input.Length > iv.Length) { block = new byte[input.Length - iv.Length]; } else { block = new byte[iv.Length]; } byte[] a = new byte[iv.Length]; byte[] buf = new byte[8 + iv.Length]; Array.Copy(input, 0, a, 0, iv.Length); Array.Copy(input, 0 + iv.Length, block, 0, input.Length - iv.Length); n = n - 1; if (n == 0) { n = 1; } for (int j = 5; j >= 0; j--) { for (int i = n; i >= 1; i--) { Array.Copy(a, 0, buf, 0, iv.Length); Array.Copy(block, 8 * (i - 1), buf, iv.Length, 8); int t = n * j + i; for (int k = 1; t != 0; k++) { byte v = (byte)t; buf[iv.Length - k] ^= v; t = (int)((uint)t >> 8); } ProcessBlock(buf, 0, buf, 0); Array.Copy(buf, 0, a, 0, 8); Array.Copy(buf, 8, block, 8 * (i - 1), 8); } } if (!GXCommon.Compare(a, iv)) { throw new ArithmeticException("Invalid CRC"); } return(block); }
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."); } }
byte[] IGXDLMSBase.Invoke(GXDLMSSettings settings, ValueEventArgs e) { //Check reply_to_HLS_authentication if (e.Index == 8) { UInt32 ic = 0; byte[] secret; if (settings.Authentication == Authentication.HighGMAC) { secret = settings.SourceSystemTitle; GXByteBuffer bb = new GXByteBuffer(e.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[])e.Parameters; if (GXCommon.Compare(serverChallenge, clientChallenge)) { if (settings.Authentication == Authentication.HighGMAC) { secret = settings.Cipher.SystemTitle; ic = settings.Cipher.InvocationCounter; } else { secret = Secret; } settings.Connected = true; return(GXSecure.Secure(settings, settings.Cipher, ic, settings.CtoSChallenge, secret)); } else { // If the password does not match. settings.Connected = false; return(null); } } else { e.Error = ErrorCode.ReadWriteDenied; return(null); } }
byte[][] IGXDLMSBase.Invoke(object sender, int index, Object parameters) { //Check reply_to_HLS_authentication if (index == 8) { GXDLMSServerBase s = sender as GXDLMSServerBase; if (s == null) { throw new ArgumentException("sender"); } GXDLMS b = s.m_Base; //Get server Challenge. List <byte> challenge = null; List <byte> CtoS = null; //Find shared secret foreach (GXAuthentication it in s.Authentications) { if (it.Type == b.Authentication) { CtoS = new List <byte>(it.SharedSecret); challenge = new List <byte>(it.SharedSecret); challenge.AddRange(b.StoCChallenge); break; } } byte[] serverChallenge = GXDLMS.Chipher(b.Authentication, challenge.ToArray(), null); byte[] clientChallenge = (byte[])parameters; int pos = 0; if (GXCommon.Compare(clientChallenge, ref pos, serverChallenge)) { CtoS.AddRange(b.CtoSChallenge); return(s.Acknowledge(Command.WriteResponse, 0, GXDLMS.Chipher(b.Authentication, CtoS.ToArray(), null), DataType.OctetString)); } else { //Return HW error. return(s.ServerReportError(Command.MethodRequest, 1)); } } else { throw new ArgumentException("Invoke failed. Invalid attribute index."); } }
byte[] IGXDLMSBase.Invoke(GXDLMSSettings settings, ValueEventArgs e) { //Check reply_to_HLS_authentication if (e.Index == 1) { UInt32 ic = 0; byte[] secret; if (settings.Authentication == Authentication.HighGMAC) { secret = settings.SourceSystemTitle; GXByteBuffer bb = new GXByteBuffer(e.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[])e.Parameters; if (serverChallenge != null && clientChallenge != null && GXCommon.Compare(serverChallenge, clientChallenge)) { if (settings.Authentication == Authentication.HighGMAC) { secret = settings.Cipher.SystemTitle; ic = settings.Cipher.InvocationCounter; } else { secret = Secret; } AssociationStatus = AssociationStatus.Associated; return(GXSecure.Secure(settings, settings.Cipher, ic, settings.CtoSChallenge, secret)); } else //If the password does not match. { AssociationStatus = AssociationStatus.NonAssociated; return(null); } } else if (e.Index == 2) { byte[] tmp = e.Parameters as byte[]; if (tmp == null || tmp.Length == 0) { e.Error = ErrorCode.ReadWriteDenied; } else { Secret = tmp; } } else if (e.Index == 3) { //Add COSEM object. GXDLMSObject obj = GetObject(settings, e.Parameters as object[]); //Unknown objects are not add. if (obj is IGXDLMSBase) { if (ObjectList.FindByLN(obj.ObjectType, obj.LogicalName) == null) { ObjectList.Add(obj); } if (settings.Objects.FindByLN(obj.ObjectType, obj.LogicalName) == null) { settings.Objects.Add(obj); } } } else if (e.Index == 4) { //Remove COSEM object. GXDLMSObject obj = GetObject(settings, e.Parameters as object[]); //Unknown objects are not removed. if (obj is IGXDLMSBase) { GXDLMSObject t = ObjectList.FindByLN(obj.ObjectType, obj.LogicalName); if (t != null) { ObjectList.Remove(t); } //Item is not removed from all objects. It might be that use wants remove object only from association view. } } else if (e.Index == 5) { object[] tmp = e.Parameters as object[]; if (tmp == null || tmp.Length != 2) { e.Error = ErrorCode.ReadWriteDenied; } else { UserList.Add(new KeyValuePair <byte, string>(Convert.ToByte(tmp[0]), Convert.ToString(tmp[1]))); } } else if (e.Index == 6) { object[] tmp = e.Parameters as object[]; if (tmp == null || tmp.Length != 2) { e.Error = ErrorCode.ReadWriteDenied; } else { UserList.Remove(new KeyValuePair <byte, string>(Convert.ToByte(tmp[0]), Convert.ToString(tmp[1]))); } } else { e.Error = ErrorCode.ReadWriteDenied; } return(null); }
/// <summary> /// Ask Gurux certificate server to generate the new certificate. /// </summary> /// <param name="address">Certificate server address.</param> /// <param name="certifications">List of certification types and PKCS #10 certificates.</param> /// <returns>Generated certificate(s).</returns> public static GXx509Certificate[] GetCertificate(string address, List <KeyValuePair <CertificateType, GXPkcs10> > certifications) { StringBuilder usage = new StringBuilder(); foreach (KeyValuePair <CertificateType, GXPkcs10> it in certifications) { if (usage.Length != 0) { usage.Append(", "); } usage.Append("{\"KeyUsage\":"); switch (it.Key) { case CertificateType.DigitalSignature: usage.Append(Convert.ToString((int)KeyUsage.DigitalSignature)); break; case CertificateType.KeyAgreement: usage.Append(Convert.ToString((int)KeyUsage.KeyAgreement)); break; default: throw new Exception("Invalid type."); } usage.Append(", \"CSR\":\""); usage.Append(it.Value.ToDer()); usage.Append("\"}"); } HttpWebRequest request = HttpWebRequest.Create(address) as HttpWebRequest; string der = "{\"Certificates\":[" + usage.ToString() + "]}"; request.ContentType = "application/json"; request.Method = "POST"; using (var streamWriter = new StreamWriter(request.GetRequestStream())) { streamWriter.Write(der); streamWriter.Flush(); streamWriter.Close(); } try { using (HttpWebResponse webresponse = request.GetResponse() as HttpWebResponse) { using (StreamReader reader = new StreamReader(webresponse.GetResponseStream())) { string str = reader.ReadToEnd(); int pos = str.IndexOf("["); if (pos == -1) { throw new Exception("Certificates are missing."); } str = str.Substring(pos + 2); pos = str.IndexOf("]"); if (pos == -1) { throw new Exception("Certificates are missing."); } str = str.Substring(0, pos - 1); List <GXx509Certificate> list = new List <GXx509Certificate>(); string[] tmp = str.Split(new string[] { "\"", "," }, StringSplitOptions.RemoveEmptyEntries); pos = 0; foreach (string it in tmp) { GXx509Certificate x509 = GXx509Certificate.FromDer(it); if (!GXCommon.Compare(certifications[pos].Value.PublicKey.RawValue, x509.PublicKey.RawValue)) { throw new Exception("Create certificate signingRequest generated wrong public key."); } ++pos; list.Add(x509); } return(list.ToArray()); } } } catch (WebException ex) { throw new Exception(new StreamReader(ex.Response.GetResponseStream()).ReadToEnd()); } }
/// <summary> /// Decrypt data. /// </summary> /// <param name="p">Decryption parameters</param> /// <returns>Decrypted data.</returns> public static byte[] DecryptAesGcm(AesGcmParameter p, GXByteBuffer data) { if (data == null || data.Size < 2) { throw new ArgumentOutOfRangeException("cryptedData"); } byte[] tmp; int len; Command cmd = (Command)data.GetUInt8(); switch (cmd) { case Command.GeneralGloCiphering: case Command.GeneralDedCiphering: len = GXCommon.GetObjectCount(data); if (len != 0) { p.SystemTitle = new byte[len]; data.Get(p.SystemTitle); if (p.Xml != null && p.Xml.Comments) { p.Xml.AppendComment(GXCommon.SystemTitleToString(Standard.DLMS, p.SystemTitle, true)); } } if (p.SystemTitle == null || p.SystemTitle.Length != 8) { if (p.Xml == null) { throw new ArgumentNullException("Invalid sender system title."); } else { p.Xml.AppendComment("Invalid sender system title."); } } break; case Command.GeneralCiphering: case Command.GloInitiateRequest: case Command.GloInitiateResponse: case Command.GloReadRequest: case Command.GloReadResponse: case Command.GloWriteRequest: case Command.GloWriteResponse: case Command.GloGetRequest: case Command.GloGetResponse: case Command.GloSetRequest: case Command.GloSetResponse: case Command.GloMethodRequest: case Command.GloMethodResponse: case Command.GloEventNotification: case Command.DedInitiateRequest: case Command.DedInitiateResponse: case Command.DedGetRequest: case Command.DedGetResponse: case Command.DedSetRequest: case Command.DedSetResponse: case Command.DedMethodRequest: case Command.DedMethodResponse: case Command.DedEventNotification: case Command.DedReadRequest: case Command.DedReadResponse: case Command.DedWriteRequest: case Command.DedWriteResponse: case Command.GloConfirmedServiceError: case Command.DedConfirmedServiceError: break; default: throw new ArgumentOutOfRangeException("cryptedData"); } int value = 0; GXPrivateKey key = null; GXPublicKey pub = null; GXByteBuffer transactionId = null; if (cmd == Command.GeneralCiphering) { transactionId = new GXByteBuffer(); len = GXCommon.GetObjectCount(data); GXCommon.SetObjectCount(len, transactionId); transactionId.Set(data, len); p.TransactionId = transactionId.GetUInt64(1); len = GXCommon.GetObjectCount(data); if (len != 0) { tmp = new byte[len]; data.Get(tmp); p.SystemTitle = tmp; } if (p.SystemTitle == null || p.SystemTitle.Length != 8) { if (p.Xml == null) { throw new ArgumentNullException("Invalid sender system title."); } else { p.Xml.AppendComment("Invalid sender system title."); } } len = GXCommon.GetObjectCount(data); tmp = new byte[len]; data.Get(tmp); p.RecipientSystemTitle = tmp; // Get date time. len = GXCommon.GetObjectCount(data); if (len != 0) { tmp = new byte[len]; data.Get(tmp); p.DateTime = tmp; } // other-information len = data.GetUInt8(); if (len != 0) { tmp = new byte[len]; data.Get(tmp); p.OtherInformation = tmp; } // KeyInfo OPTIONAL len = data.GetUInt8(); // AgreedKey CHOICE tag. data.GetUInt8(); // key-parameters len = data.GetUInt8(); value = data.GetUInt8(); p.KeyParameters = value; if (value == (int)KeyAgreementScheme.OnePassDiffieHellman) { // key-ciphered-data len = GXCommon.GetObjectCount(data); GXByteBuffer bb = new GXByteBuffer(); bb.Set(data, len); if (p.Xml != null) { p.KeyCipheredData = bb.Array(); //Find key agreement key using subject. string subject = GXAsn1Converter.SystemTitleToSubject(p.SystemTitle); foreach (KeyValuePair <GXPkcs8, GXx509Certificate> it in p.Settings.Keys) { if (it.Key != null && it.Value.KeyUsage == ASN.Enums.KeyUsage.KeyAgreement && it.Value.Subject.Contains(subject)) { key = it.Key.PrivateKey; //Get recipient Ephemeral public key. subject = GXAsn1Converter.SystemTitleToSubject(p.RecipientSystemTitle); foreach (KeyValuePair <GXPkcs8, GXx509Certificate> it2 in p.Settings.Keys) { if (it2.Value != null && it2.Value.KeyUsage == ASN.Enums.KeyUsage.KeyAgreement && it2.Value.Subject.Contains(subject)) { pub = it2.Value.PublicKey; break; } } break; } } if (key == null) { //Find key agreement key using subject. subject = GXAsn1Converter.SystemTitleToSubject(p.RecipientSystemTitle); foreach (KeyValuePair <GXPkcs8, GXx509Certificate> it in p.Settings.Keys) { if (it.Key != null && it.Value.KeyUsage == ASN.Enums.KeyUsage.KeyAgreement && it.Value.Subject.Contains(subject)) { key = it.Key.PrivateKey; break; } } } } else { key = p.Settings.Cipher.KeyAgreementKeyPair.Key; } if (key != null && pub == null) { //Get Ephemeral public key. int keySize = len / 2; pub = GXPublicKey.FromRawBytes(bb.SubArray(0, keySize)); } } else if (value == (int)KeyAgreementScheme.StaticUnifiedModel) { len = GXCommon.GetObjectCount(data); if (len != 0) { throw new ArgumentException("Invalid key parameters"); } if (p.Xml != null) { //Find key agreement key using subject. string subject = GXAsn1Converter.SystemTitleToSubject(p.RecipientSystemTitle); foreach (KeyValuePair <GXPkcs8, GXx509Certificate> it in p.Settings.Keys) { if (it.Value.KeyUsage == ASN.Enums.KeyUsage.KeyAgreement && it.Value.Subject.Contains(subject)) { key = it.Key.PrivateKey; break; } } if (key != null) { //Find key agreement key using subject. subject = GXAsn1Converter.SystemTitleToSubject(p.Settings.SourceSystemTitle); foreach (KeyValuePair <GXPkcs8, GXx509Certificate> it in p.Settings.Keys) { if (it.Value.KeyUsage == ASN.Enums.KeyUsage.KeyAgreement && it.Value.Subject.Contains(subject)) { pub = it.Value.PublicKey; break; } } } } else { key = p.Settings.Cipher.KeyAgreementKeyPair.Key; pub = p.Settings.Cipher.KeyAgreementKeyPair.Value; } } else { throw new ArgumentException("key-parameters"); } } len = GXCommon.GetObjectCount(data); if (len > data.Available) { throw new Exception("Not enought data."); } p.CipheredContent = data.Remaining(); byte sc = data.GetUInt8(); p.SecuritySuite = (SecuritySuite)(sc & 0x3); p.Security = (Security)(sc & 0x30); if ((sc & 0x80) != 0) { System.Diagnostics.Debug.WriteLine("Compression is used."); } if ((sc & 0x40) != 0) { System.Diagnostics.Debug.WriteLine("Error: Key_Set is used."); } if ((sc & 0x20) != 0) { System.Diagnostics.Debug.WriteLine("Encryption is applied."); } if (key != null) { if (value == (int)KeyAgreementScheme.OnePassDiffieHellman) { GXEcdsa c = new GXEcdsa(key); //Get Ephemeral signing key and verify it. byte[] z = c.GenerateSecret(pub); System.Diagnostics.Debug.WriteLine("Originator ephemeral public key: " + pub.ToHex()); System.Diagnostics.Debug.WriteLine("Recipient private agreement key: " + key.ToHex()); System.Diagnostics.Debug.WriteLine("Shared secret:" + GXCommon.ToHex(z, true)); GXByteBuffer kdf = new GXByteBuffer(); kdf.Set(GXSecure.GenerateKDF(p.SecuritySuite, z, p.SecuritySuite == SecuritySuite.Ecdsa256 ? AlgorithmId.AesGcm128 : AlgorithmId.AesGcm256, p.SystemTitle, p.RecipientSystemTitle, null, null)); System.Diagnostics.Debug.WriteLine("KDF:" + kdf.ToString()); p.BlockCipherKey = kdf.SubArray(0, 16); } else if (value == (int)KeyAgreementScheme.StaticUnifiedModel) { GXEcdsa c = new GXEcdsa(key); byte[] z = c.GenerateSecret(pub); System.Diagnostics.Debug.WriteLine("Shared secret:" + GXCommon.ToHex(z, true)); GXByteBuffer kdf = new GXByteBuffer(); kdf.Set(GXSecure.GenerateKDF(p.SecuritySuite, z, p.SecuritySuite == SecuritySuite.Ecdsa256 ? AlgorithmId.AesGcm128 : AlgorithmId.AesGcm256, p.SystemTitle, transactionId.Array(), p.RecipientSystemTitle, null)); System.Diagnostics.Debug.WriteLine("KDF:" + kdf.ToString()); p.BlockCipherKey = kdf.SubArray(0, 16); } else { throw new ArgumentOutOfRangeException("Invalid Key-id value."); } } UInt32 invocationCounter = data.GetUInt32(); p.InvocationCounter = invocationCounter; System.Diagnostics.Debug.WriteLine("Decrypt settings: " + p.ToString()); System.Diagnostics.Debug.WriteLine("Encrypted: " + GXCommon.ToHex(data.Data, false, data.Position, data.Size - data.Position)); byte[] tag = new byte[12]; byte[] encryptedData; int length; if (p.Security == Security.Authentication) { length = data.Size - data.Position - 12; encryptedData = new byte[length]; data.Get(encryptedData); data.Get(tag); // Check tag. EncryptAesGcm(p, encryptedData); if (!GXDLMSChipperingStream.TagsEquals(tag, p.CountTag)) { if (p.Xml == null) { throw new GXDLMSException("Decrypt failed. Invalid tag."); } else { p.Xml.AppendComment("Decrypt failed. Invalid tag."); } } return(encryptedData); } byte[] ciphertext = null; if (p.Security == Security.Encryption) { length = data.Size - data.Position; ciphertext = new byte[length]; data.Get(ciphertext); } else if (p.Security == Security.AuthenticationEncryption) { length = data.Size - data.Position - 12; ciphertext = new byte[length]; data.Get(ciphertext); data.Get(tag); } byte[] aad = GetAuthenticatedData(p, ciphertext), iv = GetNonse(invocationCounter, p.SystemTitle); GXDLMSChipperingStream gcm = new GXDLMSChipperingStream(p.Security, true, p.BlockCipherKey, aad, iv, tag); gcm.Write(ciphertext); byte[] decrypted = gcm.FlushFinalBlock(); System.Diagnostics.Debug.WriteLine("Decrypted: " + GXCommon.ToHex(decrypted, true)); if (p.Security != Security.Encryption) { if (!GXCommon.Compare(gcm.GetTag(), tag)) { if (p.Xml == null) { throw new Exception("Decrypt failed. Invalid authentication tag."); } p.Xml.AppendComment("Decrypt failed. Invalid authentication tag."); } } return(decrypted); }
byte[] IGXDLMSBase.Invoke(GXDLMSSettings settings, ValueEventArgs e) { //Check reply_to_HLS_authentication if (e.Index == 1) { UInt32 ic = 0; byte[] secret; if (settings.Authentication == Authentication.HighGMAC) { secret = settings.SourceSystemTitle; GXByteBuffer bb = new GXByteBuffer(e.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[])e.Parameters; if (serverChallenge != null && clientChallenge != null && GXCommon.Compare(serverChallenge, clientChallenge)) { if (settings.Authentication == Authentication.HighGMAC) { secret = settings.Cipher.SystemTitle; ic = settings.Cipher.InvocationCounter; } else { secret = Secret; } settings.Connected = true; return(GXSecure.Secure(settings, settings.Cipher, ic, settings.CtoSChallenge, secret)); } else //If the password does not match. { settings.Connected = false; return(null); } } else if (e.Index == 2) { byte[] tmp = e.Parameters as byte[]; if (tmp == null || tmp.Length == 0) { e.Error = ErrorCode.ReadWriteDenied; } else { Secret = tmp; } } else if (e.Index == 5) { object[] tmp = e.Parameters as object[]; if (tmp == null || tmp.Length != 2) { e.Error = ErrorCode.ReadWriteDenied; } else { UserList.Add(new KeyValuePair <byte, string>(Convert.ToByte(tmp[0]), Convert.ToString(tmp[1]))); } } else if (e.Index == 6) { object[] tmp = e.Parameters as object[]; if (tmp == null || tmp.Length != 2) { e.Error = ErrorCode.ReadWriteDenied; } else { UserList.Remove(new KeyValuePair <byte, string>(Convert.ToByte(tmp[0]), Convert.ToString(tmp[1]))); } } else { e.Error = ErrorCode.ReadWriteDenied; } return(null); }