Beispiel #1
0
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();

            if (Scheme == Ecc.P256)
            {
                sb.AppendLine("NIST P-256");
            }
            else if (Scheme == Ecc.P384)
            {
                sb.AppendLine("NIST P-384");
            }
            else
            {
                throw new ArgumentOutOfRangeException("Invalid scheme.");
            }
            GXByteBuffer pk   = new GXByteBuffer(RawValue);
            int          size = pk.Size / 2;

            sb.Append(" public x coord: ");
            sb.AppendLine(new GXBigInteger(pk.SubArray(1, size)).ToString());
            sb.Append(" public y coord: ");
            sb.AppendLine(new GXBigInteger(pk.SubArray(1 + size, size)).ToString());
            return(sb.ToString());
        }
Beispiel #2
0
        /// <summary>
        /// Check that this is correct public key.
        /// </summary>
        /// <remarks>
        /// This method can be used to verify that public and private key are on the curve.
        /// </remarks>
        public static void Validate(GXPublicKey publicKey)
        {
            if (publicKey == null)
            {
                throw new ArgumentNullException("Invalid public key.");
            }
            GXByteBuffer bb = new GXByteBuffer();

            bb.Set(publicKey.RawValue);
            int          size  = SchemeSize(publicKey.Scheme);
            GXBigInteger x     = new GXBigInteger(bb.SubArray(1, size));
            GXBigInteger y     = new GXBigInteger(bb.SubArray(1 + size, size));
            GXCurve      curve = new GXCurve(publicKey.Scheme);

            y.Multiply(y);
            y.Mod(curve.P);

            GXBigInteger tmpX = new GXBigInteger(x);

            tmpX.Multiply(x);
            tmpX.Mod(curve.P);
            tmpX.Add(curve.A);
            tmpX.Multiply(x);
            tmpX.Add(curve.B);
            tmpX.Mod(curve.P);
            if (y.Compare(tmpX) != 0)
            {
                throw new ArgumentException("Public key validate failed. Public key is not valid ECDSA public key.");
            }
        }
Beispiel #3
0
        /// <summary>
        /// Verify that signature matches the data.
        /// </summary>
        /// <param name="signature">Generated signature.</param>
        /// <param name="data">Data to valuate.</param>
        /// <returns></returns>
        public bool Verify(byte[] signature, byte[] data)
        {
            GXBigInteger msg;

            if (PublicKey == null)
            {
                if (PrivateKey == null)
                {
                    throw new ArgumentNullException("Invalid private key.");
                }
                PublicKey = PrivateKey.GetPublicKey();
            }
            if (PublicKey.Scheme == Ecc.P256)
            {
                using (SHA256 sha = new SHA256CryptoServiceProvider())
                {
                    msg = new GXBigInteger(sha.ComputeHash(data));
                }
            }
            else
            {
                using (SHA384 sha = new SHA384CryptoServiceProvider())
                {
                    msg = new GXBigInteger(sha.ComputeHash(data));
                }
            }
            GXByteBuffer pk   = new GXByteBuffer(PublicKey.RawValue);
            GXByteBuffer bb   = new GXByteBuffer(signature);
            int          size = SchemeSize(PublicKey.Scheme);
            GXBigInteger sigR = new GXBigInteger(bb.SubArray(0, size));
            GXBigInteger sigS = new GXBigInteger(bb.SubArray(size, size));
            GXBigInteger inv  = sigS;

            inv.Inv(curve.N);
            // Calculate u1 and u2.
            GXEccPoint u1 = new GXEccPoint(curve.G.x, curve.G.y, new GXBigInteger(1));
            GXEccPoint u2 = new GXEccPoint(new GXBigInteger(pk.SubArray(1, size)),
                                           new GXBigInteger(pk.SubArray(1 + size, size)), new GXBigInteger(1));
            GXBigInteger n = msg;

            n.Multiply(inv);
            n.Mod(curve.N);
            Multiply(u1, n, curve.N, curve.A, curve.P);
            n = new GXBigInteger(sigR);
            n.Multiply(inv);
            n.Mod(curve.N);
            Multiply(u2, n, curve.N, curve.A, curve.P);
            u1.z = new GXBigInteger(1);
            u2.z = new GXBigInteger(1);
            JacobianAdd(u1, u2, curve.A, curve.P);
            FromJacobian(u1, curve.P);
            return(sigR.Compare(u1.x) == 0);
        }
