/// <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));
                    }
                }
                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;
            UInt64 transactionId = 0;

            if (cmd == Command.GeneralCiphering)
            {
                len = GXCommon.GetObjectCount(data);
                tmp = new byte[len];
                data.Get(tmp);
                GXByteBuffer t = new GXByteBuffer(tmp);
                transactionId = t.GetUInt64();
                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 == 1)
                {
                    // KeyAgreement.ONE_PASS_DIFFIE_HELLMAN
                    // key-ciphered-data
                    len = GXCommon.GetObjectCount(data);
                    tmp = new byte[len];
                    data.Get(tmp);
                    p.KeyCipheredData = tmp;
                }
                else if (value == 2)
                {
                    // KeyAgreement.STATIC_UNIFIED_MODEL
                    len = GXCommon.GetObjectCount(data);
                    if (len != 0)
                    {
                        throw new ArgumentException("Invalid key parameters");
                    }
                }
                else
                {
                    throw new ArgumentException("key-parameters");
                }
            }
            len = GXCommon.GetObjectCount(data);
            p.CipheredContent = data.Remaining();
            byte sc = (byte)data.GetUInt8();

            Enums.Security security = (Enums.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.");
            }

            SecuritySuite ss = (SecuritySuite)(sc & 0x3);

            p.Security = (byte)security;
            UInt32 invocationCounter = data.GetUInt32();

            p.InvocationCounter = invocationCounter;
            if (ss == SecuritySuite.Version2)
            {
                throw new NotImplementedException("Security Suite 2 is not implemented.");
            }
            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 (security == Enums.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 (transactionId != 0)
                    {
                        p.InvocationCounter = transactionId;
                    }
                    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 (security == Enums.Security.Encryption)
            {
                length     = data.Size - data.Position;
                ciphertext = new byte[length];
                data.Get(ciphertext);
            }
            else if (security == Enums.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((byte)security, true,
                                                                    p.BlockCipherKey, aad, iv, tag);

            gcm.Write(ciphertext);
            if (transactionId != 0)
            {
                p.InvocationCounter = transactionId;
            }
            return(gcm.FlushFinalBlock());
        }
Beispiel #2
0
        ///<summary>
        ///Parse APDU.
        ///</summary>
        static internal SourceDiagnostic ParsePDU(GXDLMSSettings settings, GXICipher cipher, GXByteBuffer buff)
        {
            // Get AARE tag and length
            int tag = buff.GetUInt8();

            if (settings.IsServer)
            {
                if (tag != ((byte)BerType.Application | (byte)BerType.Constructed | (byte)PduType.ProtocolVersion))
                {
                    throw new Exception("Invalid tag.");
                }
            }
            else
            {
                if (tag != ((byte)BerType.Application | (byte)BerType.Constructed | (byte)PduType.ApplicationContextName))
                {
                    throw new Exception("Invalid tag.");
                }
            }
            int len  = buff.GetUInt8();
            int size = buff.Size - buff.Position;

            if (len > size)
            {
                throw new Exception("Not enough data.");
            }
            AssociationResult resultComponent       = AssociationResult.Accepted;
            SourceDiagnostic  resultDiagnosticValue = SourceDiagnostic.None;

            while (buff.Position < buff.Size)
            {
                tag = buff.GetUInt8();
                switch (tag)
                {
                case (byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.ApplicationContextName:    //0xA1
                    if (!ParseApplicationContextName(settings, buff))
                    {
                        throw new GXDLMSException(AssociationResult.PermanentRejected, SourceDiagnostic.ApplicationContextNameNotSupported);
                    }
                    break;

                case (byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.CalledApTitle:    ////Result 0xA2
                    //Get len.
                    if (buff.GetUInt8() != 3)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    //Choice for result (INTEGER, universal)
                    if (buff.GetUInt8() != (byte)BerType.Integer)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    //Get len.
                    if (buff.GetUInt8() != 1)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    resultComponent = (AssociationResult)buff.GetUInt8();
                    break;

                case (byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.CalledAeQualifier:    ////SourceDiagnostic 0xA3
                    len = buff.GetUInt8();
                    // ACSE service user tag.
                    tag = buff.GetUInt8();
                    len = buff.GetUInt8();
                    // Result source diagnostic component.
                    if (buff.GetUInt8() != (byte)BerType.Integer)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    if (buff.GetUInt8() != 1)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    resultDiagnosticValue = (SourceDiagnostic)buff.GetUInt8();
                    break;

                case (byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.CalledApInvocationId:    ////Result 0xA4
                    //Get len.
                    if (buff.GetUInt8() != 0xA)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    //Choice for result (Universal, Octetstring type)
                    if (buff.GetUInt8() != (byte)BerType.OctetString)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    //responding-AP-title-field
                    //Get len.
                    len = buff.GetUInt8();
                    settings.SourceSystemTitle = new byte[len];
                    buff.Get(settings.SourceSystemTitle);
                    break;

                //Client Challenge.
                case (byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.CallingApTitle:    //0xA6
                    len = buff.GetUInt8();
                    tag = buff.GetUInt8();
                    len = buff.GetUInt8();
                    settings.SourceSystemTitle = new byte[len];
                    buff.Get(settings.SourceSystemTitle);
                    break;

                //Server Challenge.
                case (byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.SenderAcseRequirements:    //0xAA
                    len = buff.GetUInt8();
                    tag = buff.GetUInt8();
                    len = buff.GetUInt8();
                    settings.StoCChallenge = new byte[len];
                    buff.Get(settings.StoCChallenge);
                    break;

                case (byte)BerType.Context | (byte)PduType.SenderAcseRequirements:   //0x8A
                case (byte)BerType.Context | (byte)PduType.CallingApInvocationId:    //0x88
                    //Get sender ACSE-requirements field component.
                    if (buff.GetUInt8() != 2)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    if (buff.GetUInt8() != (byte)BerType.ObjectDescriptor)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    if (buff.GetUInt8() != 0x80)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    break;

                case (byte)BerType.Context | (byte)PduType.MechanismName:         //0x8B
                case (byte)BerType.Context | (byte)PduType.CallingAeInvocationId: //0x89
                    len = buff.GetUInt8();
                    if (buff.GetUInt8() != 0x60)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    if (buff.GetUInt8() != 0x85)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    if (buff.GetUInt8() != 0x74)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    if (buff.GetUInt8() != 0x05)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    if (buff.GetUInt8() != 0x08)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    if (buff.GetUInt8() != 0x02)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    int tmp = buff.GetUInt8();
                    if (tmp < 0 || tmp > 5)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    settings.Authentication = (Authentication)tmp;
                    break;

                case (byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.CallingAuthenticationValue:    //0xAC
                    len = buff.GetUInt8();
                    // Get authentication information.
                    if (buff.GetUInt8() != 0x80)
                    {
                        throw new Exception("Invalid tag.");
                    }
                    len = buff.GetUInt8();
                    if (settings.Authentication < Authentication.HighMD5)
                    {
                        settings.Password = new byte[len];
                        buff.Get(settings.Password);
                    }
                    else
                    {
                        settings.CtoSChallenge = new byte[len];
                        buff.Get(settings.CtoSChallenge);
                    }
                    break;

                case (byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.UserInformation:    //0xBE
                    if (resultComponent != AssociationResult.Accepted && resultDiagnosticValue != SourceDiagnostic.None)
                    {
                        throw new GXDLMSException(resultComponent, resultDiagnosticValue);
                    }
                    ParseUserInformation(settings, cipher, buff);
                    break;

                default:
                    //Unknown tags.
                    System.Diagnostics.Debug.WriteLine("Unknown tag: " + tag + ".");
                    len            = buff.GetUInt8();
                    buff.Position += (UInt16)len;
                    break;
                }
            }
            return(resultDiagnosticValue);
        }
Beispiel #3
0
        /// <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:
                len = GXCommon.GetObjectCount(data);
                if (len != 0)
                {
                    p.SystemTitle = new byte[len];
                    data.Get(p.SystemTitle);
                }
                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.GloEventNotificationRequest:
                break;

            default:
                throw new ArgumentOutOfRangeException("cryptedData");
            }
            int    value         = 0;
            UInt64 transactionId = 0;

            if (cmd == Command.GeneralCiphering)
            {
                len = GXCommon.GetObjectCount(data);
                tmp = new byte[len];
                data.Get(tmp);
                GXByteBuffer t = new GXByteBuffer(tmp);
                transactionId = t.GetUInt64();
                len           = GXCommon.GetObjectCount(data);
                tmp           = new byte[len];
                data.Get(tmp);
                p.SystemTitle = tmp;
                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 == 1)
                {
                    // KeyAgreement.ONE_PASS_DIFFIE_HELLMAN
                    // key-ciphered-data
                    len = GXCommon.GetObjectCount(data);
                    tmp = new byte[len];
                    data.Get(tmp);
                    p.KeyCipheredData = tmp;
                }
                else if (value == 2)
                {
                    // KeyAgreement.STATIC_UNIFIED_MODEL
                    len = GXCommon.GetObjectCount(data);
                    if (len != 0)
                    {
                        throw new ArgumentException("Invalid key parameters");
                    }
                }
                else
                {
                    throw new ArgumentException("key-parameters");
                }
            }
            len = GXCommon.GetObjectCount(data);
            p.CipheredContent = data.Remaining();
            byte sc = (byte)data.GetUInt8();

            Enums.Security security = (Enums.Security)(sc & 0x30);
            SecuritySuite  ss       = (SecuritySuite)(sc & 0x3);

            p.Security = security;
            UInt32 invocationCounter = data.GetUInt32();

            p.InvocationCounter = invocationCounter;
            if (ss != SecuritySuite.AesGcm128)
            {
                throw new NotImplementedException("Security Suite 1 is not implemented.");
            }
            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 (security == Enums.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 (transactionId != 0)
                    {
                        p.InvocationCounter = transactionId;
                    }
                    throw new GXDLMSException("Decrypt failed. Invalid tag.");
                }
                return(encryptedData);
            }
            byte[] ciphertext = null;
            if (security == Enums.Security.Encryption)
            {
                length     = data.Size - data.Position;
                ciphertext = new byte[length];
                data.Get(ciphertext);
            }
            else if (security == Enums.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(security, true,
                                                                    p.BlockCipherKey, aad, iv, tag);

            gcm.Write(ciphertext);
            if (transactionId != 0)
            {
                p.InvocationCounter = transactionId;
            }
            return(gcm.FlushFinalBlock());

            /*
             * len = Gurux.DLMS.Internal.GXCommon.GetObjectCount(data);
             * p.Security = (Gurux.DLMS.Enums.Security)data.GetUInt8();
             * p.InvocationCounter = data.GetUInt32();
             * System.Diagnostics.Debug.WriteLine("Decrypt settings: " + p.ToString());
             * System.Diagnostics.Debug.WriteLine("Encrypted: " + GXCommon.ToHex(data.Array(), true));
             *
             * byte[] tag = new byte[12];
             * byte[] encryptedData;
             * int length;
             * if (p.Security == Gurux.DLMS.Enums.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))
             *  {
             *      throw new GXDLMSException("Decrypt failed. Invalid tag.");
             *  }
             *  return encryptedData;
             * }
             * byte[] ciphertext = null;
             * if (p.Security == Gurux.DLMS.Enums.Security.Encryption)
             * {
             *  length = data.Size - data.Position;
             *  ciphertext = new byte[length];
             *  data.Get(ciphertext);
             * }
             * else if (p.Security == Gurux.DLMS.Enums.Security.AuthenticationEncryption)
             * {
             *  length = data.Size - data.Position - 12;
             *  ciphertext = new byte[length];
             *  data.Get(ciphertext);
             *  data.Get(tag);
             * }
             * byte[] aad = GetAuthenticatedData(p.Security, p.AuthenticationKey, ciphertext);
             * byte[] iv = GetNonse(p.InvocationCounter, p.SystemTitle);
             * GXDLMSChipperingStream gcm = new GXDLMSChipperingStream(p.Security, true, p.BlockCipherKey, aad, iv, tag);
             * gcm.Write(ciphertext);
             * ciphertext = gcm.FlushFinalBlock();
             * if (p.Security == Gurux.DLMS.Enums.Security.AuthenticationEncryption)
             * {
             *  // Check tag.
             *  EncryptAesGcm(p, ciphertext);
             *  if (!GXDLMSChipperingStream.TagsEquals(tag, p.CountTag))
             *  {
             *      //    throw new GXDLMSException("Decrypt failed. Invalid tag.");
             *  }
             * }
             * return ciphertext;
             */
        }
Beispiel #4
0
        private static void GetValue(GXByteBuffer bb, IList <object> objects, GXAsn1Settings s)
        {
            int            len;
            short          type;
            IList <object> tmp;

            byte[] tmp2;
            type = bb.GetUInt8();
            len  = GXCommon.GetObjectCount(bb);
            if (len > bb.Available)
            {
                throw new OutOfMemoryException("GXAsn1Converter.GetValue");
            }
            int connectPos = 0;

            if (s != null)
            {
                connectPos = s.XmlLength;
            }
            int    start     = bb.Position;
            string tagString = null;

            if (s != null)
            {
                s.AppendSpaces();
                if (type == (byte)BerType.Integer)
                {
                    if (len == 1 || len == 2 || len == 4 || len == 8)
                    {
                        tagString = s.GetTag((short)-len);
                    }
                    else
                    {
                        tagString = s.GetTag((byte)BerType.Integer);
                    }
                }
                else
                {
                    tagString = s.GetTag(type);
                }
                s.Append("<" + tagString + ">");
            }

            switch (type)
            {
            case (byte)(BerType.Constructed | BerType.Context):
            case ((byte)(BerType.Constructed | BerType.Context) | 1):
            case ((byte)(BerType.Constructed | BerType.Context) | 2):
            case ((byte)(BerType.Constructed | BerType.Context) | 3):
            case ((byte)(BerType.Constructed | BerType.Context) | 4):
                if (s != null)
                {
                    s.Increase();
                }
                tmp = new GXAsn1Context()
                {
                    Index = type & 0xF
                };
                objects.Add(tmp);
                while (bb.Position < start + len)
                {
                    GetValue(bb, tmp, s);
                }
                if (s != null)
                {
                    s.Decrease();
                }
                break;

            case (byte)(BerType.Constructed | BerType.Sequence):
                if (s != null)
                {
                    s.Increase();
                }
                tmp = new GXAsn1Sequence();
                objects.Add(tmp);
                int cnt = 0;
                while (bb.Position < start + len)
                {
                    ++cnt;
                    GetValue(bb, tmp, s);
                }
                if (s != null)
                {
                    // Append comment.
                    s.AppendComment(connectPos, Convert.ToString(cnt) + " elements.");
                    s.Decrease();
                }
                break;

            case (byte)(BerType.Constructed | BerType.Set):
                if (s != null)
                {
                    s.Increase();
                }
                tmp = new List <object>();
                GetValue(bb, tmp, s);
                if (tmp[0] is GXAsn1Sequence)
                {
                    tmp = (GXAsn1Sequence)tmp[0];
                    objects.Add(new KeyValuePair <object, object>(tmp[0], tmp[1]));
                }
                else
                {
                    KeyValuePair <object, object> e = new KeyValuePair <object, object>(tmp, null);
                    objects.Add(e);
                }
                if (s != null)
                {
                    s.Decrease();
                }
                break;

            case (byte)BerType.ObjectIdentifier:
                GXAsn1ObjectIdentifier oi = new GXAsn1ObjectIdentifier(bb, len);
                objects.Add(oi);
                if (s != null)
                {
                    string str = oi.Description;
                    if (str != null)
                    {
                        s.AppendComment(connectPos, str);
                    }
                    s.Append(oi.ToString());
                }

                break;

            case (byte)BerType.PrintableString:
                objects.Add(bb.GetString(len));
                if (s != null)
                {
                    s.Append(Convert.ToString(objects[objects.Count - 1]));
                }

                break;

            case (byte)BerType.Utf8StringTag:
                objects.Add(new GXAsn1Utf8String(bb.GetString(bb.Position, len)));
                bb.Position = bb.Position + len;
                if (s != null)
                {
                    s.Append(Convert.ToString(objects[objects.Count - 1]));
                }

                break;

            case (byte)BerType.Ia5String:
                objects.Add(new GXAsn1Ia5String(bb.GetString(len)));
                if (s != null)
                {
                    s.Append(Convert.ToString(objects[objects.Count - 1]));
                }
                break;

            case (byte)BerType.Integer:
                if (len == 1)
                {
                    objects.Add(bb.GetInt8());
                }
                else if (len == 2)
                {
                    objects.Add(bb.GetInt16());
                }
                else if (len == 4)
                {
                    objects.Add(bb.GetInt32());
                }
                else
                {
                    tmp2 = new byte[len];
                    bb.Get(tmp2);
                    objects.Add(new GXAsn1Integer(tmp2));
                }
                if (s != null)
                {
                    s.Append(Convert.ToString(objects[objects.Count - 1]));
                }
                break;

            case (byte)BerType.Null:
                objects.Add(null);
                break;

            case (byte)BerType.BitString:
                GXAsn1BitString tmp3 = new GXAsn1BitString(bb.SubArray(bb.Position, len));
                objects.Add(tmp3);
                bb.Position = bb.Position + len;
                if (s != null)
                {
                    // Append comment.
                    s.AppendComment(connectPos, Convert.ToString(tmp3.Length) + " bit.");
                    s.Append(tmp3.asString());
                }
                break;

            case (byte)BerType.UtcTime:
                tmp2 = new byte[len];
                bb.Get(tmp2);
                objects.Add(GetUtcTime(ASCIIEncoding.ASCII.GetString(tmp2)));
                if (s != null)
                {
                    s.Append(((DateTimeOffset)objects[objects.Count - 1]).UtcDateTime.ToString("yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture));
                }
                break;

            case (byte)BerType.GeneralizedTime:
                tmp2 = new byte[len];
                bb.Get(tmp2);
                objects.Add(GXCommon.GetGeneralizedTime(ASCIIEncoding.ASCII.GetString(tmp2)));
                if (s != null)
                {
                    s.Append(Convert.ToString(objects[objects.Count - 1]));
                }
                break;

            case (byte)BerType.Context:
            case (byte)BerType.Context | 1:
            case (byte)BerType.Context | 2:
            case (byte)BerType.Context | 3:
                tmp = new GXAsn1Context()
                {
                    Constructed = false, Index = type & 0xF
                };
                tmp2 = new byte[len];
                bb.Get(tmp2);
                tmp.Add(tmp2);
                objects.Add(tmp);
                if (s != null)
                {
                    s.Append(GXCommon.ToHex(tmp2, false));
                }
                break;

            case (byte)BerType.OctetString:
                int t = bb.GetUInt8(bb.Position);
                switch (t)
                {
                case (byte)(BerType.Constructed | BerType.Sequence):
                case (byte)BerType.BitString:
                    if (s != null)
                    {
                        s.Increase();
                    }
                    GetValue(bb, objects, s);
                    if (s != null)
                    {
                        s.Decrease();
                    }
                    break;

                default:
                    tmp2 = new byte[len];
                    bb.Get(tmp2);
                    objects.Add(tmp2);
                    if (s != null)
                    {
                        s.Append(GXCommon.ToHex(tmp2, false));
                    }
                    break;
                }
                break;

            case (byte)BerType.Boolean:
                bool b = bb.GetUInt8() != 0;
                objects.Add(b);
                if (s != null)
                {
                    s.Append(Convert.ToString(b));
                }
                break;

            default:
                throw new System.ArgumentException("Invalid type: " + type);
            }
            if (s != null)
            {
                s.Append("</" + tagString + ">\r\n");
            }
        }
Beispiel #5
0
        /// <summary>
        /// Parse User Information from PDU.
        /// </summary>
        private static void ParseUserInformation(GXDLMSSettings settings, GXICipher cipher, GXByteBuffer data)
        {
            byte len = data.GetUInt8();

            if (data.Size - data.Position < len)
            {
                throw new Exception("Not enough data.");
            }
            //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 == GXCommon.InitialResponceGlo)
            {
                --data.Position;
                cipher.Security = cipher.Decrypt(settings.SourceSystemTitle, data);
                tag             = data.GetUInt8();
            }
            else if (tag == GXCommon.InitialRequestGlo)
            {
                --data.Position;
                cipher.Security = cipher.Decrypt(settings.SourceSystemTitle, data);
                tag             = data.GetUInt8();
            }
            bool response = tag == GXCommon.InitialResponce;

            if (response)
            {
                //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;
                }
            }
            else if (tag == GXCommon.InitialRequest)
            {
                //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 (settings.IsServer)
            {
                settings.DlmsVersionNumber = data.GetUInt8();
            }
            else
            {
                if (data.GetUInt8() != 6)
                {
                    throw new Exception("Invalid DLMS version number.");
                }
            }

            //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 (settings.UseLogicalNameReferencing)
            {
                if (settings.IsServer)
                {
                    //Skip settings what client asks.
                    //All server settings are always returned.
                    byte[] tmp = new byte[3];
                    data.Get(tmp);
                }
                else
                {
                    data.Get(settings.LnSettings.ConformanceBlock);
                }
            }
            else
            {
                if (settings.IsServer)
                {
                    //Skip settings what client asks.
                    //All server settings are always returned.
                    byte[] tmp = new byte[3];
                    data.Get(tmp);
                }
                else
                {
                    data.Get(settings.SnSettings.ConformanceBlock);
                }
            }
            if (settings.IsServer)
            {
                data.GetUInt16();
            }
            else
            {
                settings.MaxReceivePDUSize = data.GetUInt16();
            }
            if (response)
            {
                //VAA Name
                tag = data.GetUInt16();
                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.");
                }
            }
        }
Beispiel #6
0
        /// <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);
        }
        /// <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");
            }
            int len;
            Command cmd = (Command)data.GetUInt8();
            switch (cmd)
            {
                case Command.GloGeneralCiphering:
                    len = GXCommon.GetObjectCount(data);
                    p.SystemTitle = new byte[len];
                    data.Get(p.SystemTitle);
                    break;
                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.GloEventNotificationRequest:
                    break;
                default:
                    throw new ArgumentOutOfRangeException("cryptedData");
            }
            len = Gurux.DLMS.Internal.GXCommon.GetObjectCount(data);
            p.Security = (Gurux.DLMS.Enums.Security)data.GetUInt8();
            p.FrameCounter = data.GetUInt32();
            System.Diagnostics.Debug.WriteLine("Decrypt settings: " + p.ToString());
            System.Diagnostics.Debug.WriteLine("Encrypted: " + GXCommon.ToHex(data.Array(), true));

            byte[] tag = new byte[12];
            byte[] encryptedData;
            int length;
            if (p.Security == Gurux.DLMS.Enums.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))
                {
                    throw new GXDLMSException("Decrypt failed. Invalid tag.");
                }
                return encryptedData;
            }
            byte[] ciphertext = null;
            if (p.Security == Gurux.DLMS.Enums.Security.Encryption)
            {
                length = data.Size - data.Position;
                ciphertext = new byte[length];
                data.Get(ciphertext);
            }
            else if (p.Security == Gurux.DLMS.Enums.Security.AuthenticationEncryption)
            {
                length = data.Size - data.Position - 12;
                ciphertext = new byte[length];
                data.Get(ciphertext);
                data.Get(tag);
            }
            byte[] aad = GetAuthenticatedData(p.Security, p.AuthenticationKey, data.Array());
            byte[] iv = GetNonse(p.FrameCounter, p.SystemTitle);
            GXDLMSChipperingStream gcm = new GXDLMSChipperingStream(p.Security, true, p.BlockCipherKey, aad, iv, tag);
            gcm.Write(ciphertext);
            return gcm.FlushFinalBlock();
        }
Beispiel #8
0
        /// <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");
            }
            int     len;
            Command cmd = (Command)data.GetUInt8();

            switch (cmd)
            {
            case Command.GeneralGloCiphering:
                len = GXCommon.GetObjectCount(data);
                if (len != 0)
                {
                    p.SystemTitle = new byte[len];
                    data.Get(p.SystemTitle);
                }
                break;

            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.GloEventNotificationRequest:
                break;

            default:
                throw new ArgumentOutOfRangeException("cryptedData");
            }
            len                 = Gurux.DLMS.Internal.GXCommon.GetObjectCount(data);
            p.Security          = (Gurux.DLMS.Enums.Security)data.GetUInt8();
            p.InvocationCounter = data.GetUInt32();
            System.Diagnostics.Debug.WriteLine("Decrypt settings: " + p.ToString());
            System.Diagnostics.Debug.WriteLine("Encrypted: " + GXCommon.ToHex(data.Array(), true));

            byte[] tag = new byte[12];
            byte[] encryptedData;
            int    length;

            if (p.Security == Gurux.DLMS.Enums.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))
                {
                    throw new GXDLMSException("Decrypt failed. Invalid tag.");
                }
                return(encryptedData);
            }
            byte[] ciphertext = null;
            if (p.Security == Gurux.DLMS.Enums.Security.Encryption)
            {
                length     = data.Size - data.Position;
                ciphertext = new byte[length];
                data.Get(ciphertext);
            }
            else if (p.Security == Gurux.DLMS.Enums.Security.AuthenticationEncryption)
            {
                length     = data.Size - data.Position - 12;
                ciphertext = new byte[length];
                data.Get(ciphertext);
                data.Get(tag);
            }
            byte[] aad = GetAuthenticatedData(p.Security, p.AuthenticationKey, ciphertext);
            byte[] iv  = GetNonse(p.InvocationCounter, p.SystemTitle);
            GXDLMSChipperingStream gcm = new GXDLMSChipperingStream(p.Security, true, p.BlockCipherKey, aad, iv, tag);

            gcm.Write(ciphertext);
            ciphertext = gcm.FlushFinalBlock();
            if (p.Security == Gurux.DLMS.Enums.Security.AuthenticationEncryption)
            {
                // Check tag.
                EncryptAesGcm(p, ciphertext);
                if (!GXDLMSChipperingStream.TagsEquals(tag, p.CountTag))
                {
                    //    throw new GXDLMSException("Decrypt failed. Invalid tag.");
                }
            }
            return(ciphertext);
        }
