public static byte[] reverseAuthenticatedEncryption(CosemParameters parameters, CosemConnection connection, byte[] data)
        {
            switch (data[0] & 0xff)
            {
            case SC_AUTHENTICATION:
                byte[] aux = helper.extensions.copyOfRange(data, 1, 5);
                connection.serverInvocationCounter = BitConverter.ToInt32(new byte[] { (aux[3]), (aux[2]), (aux[1]), (aux[0]) }, 0);
                return(aesGcmReverse(new byte[0], helper.extensions.copyOfRange(data, 5, data.Length), parameters, connection));

            case SC_AUTHENTICATION_ENCRYPTION:
                byte[] authData = new byte[parameters.ak.Length + 1];
                authData[0] = SC_AUTHENTICATION_ENCRYPTION;
                Array.Copy(parameters.ak, 0, authData, 1, parameters.ak.Length);
                aux = helper.extensions.copyOfRange(data, 1, 5);
                connection.serverInvocationCounter = BitConverter.ToInt32(new byte[] { (aux[3]), (aux[2]), (aux[1]), (aux[0]) }, 0);
                return(aesGcmReverse(helper.extensions.copyOfRange(data, 5, data.Length), authData, parameters, connection));

            case SC_ENCRYPTION:
                aux = helper.extensions.copyOfRange(data, 1, 5);
                connection.serverInvocationCounter = BitConverter.ToInt32(new byte[] { (aux[3]), (aux[2]), (aux[1]), (aux[0]) }, 0);
                return(aesGcmReverse(helper.extensions.copyOfRange(data, 5, data.Length), new byte[0], parameters, connection));

            default:
                return(data);
            }
        }