Beispiel #4
0
        /// <summary>
        /// Verify that signature matches the data.
        /// </summary>
        /// <param name="signature">Generated signature.</param>
        /// <param name="data">Data to valuate.</param>
        /// <returns></returns>
        public bool Verify(byte[] signature, byte[] data)
        {
            GXBigInteger msg;

            using (SHA256 sha = new SHA256CryptoServiceProvider())
            {
                msg = new GXBigInteger(sha.ComputeHash(data));
            }
            if (PublicKey == null)
            {
                PublicKey = PrivateKey.GetPublicKey();
            }
            GXByteBuffer pk   = new GXByteBuffer(PublicKey.RawValue);
            GXByteBuffer bb   = new GXByteBuffer(signature);
            GXBigInteger sigR = new GXBigInteger(bb.SubArray(0, 32));
            GXBigInteger sigS = new GXBigInteger(bb.SubArray(32, 32));
            GXBigInteger inv  = sigS;

            inv.Inv(curve.N);
            // Calculate u1 and u2.
            GXEccPoint   u1 = new GXEccPoint(curve.G.x, curve.G.y, new GXBigInteger(1));
            GXEccPoint   u2 = new GXEccPoint(new GXBigInteger(pk.SubArray(1, 32)), new GXBigInteger(pk.SubArray(33, 32)), new GXBigInteger(1));
            GXBigInteger n  = msg;

            n.Multiply(inv);
            n.Mod(curve.N);
            Multiply(u1, n, curve.N, curve.A, curve.P);
            n = new GXBigInteger(sigR);
            n.Multiply(inv);
            n.Mod(curve.N);
            Multiply(u2, n, curve.N, curve.A, curve.P);
            //  add = Math.add(u1, u2, P = curve.P, A = curve.A)
            u1.z = new GXBigInteger(1);
            u2.z = new GXBigInteger(1);
            JacobianAdd(u1, u2, curve.A, curve.P);
            FromJacobian(u1, curve.P);
            return(sigR.Compare(u1.x) == 0);
        }
Beispiel #5
0
        /// <summary>
        /// Sign
        /// </summary>
        /// <param name="key">Private key. </param>
        /// <param name="HashAlgorithm">Used algorithm for signing. </param>
        void Sign(GXPrivateKey key, HashAlgorithm HashAlgorithm)
        {
            byte[]  data = GXAsn1Converter.ToByteArray(GetData());
            GXEcdsa e    = new GXEcdsa(key);

            SignatureAlgorithm = HashAlgorithm;
            GXByteBuffer bb = new GXByteBuffer();

            bb.Set(e.Sign(data));
            int size = SignatureAlgorithm == HashAlgorithm.Sha256WithEcdsa ? 32 : 48;

            object[] tmp = new object[] { new GXAsn1Integer(bb.SubArray(0, size)), new GXAsn1Integer(bb.SubArray(size, size)) };
            Signature = GXAsn1Converter.ToByteArray(tmp);
        }