Beispiel #9
0
 ///<summary>
 ///Get octect string value from DLMS data.
 ///</summary>
 ///<param name="buff">
 ///Received DLMS data.
 ///</param>
 ///<param name="info">
 ///Data info.
 ///</param>
 ///<returns>
 ///Parsed octet string value.
 ///</returns>
 private static object GetOctetString(GXByteBuffer buff, GXDataInfo info, bool knownType)
 {
     object value;
     int len;
     if (knownType)
     {
         len = buff.Size;
     }
     else
     {
         len = GXCommon.GetObjectCount(buff);
         // If there is not enough data available.
         if (buff.Size - buff.Position < len)
         {
             info.Complete = false;
             return null;
         }
     }
     byte[] tmp = new byte[len];
     buff.Get(tmp);
     value = tmp;
     if (info.xml != null)
     {
         info.xml.AppendLine(info.xml.GetDataType(info.Type), "Value", GXCommon.ToHex(tmp, false));
     }
     return value;
 }
Beispiel #10
0
        private static void updatePassword(GXDLMSSettings settings, GXByteBuffer buff, GXDLMSTranslatorStructure xml)
        {
            int len = buff.GetUInt8();
            // Get authentication information.
            if (buff.GetUInt8() != 0x80)
            {
                throw new Exception("Invalid tag.");
            }
            len = buff.GetUInt8();
            if (settings.Authentication == Authentication.Low)
            {
                settings.Password = new byte[len];
                buff.Get(settings.Password);
            }
            else
            {
                settings.CtoSChallenge = new byte[len];
                buff.Get(settings.CtoSChallenge);
            }

            if (xml != null)
            {
                if (xml.OutputType == TranslatorOutputType.SimpleXml)
                {
                    if (settings.Authentication == Authentication.Low)
                    {
                        xml.AppendLine(TranslatorGeneralTags.CallingAuthentication,
                                       "Value",
                                       GXCommon.ToHex(settings.Password, false));
                    }
                    else
                    {
                        xml.AppendLine(TranslatorGeneralTags.CallingAuthentication,
                                       "Value",
                                       GXCommon.ToHex(settings.CtoSChallenge, false));
                    }
                }
                else
                {
                    xml.AppendStartTag(
                        TranslatorGeneralTags.CallingAuthentication);
                    xml.AppendStartTag(TranslatorGeneralTags.CharString);
                    if (settings.Authentication == Authentication.Low)
                    {
                        xml.Append(GXCommon.ToHex(settings.Password, false));
                    }
                    else
                    {
                        xml.Append(
                            GXCommon.ToHex(settings.CtoSChallenge, false));
                    }
                    xml.AppendEndTag(TranslatorGeneralTags.CharString);
                    xml.AppendEndTag(TranslatorGeneralTags.CallingAuthentication);
                }
            }
        }