Example #2
0
        private static byte[] generateInitiateRequest(CosemParameters parameters)
        {
            System.IO.MemoryStream stream = new System.IO.MemoryStream();
            stream.WriteByte(Constants.xDlmsApdu.NoCiphering.INITIATE_REQUEST);
            stream.WriteByte(0);                              //Dedicated key
            stream.WriteByte(0);                              //Response-allowed
            stream.WriteByte(0);                              //Proposed quality of service
            stream.WriteByte(Constants.DLMS_VERSION);         //Dlms version
            stream.WriteByte(Constants.ConformanceBlock.TAG); //Conformance block tag
            byte[] conformance = generateConformanceBlock(parameters);
            stream.WriteByte((byte)(conformance.Length));
            stream.Write(conformance, 0, conformance.Length);             //Conformance block

            //stream.WriteByte(ByteBuffer.allocate(2).putShort(parameters.maxPduSize).array());
            stream.WriteByte((byte)(parameters.maxPduSize >> 8)); //Max pdu size
            stream.WriteByte((byte)(parameters.maxPduSize));

            System.IO.MemoryStream stream2 = new System.IO.MemoryStream();
            if (parameters.securityType != SecurityType.NONE)
            {
                stream2.WriteByte(Constants.xDlmsApdu.GlobalCiphering.INITIATE_REQUEST);
                byte[] data = Security.authenticatedEncryption(parameters, stream.ToArray());
                stream2.WriteByte((byte)(data.Length));
                stream2.Write(data, 0, data.Length);
            }
            else
            {
                //stream2.WriteByte(stream.ToArray());
                byte[] aux = stream.ToArray();
                stream2.Write(aux, 0, aux.Length);
            }
            return(stream2.ToArray());
        }
        public static byte[] authenticatedEncryption(CosemParameters parameters, byte[] data)
        {
            if (parameters.securityType == SecurityType.NONE)
            {
                return(data);
            }
            int ivCounter = parameters.getInvocationCounter();
            int sc        = 0;

            switch (parameters.securityType)
            {
            case SecurityType.AUTHENTICATION:
                sc = SC_AUTHENTICATION;
                byte[] authData = new byte[parameters.ak.Length + data.Length + 1];
                authData[0] = SC_AUTHENTICATION;
                Array.Copy(parameters.ak, 0, authData, 1, parameters.ak.Length);
                Array.Copy(data, 0, authData, parameters.ak.Length + 1, data.Length);
                byte[] mac   = aesGcm(new byte[0], authData, parameters, ivCounter);
                byte[] data_ = new byte[data.Length + mac.Length];
                Array.Copy(data, 0, data_, 0, data.Length);
                Array.Copy(mac, 0, data_, data.Length, mac.Length);
                data = data_;
                break;

            case SecurityType.AUTHENTICATION_ENCRYPTION:
                sc          = SC_AUTHENTICATION_ENCRYPTION;
                authData    = new byte[parameters.ak.Length + 1];
                authData[0] = SC_AUTHENTICATION_ENCRYPTION;
                Array.Copy(parameters.ak, 0, authData, 1, parameters.ak.Length);
                data = aesGcm(data, authData, parameters, ivCounter);
                break;

            case SecurityType.ENCRYPTION:
                sc   = SC_ENCRYPTION;
                data = aesGcm(data, new byte[0], parameters, ivCounter);
                break;

            default:
                throw new System.InvalidOperationException();
            }

            try
            {
                System.IO.MemoryStream stream = new System.IO.MemoryStream();
                stream.WriteByte((byte)sc);
                stream.WriteByte((byte)(ivCounter >> 24));
                stream.WriteByte((byte)(ivCounter >> 16));
                stream.WriteByte((byte)(ivCounter >> 8));
                stream.WriteByte((byte)(ivCounter));
                stream.Write(data, 0, data.Length);
                return(stream.ToArray());
            }
            catch (IOException)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.INTERNAL_ERROR);
            }
        }
 internal static byte[] generateChallanger(CosemParameters parameters)
 {
     byte[] random = new byte[parameters.challengerSize];
     lock (randomLocker)
     {
         sr.NextBytes(random);
     }
     return(random);
 }
        internal static bool verifyChallenger(CosemParameters parameters, CosemConnection connection, byte[] data)
        {
            if (data == null || data.Length == 0)
            {
                return(false);
            }
            try
            {
                byte[] calculated = new byte[0];
                switch (parameters.authenticationType.innerEnumValue)
                {
                case AuthenticationType.InnerEnum.PUBLIC:
                case AuthenticationType.InnerEnum.LLS:
                    throw new System.InvalidOperationException();

                case AuthenticationType.InnerEnum.HLS:
                    calculated = aes128(connection.challengeServerToClient, parameters.llsHlsSecret);
                    break;

                case AuthenticationType.InnerEnum.HLS_MD5:
                    calculated = md5(connection.challengeClientToServer, parameters.llsHlsSecret);
                    break;

                case AuthenticationType.InnerEnum.HLS_SHA1:
                    calculated = sha1(connection.challengeClientToServer, parameters.llsHlsSecret);
                    break;

                case AuthenticationType.InnerEnum.HLS_GMAC:
                    if (data[0] != SC_AUTHENTICATION)
                    {
                        return(false);
                    }
                    System.IO.MemoryStream stream = new System.IO.MemoryStream();
                    stream.WriteByte(SC_AUTHENTICATION);
                    stream.Write(parameters.ak, 0, parameters.ak.Length);
                    stream.Write(connection.challengeClientToServer, 0, connection.challengeClientToServer.Length);
                    //connection.serverInvocationCounter = BitConverter.ToInt32(helper.extensions.copyOfRange(data, 1, 5), 0);
                    var aux = helper.extensions.copyOfRange(data, 1, 5);
                    connection.serverInvocationCounter = BitConverter.ToInt32(new byte[] { (aux[3]), (aux[2]), (aux[1]), (aux[0]) }, 0);
                    data = helper.extensions.copyOfRange(data, 5, data.Length);
                    CosemParameters cosemParams = new CosemParameters();
                    cosemParams.setSystemTitle(connection.serverSysTitle);
                    cosemParams.setEk(parameters.ek);
                    calculated = Security.aesGcm(new byte[0], stream.ToArray(), cosemParams, connection.serverInvocationCounter);
                    break;

                default:
                    throw new System.ArgumentException();
                }
                return(Enumerable.SequenceEqual(data, calculated));
            }
            catch (IOException)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.INTERNAL_ERROR);
            }
        }
 public static byte[] aesGcmReverse(byte[] encrypted, byte[] authData, CosemParameters parameters, CosemConnection connection)
 {
     try
     {
         byte[] iv = getIv(connection.serverSysTitle, connection.serverInvocationCounter);
         lock (cipherLocker)
         {
             using (var cipherStream = new MemoryStream(encrypted))
                 using (var cipherReader = new BinaryReader(cipherStream))
                 {
                     var cipher = new GcmBlockCipher(new AesEngine());
                     cipher.Init(false, new AeadParameters(new KeyParameter(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }), MacBitSize, iv));
                     var cipherText = cipherReader.ReadBytes(encrypted.Length);
                     var plainText  = new byte[cipher.GetOutputSize(cipherText.Length)];
                     var len        = cipher.ProcessBytes(cipherText, 0, cipherText.Length, plainText, 0);
                     cipher.ProcessAadBytes(authData, 0, authData.Length);
                     cipher.DoFinal(plainText, len);
                     return(plainText);
                 }
         }
     }
     catch (InvalidKeyException e)
     {
         Console.WriteLine(e.ToString());
         Console.Write(e.StackTrace);
     }
     //catch (InvalidAlgorithmParameterException e)
     catch (InvalidParameterException e)
     {
         Console.WriteLine(e.ToString());
         Console.Write(e.StackTrace);
     }
     //catch (IllegalBlockSizeException e)
     catch (CryptographicException e)
     {
         Console.WriteLine(e.ToString());
         Console.Write(e.StackTrace);
     }
     //catch (AEADBadTagException)
     //{
     //    throw new DlmsException(DlmsException.DlmsExceptionReason.SECURITY_FAIL);
     //}
     //catch (BadPaddingException e)
     //{
     //    Console.WriteLine(e.ToString());
     //    Console.Write(e.StackTrace);
     //}
     throw new DlmsException(DlmsException.DlmsExceptionReason.INTERNAL_ERROR);
 }
        internal static byte[] processChallanger(CosemParameters parameters, CosemConnection connection)
        {
            try
            {
                switch (parameters.authenticationType.innerEnumValue)
                {
                case AuthenticationType.InnerEnum.PUBLIC:
                case AuthenticationType.InnerEnum.LLS:
                    throw new System.InvalidOperationException();

                case AuthenticationType.InnerEnum.HLS:
                    return(aes128(connection.challengeServerToClient, parameters.llsHlsSecret));

                case AuthenticationType.InnerEnum.HLS_MD5:
                    return(md5(connection.challengeServerToClient, parameters.llsHlsSecret));

                case AuthenticationType.InnerEnum.HLS_SHA1:
                    return(sha1(connection.challengeServerToClient, parameters.llsHlsSecret));

                case AuthenticationType.InnerEnum.HLS_GMAC:
                    int ivCounter = parameters.getInvocationCounter();
                    System.IO.MemoryStream data = new System.IO.MemoryStream();
                    data.WriteByte(SC_AUTHENTICATION);
                    data.Write(parameters.ak, 0, parameters.ak.Length);
                    data.Write(connection.challengeServerToClient, 0, connection.challengeServerToClient.Length);
                    System.IO.MemoryStream stream = new System.IO.MemoryStream();
                    stream.WriteByte(SC_AUTHENTICATION);
                    stream.WriteByte((byte)(ivCounter >> 24));
                    stream.WriteByte((byte)(ivCounter >> 16));
                    stream.WriteByte((byte)(ivCounter >> 8));
                    stream.WriteByte((byte)(ivCounter));
                    byte[] aux = Security.aesGcm(new byte[0], data.ToArray(), parameters, ivCounter);
                    stream.Write(aux, 0, aux.Length);
                    return(stream.ToArray());

                default:
                    throw new System.ArgumentException();
                }
            }
            catch (IOException)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.INTERNAL_ERROR);
            }
        }
 public static byte[] aesGcm(byte[] data, byte[] authData, CosemParameters parameters, int ivCounter)
 {
     try
     {
         byte[] iv = getIv(parameters.systemTitle, ivCounter);
         lock (cipherLocker)
         {
             var cipher = new GcmBlockCipher(new AesEngine());
             cipher.Init(true, new AeadParameters(new KeyParameter(parameters.ek), MacBitSize, iv));
             var cipherText = new byte[cipher.GetOutputSize(data.Length)];
             var len        = cipher.ProcessBytes(data, 0, data.Length, cipherText, 0);
             cipher.ProcessAadBytes(authData, 0, authData.Length);
             cipher.DoFinal(cipherText, len);
             return(cipherText);
         }
     }
     catch (InvalidKeyException e)
     {
         Console.WriteLine(e.ToString());
         Console.Write(e.StackTrace);
     }
     catch (InvalidParameterException e)
     {
         Console.WriteLine(e.ToString());
         Console.Write(e.StackTrace);
     }
     catch (CryptographicException e)
     {
         Console.WriteLine(e.ToString());
         Console.Write(e.StackTrace);
     }
     //catch (AEADBadTagException)
     //{
     //    throw new DlmsException(DlmsException.DlmsExceptionReason.SECURITY_FAIL);
     //}
     //catch (BadPaddingException e)
     //{
     //    Console.WriteLine(e.ToString());
     //    Console.Write(e.StackTrace);
     //}
     throw new DlmsException(DlmsException.DlmsExceptionReason.INTERNAL_ERROR);
 }
