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);
            }
        }
        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);
            }
        }
        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());
        }
Exemple #4
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();
 }
 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);
 }
        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);
            }
        }
Exemple #7
0
 internal DataBlock(CosemConnection outerInstance)
 {
     this.outerInstance = outerInstance;
     data = new System.IO.MemoryStream();
 }
        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);
                }
            }
        }
        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);
        }