Beispiel #11
0
        ///<summary>
        ///Parse APDU.
        ///</summary>
        static internal SourceDiagnostic ParsePDU(GXDLMSSettings settings, GXICipher cipher,
                GXByteBuffer buff, GXDLMSTranslatorStructure xml)
        {
            // Get AARE tag and length
            int tag = buff.GetUInt8();
            if (settings.IsServer)
            {
                if (tag != ((byte)BerType.Application | (byte)BerType.Constructed | (byte)PduType.ProtocolVersion))
                {
                    throw new Exception("Invalid tag.");
                }
            }
            else
            {
                if (tag != ((byte)BerType.Application | (byte)BerType.Constructed | (byte)PduType.ApplicationContextName))
                {
                    throw new Exception("Invalid tag.");
                }
            }
            int len = buff.GetUInt8();
            int size = buff.Size - buff.Position;
            if (len > size)
            {
                throw new Exception("Not enough data.");
            }
            //Opening tags
            if (xml != null)
            {
                if (settings.IsServer)
                {
                    xml.AppendStartTag(Command.Aarq);
                }
                else
                {
                    xml.AppendStartTag(Command.Aare);
                }
            }
            AssociationResult resultComponent = AssociationResult.Accepted;
            SourceDiagnostic resultDiagnosticValue = SourceDiagnostic.None;
            while (buff.Position < buff.Size)
            {
                tag = buff.GetUInt8();
                switch (tag)
                {
                    case (byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.ApplicationContextName://0xA1
                        if (!ParseApplicationContextName(settings, buff, xml))
                        {
                            throw new GXDLMSException(AssociationResult.PermanentRejected, SourceDiagnostic.ApplicationContextNameNotSupported);
                        }
                        break;
                    case (byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.CalledApTitle://0xA2
                                                                                                         //Get len.
                        if (buff.GetUInt8() != 3)
                        {
                            throw new Exception("Invalid tag.");
                        }
                        //Choice for result (INTEGER, universal)
                        if (buff.GetUInt8() != (byte)BerType.Integer)
                        {
                            throw new Exception("Invalid tag.");
                        }
                        //Get len.
                        if (buff.GetUInt8() != 1)
                        {
                            throw new Exception("Invalid tag.");
                        }
                        resultComponent = (AssociationResult)buff.GetUInt8();
                        if (xml != null)
                        {
                            xml.AppendLine(TranslatorGeneralTags.AssociationResult, "Value", xml.IntegerToHex((int)resultComponent, 2));
                            xml.AppendStartTag(TranslatorGeneralTags.ResultSourceDiagnostic);
                        }
                        break;
                    case (byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.CalledAeQualifier:////SourceDiagnostic 0xA3
                        len = buff.GetUInt8();
                        // ACSE service user tag.
                        tag = buff.GetUInt8();
                        len = buff.GetUInt8();
                        // Result source diagnostic component.
                        if (buff.GetUInt8() != (byte)BerType.Integer)
                        {
                            throw new Exception("Invalid tag.");
                        }
                        if (buff.GetUInt8() != 1)
                        {
                            throw new Exception("Invalid tag.");
                        }
                        resultDiagnosticValue = (SourceDiagnostic)buff.GetUInt8();
                        if (xml != null)
                        {
                            xml.AppendLine(TranslatorGeneralTags.ACSEServiceUser, "Value", xml.IntegerToHex((int)resultDiagnosticValue, 2));
                            xml.AppendEndTag(TranslatorGeneralTags.ResultSourceDiagnostic);
                        }
                        break;
                    case (byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.CalledApInvocationId:
                        ////Result 0xA4
                        //Get len.
                        if (buff.GetUInt8() != 0xA)
                        {
                            throw new Exception("Invalid tag.");
                        }
                        //Choice for result (Universal, Octetstring type)
                        if (buff.GetUInt8() != (byte)BerType.OctetString)
                        {
                            throw new Exception("Invalid tag.");
                        }
                        //responding-AP-title-field
                        //Get len.
                        len = buff.GetUInt8();
                        settings.SourceSystemTitle = new byte[len];
                        buff.Get(settings.SourceSystemTitle);
                        if (xml != null)
                        {
                            //RespondingAPTitle
                            xml.AppendLine(TranslatorGeneralTags.RespondingAPTitle, "Value", GXCommon.ToHex(settings.SourceSystemTitle, false));
                        }
                        break;
                    //Client Challenge.
                    case (byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.CallingApTitle://0xA6
                        len = buff.GetUInt8();
                        tag = buff.GetUInt8();
                        len = buff.GetUInt8();
                        settings.SourceSystemTitle = new byte[len];
                        buff.Get(settings.SourceSystemTitle);
                        if (xml != null)
                        {
                            //CallingAPTitle
                            xml.AppendLine(TranslatorGeneralTags.CallingAPTitle, "Value", GXCommon.ToHex(settings.SourceSystemTitle, false));
                        }
                        break;
                    //Server Challenge.
                    case (byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.SenderAcseRequirements://0xAA
                        len = buff.GetUInt8();
                        tag = buff.GetUInt8();
                        len = buff.GetUInt8();
                        settings.StoCChallenge = new byte[len];
                        buff.Get(settings.StoCChallenge);
                        AppendServerSystemTitleToXml(settings, xml, tag);
                        break;
                    case (byte)BerType.Context | (byte)PduType.SenderAcseRequirements:
                    //0x8A
                    case (byte)BerType.Context | (byte)PduType.CallingApInvocationId:
                        //0x88

                        //Get sender ACSE-requirements field component.
                        if (buff.GetUInt8() != 2)
                        {
                            throw new Exception("Invalid tag.");
                        }
                        if (buff.GetUInt8() != (byte)BerType.ObjectDescriptor)
                        {
                            throw new Exception("Invalid tag.");
                        }
                        if (buff.GetUInt8() != 0x80)
                        {
                            throw new Exception("Invalid tag.");
                        }
                        //SenderACSERequirements
                        if (xml != null)
                        {
                            xml.AppendLine(tag, "Value", "1");
                        }
                        break;
                    case (byte)BerType.Context | (byte)PduType.MechanismName://0x8B
                    case (byte)BerType.Context | (byte)PduType.CallingAeInvocationId://0x89
                        UpdateAuthentication(settings, buff);
                        if (xml != null)
                        {
                            if (xml.OutputType == TranslatorOutputType.SimpleXml)
                            {
                                xml.AppendLine(tag, "Value", settings.Authentication.ToString());
                            }
                            else
                            {
                                xml.AppendLine(tag, "Value", ((int)settings.Authentication).ToString());
                            }
                        }
                        break;
                    case (byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.CallingAuthenticationValue://0xAC
                        updatePassword(settings, buff, xml);
                        break;
                    case (byte)BerType.Context | (byte)BerType.Constructed | (byte)PduType.UserInformation:
                        //0xBE
                        if (xml == null && resultComponent != AssociationResult.Accepted && resultDiagnosticValue != SourceDiagnostic.None)
                        {
                            throw new GXDLMSException(resultComponent, resultDiagnosticValue);
                        }
                        ParseUserInformation(settings, cipher, buff, xml);
                        break;
                    default:
                        //Unknown tags.
                        System.Diagnostics.Debug.WriteLine("Unknown tag: " + tag + ".");
                        if (buff.Position < buff.Size)
                        {
                            len = buff.GetUInt8();
                            buff.Position += (UInt16)len;
                        }
                        break;
                }
            }
            //Closing tags
            if (xml != null)
            {
                if (settings.IsServer)
                {
                    xml.AppendEndTag(Command.Aarq);
                }
                else
                {
                    xml.AppendEndTag(Command.Aare);
                }
            }
            return resultDiagnosticValue;
        }
Beispiel #12
0
        /// <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);
            }
        }
        /// <summary>
        /// Update ephemeral keys.
        /// </summary>
        /// <param name="client">DLMS Client.</param>
        /// <param name="value">Received reply from the server.</param>
        /// <returns>List of Parsed key id and GUAK. This is for debugging purpose.</returns>
        public List <KeyValuePair <GlobalKeyType, byte[]> > UpdateEphemeralKeys(GXDLMSSecureClient client, GXByteBuffer value)
        {
            if (client == null)
            {
                throw new ArgumentNullException(nameof(client));
            }
            if (value.GetUInt8() != (byte)DataType.Array)
            {
                throw new ArgumentOutOfRangeException("Invalid tag.");
            }
            GXEcdsa c     = new GXEcdsa(client.Ciphering.EphemeralKeyPair.Key);
            int     count = GXCommon.GetObjectCount(value);
            List <KeyValuePair <GlobalKeyType, byte[]> > list = new List <KeyValuePair <GlobalKeyType, byte[]> >();

            for (int pos = 0; pos != count; ++pos)
            {
                if (value.GetUInt8() != (byte)DataType.Structure)
                {
                    throw new ArgumentOutOfRangeException("Invalid tag.");
                }
                if (value.GetUInt8() != 2)
                {
                    throw new ArgumentOutOfRangeException("Invalid length.");
                }
                if (value.GetUInt8() != (byte)DataType.Enum)
                {
                    throw new ArgumentOutOfRangeException("Invalid key id data type.");
                }
                int keyId = value.GetUInt8();
                if (keyId > 4)
                {
                    throw new ArgumentOutOfRangeException("Invalid key type.");
                }
                if (value.GetUInt8() != (byte)DataType.OctetString)
                {
                    throw new ArgumentOutOfRangeException("Invalid tag.");
                }
                if (GXCommon.GetObjectCount(value) != 128)
                {
                    throw new ArgumentOutOfRangeException("Invalid length.");
                }
                //Get ephemeral public key server.
                GXByteBuffer key = new GXByteBuffer();
                key.SetUInt8(4);
                key.Set(value, 64);
                GXPublicKey targetEphemeralKey = GXPublicKey.FromRawBytes(key.Array());
                //Get ephemeral public key signature server.
                byte[] signature = new byte[64];
                value.Get(signature);
                key.SetUInt8(0, (byte)keyId);
                //Verify signature.
                if (!GXSecure.ValidateEphemeralPublicKeySignature(key.Array(), signature, client.Ciphering.SigningKeyPair.Value))
                {
                    throw new GXDLMSCipherException("Invalid signature.");
                }
                byte[] z = c.GenerateSecret(targetEphemeralKey);
                System.Diagnostics.Debug.WriteLine("Shared secret:" + GXCommon.ToHex(z, true));
                GXByteBuffer kdf = new GXByteBuffer();
                kdf.Set(GXSecure.GenerateKDF(client.SecuritySuite, z,
                                             AlgorithmId.AesGcm128,
                                             client.Ciphering.SystemTitle,
                                             client.Settings.SourceSystemTitle, null, null));
                System.Diagnostics.Debug.WriteLine("KDF:" + kdf.ToString());
                list.Add(new KeyValuePair <GlobalKeyType, byte[]>((GlobalKeyType)keyId, kdf.SubArray(0, 16)));
            }
            //Update ephemeral keys.
            foreach (KeyValuePair <GlobalKeyType, byte[]> it in list)
            {
                switch (it.Key)
                {
                case GlobalKeyType.UnicastEncryption:
                    client.Settings.EphemeralBlockCipherKey = it.Value;
                    break;

                case GlobalKeyType.BroadcastEncryption:
                    client.Settings.EphemeralBroadcastBlockCipherKey = it.Value;
                    break;

                case GlobalKeyType.Authentication:
                    client.Settings.EphemeralAuthenticationKey = it.Value;
                    break;

                case GlobalKeyType.Kek:
                    client.Settings.EphemeralKek = it.Value;
                    break;
                }
            }
            return(list);
        }
Beispiel #14
0
        /// <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");
            }
            Command cmd = (Command)data.GetUInt8();

            if (!((byte)cmd == 0x21 || (byte)cmd == 0x28 ||
                  cmd == Command.GloGetRequest ||
                  cmd == Command.GloGetResponse ||
                  cmd == Command.GloSetRequest ||
                  cmd == Command.GloSetResponse ||
                  cmd == Command.GloMethodRequest ||
                  cmd == Command.GloMethodResponse))
            {
                throw new ArgumentOutOfRangeException("cryptedData");
            }
            int len = Gurux.DLMS.Internal.GXCommon.GetObjectCount(data);

            p.Security     = (Security)data.GetUInt8();
            p.FrameCounter = data.GetUInt32();
            System.Diagnostics.Debug.WriteLine("Decrypt settings: " + p.ToString());
            System.Diagnostics.Debug.WriteLine("Encrypted: " + GXCommon.ToHex(data.Array(), true));

            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))
                {
                    throw new GXDLMSException("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.Security, p.AuthenticationKey, data.Array());
            GXDLMSChipperingStream gcm = new GXDLMSChipperingStream(p.Security, false, p.BlockCipherKey, aad, GetNonse(p.FrameCounter, p.SystemTitle), tag);

            gcm.Write(ciphertext);
            return(gcm.FlushFinalBlock());
        }