Example #9
0
        private static byte[] generateConformanceBlock(CosemParameters parameters)
        {
            int conformanceBlock = 0;

            if (parameters.referenceType == ReferenceType.SHORT_NAME)
            {
                conformanceBlock |= Constants.ConformanceBlock.READ;
                conformanceBlock |= Constants.ConformanceBlock.WRITE;
            }
            if (parameters.referenceType == ReferenceType.LOGICAL_NAME)
            {
                conformanceBlock |= Constants.ConformanceBlock.GET;
                conformanceBlock |= Constants.ConformanceBlock.SET;
            }
            conformanceBlock |= Constants.ConformanceBlock.ACTION;
            conformanceBlock |= Constants.ConformanceBlock.BLOCK_TRANSFER_WITH_ACTION;
            conformanceBlock |= Constants.ConformanceBlock.BLOCK_TRANSFER_WITH_GET_OR_READ;
            conformanceBlock |= Constants.ConformanceBlock.BLOCK_TRANSFER_WITH_SET_OR_WRITE;
            conformanceBlock |= Constants.ConformanceBlock.SELECTIVE_ACCESS;
            //return ByteBuffer.allocate(4).putInt(conformanceBlock).array();
            return(new byte[] { (byte)(conformanceBlock >> 24), (byte)(conformanceBlock >> 16), (byte)(conformanceBlock >> 8), (byte)(conformanceBlock) });
        }