Beispiel #6
0
        /// <summary>
        /// Generate shared secret from public and private key.
        /// </summary>
        /// <param name="publicKey">Public key.</param>
        /// <returns>Generated secret.</returns>
        public byte[] GenerateSecret(GXPublicKey publicKey)
        {
            if (PrivateKey == null)
            {
                throw new ArgumentNullException("Invalid private key.");
            }
            if (PrivateKey.Scheme != publicKey.Scheme)
            {
                throw new ArgumentNullException("Private key scheme is different than public key.");
            }
            GXByteBuffer bb = new GXByteBuffer();

            bb.Set(publicKey.RawValue);
            int          size  = SchemeSize(PrivateKey.Scheme);
            GXBigInteger x     = new GXBigInteger(bb.SubArray(1, size));
            GXBigInteger y     = new GXBigInteger(bb.SubArray(1 + size, size));
            GXBigInteger pk    = new GXBigInteger(PrivateKey.RawValue);
            GXCurve      curve = new GXCurve(PrivateKey.Scheme);
            GXEccPoint   p     = new GXEccPoint(x, y, new GXBigInteger(1));

            p = JacobianMultiply(p, pk, curve.N, curve.A, curve.P);
            FromJacobian(p, curve.P);
            return(p.x.ToArray());
        }
Beispiel #7
0
        /// <summary>
        /// Test is x509 file certified by the certifier.
        /// </summary>
        /// <param name="certifier">Public key of the certifier.</param>
        /// <returns>True, if certifier has certified the certificate.</returns>
        public bool IsCertified(GXPublicKey certifier)
        {
            if (certifier == null)
            {
                throw new ArgumentNullException(nameof(certifier));
            }
            //Get raw data
            GXByteBuffer tmp2 = new GXByteBuffer();

            tmp2.Set(Encoded);
            GXAsn1Converter.GetNext(tmp2);
            tmp2.Size     = tmp2.Position;
            tmp2.Position = 1;
            GXCommon.GetObjectCount(tmp2);
            GXEcdsa        e    = new GXEcdsa(certifier);
            GXAsn1Sequence tmp3 = (GXAsn1Sequence)GXAsn1Converter.FromByteArray(Signature);
            GXByteBuffer   bb   = new GXByteBuffer();
            int            size = SignatureAlgorithm == HashAlgorithm.Sha256WithEcdsa ? 32 : 48;

            //Some implementations might add extra byte. It must removed.
            bb.Set(((GXAsn1Integer)tmp3[0]).Value, ((GXAsn1Integer)tmp3[0]).Value.Length == size ? 0 : 1, size);
            bb.Set(((GXAsn1Integer)tmp3[1]).Value, ((GXAsn1Integer)tmp3[1]).Value.Length == size ? 0 : 1, size);
            return(e.Verify(bb.Array(), tmp2.SubArray(tmp2.Position, tmp2.Available)));
        }
Beispiel #8
0
 object IGXDLMSBase.GetValue(GXDLMSSettings settings, ValueEventArgs e)
 {
     if (e.Index == 1)
     {
         return(GXCommon.LogicalNameToBytes(LogicalName));
     }
     if (e.Index == 2)
     {
         return(GetObjects(settings, e).Array());
     }
     if (e.Index == 3)
     {
         GXByteBuffer data = new GXByteBuffer();
         data.SetUInt8((byte)DataType.Structure);
         //Add count
         data.SetUInt8(2);
         data.SetUInt8((byte)DataType.Int8);
         data.SetUInt8(ClientSAP);
         data.SetUInt8((byte)DataType.UInt16);
         data.SetUInt16(ServerSAP);
         return(data.Array());
     }
     if (e.Index == 4)
     {
         GXByteBuffer data = new GXByteBuffer();
         data.SetUInt8((byte)DataType.Structure);
         //Add count
         data.SetUInt8(0x7);
         GXCommon.SetData(settings, data, DataType.UInt8, ApplicationContextName.JointIsoCtt);
         GXCommon.SetData(settings, data, DataType.UInt8, ApplicationContextName.Country);
         GXCommon.SetData(settings, data, DataType.UInt16, ApplicationContextName.CountryName);
         GXCommon.SetData(settings, data, DataType.UInt8, ApplicationContextName.IdentifiedOrganization);
         GXCommon.SetData(settings, data, DataType.UInt8, ApplicationContextName.DlmsUA);
         GXCommon.SetData(settings, data, DataType.UInt8, ApplicationContextName.ApplicationContext);
         GXCommon.SetData(settings, data, DataType.UInt8, ApplicationContextName.ContextId);
         return(data.Array());
     }
     if (e.Index == 5)
     {
         GXByteBuffer data = new GXByteBuffer();
         data.SetUInt8((byte)DataType.Structure);
         data.SetUInt8(6);
         GXByteBuffer bb = new GXByteBuffer();
         bb.SetUInt32((UInt32)XDLMSContextInfo.Conformance);
         GXCommon.SetData(settings, data, DataType.BitString, bb.SubArray(1, 3));
         GXCommon.SetData(settings, data, DataType.UInt16, XDLMSContextInfo.MaxReceivePduSize);
         GXCommon.SetData(settings, data, DataType.UInt16, XDLMSContextInfo.MaxSendPduSize);
         GXCommon.SetData(settings, data, DataType.UInt8, XDLMSContextInfo.DlmsVersionNumber);
         GXCommon.SetData(settings, data, DataType.Int8, XDLMSContextInfo.QualityOfService);
         GXCommon.SetData(settings, data, DataType.OctetString, XDLMSContextInfo.CypheringInfo);
         return(data.Array());
     }
     if (e.Index == 6)
     {
         GXByteBuffer data = new GXByteBuffer();
         data.SetUInt8((byte)DataType.Structure);
         //Add count
         data.SetUInt8(0x7);
         GXCommon.SetData(settings, data, DataType.UInt8, AuthenticationMechanismName.JointIsoCtt);
         GXCommon.SetData(settings, data, DataType.UInt8, AuthenticationMechanismName.Country);
         GXCommon.SetData(settings, data, DataType.UInt16, AuthenticationMechanismName.CountryName);
         GXCommon.SetData(settings, data, DataType.UInt8, AuthenticationMechanismName.IdentifiedOrganization);
         GXCommon.SetData(settings, data, DataType.UInt8, AuthenticationMechanismName.DlmsUA);
         GXCommon.SetData(settings, data, DataType.UInt8, AuthenticationMechanismName.AuthenticationMechanismName);
         GXCommon.SetData(settings, data, DataType.UInt8, AuthenticationMechanismName.MechanismId);
         return(data.Array());
     }
     if (e.Index == 7)
     {
         return(Secret);
     }
     if (e.Index == 8)
     {
         return(AssociationStatus);
     }
     if (e.Index == 9)
     {
         return(GXCommon.LogicalNameToBytes(SecuritySetupReference));
     }
     if (e.Index == 10)
     {
         return(GetUserList(settings, e).Array());
     }
     if (e.Index == 11)
     {
         GXByteBuffer data = new GXByteBuffer();
         data.SetUInt8((byte)DataType.Structure);
         //Add structure size.
         data.SetUInt8(2);
         GXCommon.SetData(settings, data, DataType.UInt8, CurrentUser.Key);
         GXCommon.SetData(settings, data, DataType.String, CurrentUser.Value);
         return(data.Array());
     }
     e.Error = ErrorCode.ReadWriteDenied;
     return(null);
 }