Example #10
0
        internal static byte[] request(CosemParameters parameters, CosemConnection connection)
        {
            const int BASE = Constants.Ber.CLASS_CONTEXT | Constants.Ber.CONSTRUCTED;

            byte[] applicationContextName = generateApplicationContextName(parameters.referenceType, parameters.securityType);
            connection.proposedContextName = applicationContextName;
            System.IO.MemoryStream data = new System.IO.MemoryStream();

            //TODO
            if (parameters.authenticationType == AuthenticationType.PUBLIC)
            {
                //data.WriteByte(new byte[] {(byte)0x80, 0x02, 0x07, (byte)0x80});
                byte[] aux = new byte[] { (byte)0x80, 0x02, 0x07, (byte)0x80 };
                data.Write(aux, 0, aux.Length);
            }

            data.WriteByte(BASE | Constants.AarqApdu.APPLICATION_CONTEXT_NAME);
            data.WriteByte((byte)(applicationContextName.Length + 2));
            data.WriteByte(Constants.Ber.OBJECT_IDENTIFIER);
            data.WriteByte((byte)(applicationContextName.Length));
            data.Write(applicationContextName, 0, applicationContextName.Length);             //big or little endian?

            if (parameters.securityType != SecurityType.NONE || parameters.authenticationType == AuthenticationType.HLS_GMAC)
            {
                data.WriteByte(BASE | Constants.Ber.OBJECT_IDENTIFIER);
                data.WriteByte((byte)(parameters.systemTitle.Length + 2));
                data.WriteByte(Constants.Ber.OCTET_STRING);
                data.WriteByte((byte)(parameters.systemTitle.Length));
                //data.WriteByte((byte)(parameters.systemTitle));
                byte[] aux = parameters.systemTitle;
                data.Write(aux, 0, aux.Length);
            }
            if (parameters.authenticationType != AuthenticationType.PUBLIC)
            {
                data.WriteByte(Constants.Ber.CLASS_CONTEXT | Constants.AarqApdu.SENDER_ACSE_REQUIREMENTS);
                data.WriteByte(2);
                data.WriteByte(Constants.Ber.BIT_STRING | Constants.Ber.OCTET_STRING);
                data.WriteByte(0x80);
                data.WriteByte(Constants.Ber.CLASS_CONTEXT | Constants.AarqApdu.MECHANISM_NAME);
                data.WriteByte(7);
                //data.WriteByte(new byte[]{0x60, (byte)0x85, 0x74, 0x05, 0x08, 0x02, (byte)parameters.authenticationType.value});
                byte[] aux = new byte[] { 0x60, (byte)0x85, 0x74, 0x05, 0x08, 0x02, (byte)parameters.authenticationType.value };
                data.Write(aux, 0, aux.Length);

                data.WriteByte(BASE | Constants.AarqApdu.CALLING_AUTHENTICATION_VALUE);
                if (parameters.authenticationType == AuthenticationType.LLS)
                {
                    data.WriteByte((byte)(parameters.llsHlsSecret.Length + 2));
                    data.WriteByte(Constants.Ber.CLASS_CONTEXT);
                    data.WriteByte((byte)(parameters.llsHlsSecret.Length));
                    //data.WriteByte(parameters.llsHlsSecret);
                    byte[] aux2 = parameters.llsHlsSecret;
                    data.Write(aux2, 0, aux2.Length);
                }
                else if (parameters.authenticationType != AuthenticationType.PUBLIC)
                {
                    connection.challengeClientToServer = Security.generateChallanger(parameters);
                    data.WriteByte((byte)(connection.challengeClientToServer.Length + 2));
                    data.WriteByte(Constants.Ber.CLASS_CONTEXT);
                    data.WriteByte((byte)(connection.challengeClientToServer.Length));
                    //data.WriteByte(connection.challengeClientToServer);
                    byte[] aux2 = connection.challengeClientToServer;
                    data.Write(aux2, 0, aux2.Length);
                }
            }
            data.WriteByte(Constants.Ber.CONTEXT_CONSTRUCTED | Constants.AarqApdu.USER_INFORMATION);
            byte[] initiateRequest = generateInitiateRequest(parameters);
            data.WriteByte((byte)(initiateRequest.Length + 2));
            data.WriteByte(Constants.Ber.OCTET_STRING);
            data.WriteByte((byte)(initiateRequest.Length));
            data.Write(initiateRequest, 0, initiateRequest.Length);
            System.IO.MemoryStream stream = new System.IO.MemoryStream();
            stream.WriteByte(Constants.Ber.CLASS_APPLICATION | Constants.Ber.CONSTRUCTED);
            stream.WriteByte((byte)(data.Length));
            stream.Write(data.ToArray(), 0, data.ToArray().Length);

            return(stream.ToArray());
        }
Example #11
0
 /// <summary>
 /// Creates a Cosem object </summary>
 /// <param name="params"> CosemParameters for this Cosem object </param>
 public Cosem(CosemParameters parameters)
 {
     this.parameters = parameters;
     this.connection = new CosemConnection();
 }
Example #12
0
        internal static void parseResponse(CosemParameters parameters, CosemConnection connection, byte[] data)
        {
            if (data == null || data.Length < 4)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
            }

            if ((data[0] & 0xFF) != Constants.AareApdu.APPLICATION_1)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
            }

            if ((data[1] & 0xFF) != data.Length - 2)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
            }

            if ((data[2] & 0xFF) != (Constants.Ber.CONTEXT_CONSTRUCTED | Constants.AareApdu.APPLICATION_CONTEXT_NAME))
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
            }

            int offset = (data[3] & 0xFF) + 4;

            parseContextName(helper.extensions.copyOfRange(data, 4, offset), connection.proposedContextName);
            if ((data[offset++] & 0xFF) != (Constants.Ber.CONTEXT_CONSTRUCTED | Constants.AareApdu.RESULT))
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
            }

            int resultLen = data[offset++] & 0xFF;

            byte[] result = helper.extensions.copyOfRange(data, offset, offset + resultLen);
            offset += resultLen;
            if ((data[offset++] & 0xFF) != (Constants.Ber.CONTEXT_CONSTRUCTED | Constants.AareApdu.RESULT_SOURCE_DIAGNOSTIC))
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
            }

            resultLen = data[offset++] & 0xFF;
            byte[] diagnostic = helper.extensions.copyOfRange(data, offset, offset + resultLen);
            offset += resultLen;

            parseResultAndDiagnostic(result, diagnostic);

            //Parse optional tags
            while (offset < data.Length)
            {
                int tag = (data[offset++] & 0xFF);
                int len = (data[offset++] & 0xFF);
                if (data.Length < (offset + len))
                {
                    throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
                }
                byte[] value = helper.extensions.copyOfRange(data, offset, offset + len);
                offset += len;
                if (tag == (Constants.Ber.CONTEXT_CONSTRUCTED | Constants.AareApdu.RESPONDING_AP_TITLE))
                {
                    if (value[0] != Constants.Ber.OCTET_STRING || value[1] != value.Length - 2)
                    {
                        throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
                    }
                    connection.serverSysTitle = helper.extensions.copyOfRange(value, 2, value.Length);
                    StringBuilder sb = new StringBuilder();
                    foreach (byte b in connection.serverSysTitle)
                    {
                        sb.Append(b);
                    }
                    Console.WriteLine(sb);
                }
                else if (tag == (Constants.Ber.CLASS_CONTEXT | Constants.AareApdu.RESPONDER_ACSE_REQUIREMENTS))
                {
                    //System.out.println("Resp ACSE Req: "+printBytes(value));
                }
                else if (tag == (Constants.Ber.CLASS_CONTEXT | Constants.AareApdu.MECHANISM_NAME))
                {
                    //System.out.println("Mechanism Name: "+printBytes(value));
                }
                else if (tag == (Constants.Ber.CONTEXT_CONSTRUCTED | Constants.AareApdu.RESPONDING_AUTHENTICATION_VALUE))
                {
                    if ((value[0] & 0xFF) != 0x80 || value[1] != value.Length - 2)
                    {
                        throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
                    }
                    connection.challengeServerToClient = helper.extensions.copyOfRange(value, 2, value.Length);
                }
                else if (tag == (Constants.Ber.CONTEXT_CONSTRUCTED | Constants.AareApdu.USER_INFORMATION))
                {
                    parseUserInfo(value, parameters, connection);
                }
            }
        }