Beispiel #9
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 #10
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);
        }
        byte[] IGXDLMSBase.Invoke(GXDLMSSettings settings, ValueEventArgs e)
        {
            if (e.Index == 1)
            {
                SecurityPolicy = (SecurityPolicy)e.Parameters;
            }
            else if (e.Index == 2)
            {
                try
                {
                    foreach (List <object> item in e.Parameters as List <object> )
                    {
                        GlobalKeyType type = (GlobalKeyType)Convert.ToInt32(item[0]);
                        byte[]        data = (byte[])item[1];
                        //if settings.Cipher is null non secure server is used.
                        //Keys are take in action after reply is generated.
                        switch (type)
                        {
                        case GlobalKeyType.UnicastEncryption:
                            GXDLMSSecureClient.Decrypt(settings.Kek, data);
                            break;

                        case GlobalKeyType.BroadcastEncryption:
                            //Invalid type
                            e.Error = ErrorCode.ReadWriteDenied;
                            break;

                        case GlobalKeyType.Authentication:
                            GXDLMSSecureClient.Decrypt(settings.Kek, data);
                            break;

                        case GlobalKeyType.Kek:
                            GXDLMSSecureClient.Decrypt(settings.Kek, data);
                            break;

                        default:
                            //Invalid type
                            e.Error = ErrorCode.ReadWriteDenied;
                            break;
                        }
                    }
                }
                catch (Exception)
                {
                    e.Error = ErrorCode.ReadWriteDenied;
                }
            }
            else if (e.Index == 3)
            {
                // key_agreement
                try
                {
                    List <Object> tmp   = (List <Object>)(e.Parameters as List <Object>)[0];
                    byte          keyId = (byte)tmp[0];
                    if (keyId != 0)
                    {
                        e.Error = ErrorCode.InconsistentClass;
                    }
                    else
                    {
                        byte[] data = (byte[])tmp[0];
                        // ephemeral public key
                        GXByteBuffer data2 = new GXByteBuffer(65);
                        data2.SetUInt8(keyId);
                        data2.Set(data, 0, 64);
                        GXByteBuffer sign = new GXByteBuffer();
                        sign.Set(data, 64, 64);
                        GXPublicKey pk      = null;
                        string      subject = SystemTitleToSubject(settings.SourceSystemTitle);
                        foreach (GXx509Certificate it in settings.Cipher.Certificates)
                        {
                            if ((it.KeyUsage & KeyUsage.DigitalSignature) != 0 && it.Subject == subject)
                            {
                                pk = it.PublicKey;
                                break;
                            }
                        }
                        if (pk == null) //TODO:|| !GXSecure.ValidateEphemeralPublicKeySignature(data2.Array(), sign.Array(), pk))
                        {
                            e.Error = ErrorCode.InconsistentClass;
                            settings.TargetEphemeralKey = null;
                        }
                        else
                        {
                            settings.TargetEphemeralKey = GXPublicKey.FromRawBytes(data2.SubArray(1, 64));
                            // Generate ephemeral keys.
                            KeyValuePair <GXPrivateKey, GXPublicKey> eKpS = settings.Cipher.EphemeralKeyPair;
                            if (eKpS.Key == null)
                            {
                                eKpS = GXEcdsa.GenerateKeyPair(GetEcc(SecuritySuite));
                                settings.Cipher.EphemeralKeyPair = eKpS;
                            }
                            // Generate shared secret.
                            return(null);
                        }
                    }
                }
                catch (Exception)
                {
                    e.Error = ErrorCode.InconsistentClass;
                }
            }
            else if (e.Index == 4)
            {
                // generate_key_pair
                CertificateType key = (CertificateType)(int)e.Parameters;
                KeyValuePair <GXPrivateKey, GXPublicKey> value = GXEcdsa.GenerateKeyPair(GetEcc(SecuritySuite));
                switch (key)
                {
                case CertificateType.DigitalSignature:
                    settings.Cipher.SigningKeyPair = value;
                    break;

                case CertificateType.KeyAgreement:
                    settings.Cipher.KeyAgreementKeyPair = value;
                    break;

                default:
                    e.Error = ErrorCode.InconsistentClass;
                    break;
                }
            }
            else if (e.Index == 5)
            {
                // generate_certificate_request
                CertificateType key = (CertificateType)(int)e.Parameters;
                try
                {
                    KeyValuePair <GXPrivateKey, GXPublicKey> kp = default(KeyValuePair <GXPrivateKey, GXPublicKey>);
                    switch (key)
                    {
                    case CertificateType.DigitalSignature:
                        kp = settings.Cipher.SigningKeyPair;
                        break;

                    case CertificateType.KeyAgreement:
                        kp = settings.Cipher.KeyAgreementKeyPair;
                        break;

                    default:
                        break;
                    }
                    if (kp.Key != null)
                    {
                        GXPkcs10 pkc10 = GXPkcs10.CreateCertificateSigningRequest(kp, SystemTitleToSubject(settings.Cipher.SystemTitle));
                        return(pkc10.Encoded);
                    }
                    else
                    {
                        e.Error = ErrorCode.ReadWriteDenied;
                    }
                }
                catch (Exception)
                {
                    e.Error = ErrorCode.ReadWriteDenied;
                }
            }
            else if (e.Index == 6)
            {
                // import_certificate
                GXx509Certificate cert = new GXx509Certificate((byte[])e.Parameters);
                if (cert.KeyUsage == 0)
                {
                    // At least one bit must be used.
                    e.Error = ErrorCode.InconsistentClass;
                }
                else
                {
                    settings.Cipher.Certificates.Add(cert);
                }
            }
            else if (e.Index == 7)
            {
                // export_certificate
                List <Object>     tmp  = (List <Object>)e.Parameters;
                short             type = (short)tmp[0];
                GXx509Certificate cert = null;
                lock (settings.Cipher.Certificates)
                {
                    if (type == 0)
                    {
                        tmp  = (List <Object>)tmp[1];
                        cert = FindCertificateByEntity(settings, (CertificateEntity)tmp[0], (CertificateType)tmp[1], (byte[])tmp[2]);
                    }
                    else if (type == 1)
                    {
                        tmp  = (List <Object>)tmp[1];
                        cert = FindCertificateBySerial(settings, (byte[])tmp[1], ASCIIEncoding.ASCII.GetString((byte[])tmp[2]));
                    }
                    if (cert == null)
                    {
                        e.Error = ErrorCode.InconsistentClass;
                    }
                    else
                    {
                        return(cert.Encoded);
                    }
                }
            }
            else if (e.Index == 8)
            {
                // remove_certificate
                List <Object>     tmp  = (List <Object>)((List <object>)e.Parameters)[0];
                short             type = (short)tmp[0];
                GXx509Certificate cert = null;
                lock (settings.Cipher.Certificates)
                {
                    if (type == 0)
                    {
                        cert = FindCertificateByEntity(settings, (CertificateEntity)tmp[1], (CertificateType)tmp[2], (byte[])tmp[3]);
                    }
                    else if (type == 1)
                    {
                        cert = FindCertificateBySerial(settings, (byte[])tmp[1], ASCIIEncoding.ASCII.GetString((byte[])tmp[2]));
                    }
                    if (cert == null)
                    {
                        e.Error = ErrorCode.InconsistentClass;
                    }
                    else
                    {
                        settings.Cipher.Certificates.Remove(cert);
                    }
                }
            }
            else
            {
                e.Error = ErrorCode.ReadWriteDenied;
            }
            //Return standard reply.
            return(null);
        }
        /// <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 #13