Example #13
0
        private static void parseUserInfo(byte[] data, CosemParameters parameters, CosemConnection connection)
        {
            if (data == null || data.Length < 16)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
            }
            if (data[0] != Constants.Ber.OCTET_STRING)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
            }
            if (data[1] < 14 || data[1] != data.Length - 2)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
            }
            if (parameters.securityType != SecurityType.NONE)
            {
                if (data[2] != Constants.xDlmsApdu.GlobalCiphering.INITIATE_RESPONSE)
                {
                    throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
                }
                if (data[3] != data.Length - 4)
                {
                    throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
                }
                byte[] encrypted = new byte[data[3] & 0xFF];
                Array.Copy(data, 4, encrypted, 0, encrypted.Length);
                data = Security.reverseAuthenticatedEncryption(parameters, connection, encrypted);
            }
            else
            {
                data = helper.extensions.copyOfRange(data, 2, data.Length);
            }
            if (data[0] != Constants.xDlmsApdu.NoCiphering.INITIATE_RESPONSE)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
            }
            if (data[1] != 0 || data[2] != Constants.DLMS_VERSION)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
            }
            if (data[3] != Constants.ConformanceBlock.TAG)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
            }
            if (data[4] != 0x1F || data[5] != 0x04 || data[6] != 0x00)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
            }
            connection.conformanceBlock = helper.extensions.copyOfRange(data, 7, 10);
            //int vaa = ByteBuffer.allocate(2).put(Arrays.copyOfRange(data, 12, data.Length)).getShort(0);
            byte[] aux = helper.extensions.copyOfRange(data, 12, data.Length);
            int    vaa = BitConverter.ToInt16(new byte[] { (aux[1]), (aux[0]) }, 0);

            if (parameters.referenceType == ReferenceType.LOGICAL_NAME && vaa != 0x0007)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
            }
            if (parameters.referenceType == ReferenceType.SHORT_NAME && vaa != 0xFA00)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.MALFORMED_AARE_FRAME);
            }
            connection.maxPduSize = ((data[10] & 0xFF) << 8) | (data[11] & 0xFF);
        }