0
        private void Init(byte[] data)
        {
            rawData    = data;
            Attributes = new List <KeyValuePair <PkcsObjectIdentifier, object[]> >();
            GXAsn1Sequence seq = (GXAsn1Sequence)GXAsn1Converter.FromByteArray(data);

            if (seq.Count < 3)
            {
                throw new System.ArgumentException("Wrong number of elements in sequence.");
            }
            if (!(seq[0] is GXAsn1Sequence))
            {
                PkcsType type = GXAsn1Converter.GetCertificateType(data, seq);
                switch (type)
                {
                case PkcsType.Pkcs8:
                    throw new GXDLMSCertificateException("Invalid Certificate. This is PKCS 8, not PKCS 10.");

                case PkcsType.x509Certificate:
                    throw new GXDLMSCertificateException("Invalid Certificate. This is PKCS x509 certificate, not PKCS 10.");
                }
                throw new GXDLMSCertificateException("Invalid Certificate Version.");
            }
            /////////////////////////////
            // CertificationRequestInfo ::= SEQUENCE {
            // version INTEGER { v1(0) } (v1,...),
            // subject Name,
            // subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
            // attributes [0] Attributes{{ CRIAttributes }}
            // }

            GXAsn1Sequence reqInfo = (GXAsn1Sequence)seq[0];

            Version = (CertificateVersion)(sbyte)reqInfo[0];
            Subject = GXAsn1Converter.GetSubject((GXAsn1Sequence)reqInfo[1]);
            // subject Public key info.
            GXAsn1Sequence subjectPKInfo = (GXAsn1Sequence)reqInfo[2];

            if (reqInfo.Count > 3)
            {
                //PkcsObjectIdentifier
                foreach (GXAsn1Sequence it in (GXAsn1Context)reqInfo[3])
                {
                    List <object> values = new List <object>();
                    foreach (object v in (List <object>)((KeyValuePair <object, object>)it[1]).Key)
                    {
                        values.Add(v);
                    }
                    Attributes.Add(new KeyValuePair <PkcsObjectIdentifier, object[]>(PkcsObjectIdentifierConverter.FromString(it[0].ToString()), values.ToArray()));
                }
            }
            GXAsn1Sequence tmp = (GXAsn1Sequence)subjectPKInfo[0];

            Algorithm = X9ObjectIdentifierConverter.FromString(tmp[0].ToString());
            if (Algorithm != X9ObjectIdentifier.IdECPublicKey)
            {
                object algorithm = Algorithm;
                if (Algorithm == X9ObjectIdentifier.None)
                {
                    algorithm = PkcsObjectIdentifierConverter.FromString(tmp[0].ToString());
                    if ((PkcsObjectIdentifier)algorithm == PkcsObjectIdentifier.None)
                    {
                        algorithm = tmp[0].ToString();
                    }
                }
                throw new Exception("Invalid PKCS #10 certificate algorithm. " + algorithm);
            }
            PublicKey = GXPublicKey.FromRawBytes(((GXAsn1BitString)subjectPKInfo[1]).Value);
            GXEcdsa.Validate(PublicKey);
            /////////////////////////////
            // signatureAlgorithm
            GXAsn1Sequence sign = (GXAsn1Sequence)seq[1];

            SignatureAlgorithm = HashAlgorithmConverter.FromString(sign[0].ToString());
            if (SignatureAlgorithm != HashAlgorithm.Sha256WithEcdsa && SignatureAlgorithm != HashAlgorithm.Sha384WithEcdsa)
            {
                throw new GXDLMSCertificateException("Invalid signature algorithm. " + sign[0].ToString());
            }
            if (sign.Count != 1)
            {
                SignatureParameters = sign[1];
            }
            /////////////////////////////
            // signature
            //Get raw data
            GXByteBuffer tmp2 = new GXByteBuffer();

            tmp2.Set(data);
            GXAsn1Converter.GetNext(tmp2);
            tmp2.Size     = tmp2.Position;
            tmp2.Position = 1;
            GXCommon.GetObjectCount(tmp2);
            //Get signature.
            Signature = ((GXAsn1BitString)seq[2]).Value;
            GXEcdsa        e    = new GXEcdsa(PublicKey);
            GXAsn1Sequence tmp3 = (GXAsn1Sequence)GXAsn1Converter.FromByteArray(Signature);
            GXByteBuffer   bb   = new GXByteBuffer();
            int            size = SignatureAlgorithm == HashAlgorithm.Sha256WithEcdsa ? 32 : 48;

            //Some implementations might add extra byte. It must removed.
            bb.Set(((GXAsn1Integer)tmp3[0]).Value, ((GXAsn1Integer)tmp3[0]).Value.Length == size ? 0 : 1, size);
            bb.Set(((GXAsn1Integer)tmp3[1]).Value, ((GXAsn1Integer)tmp3[1]).Value.Length == size ? 0 : 1, size);
            if (!e.Verify(bb.Array(), tmp2.SubArray(tmp2.Position, tmp2.Available)))
            {
                throw new ArgumentException("Invalid Signature.");
            }
        }