/// <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."); } }
/// <summary> /// Generate public and private key pair. /// </summary> /// <returns></returns> public static KeyValuePair <GXPrivateKey, GXPublicKey> GenerateKeyPair(Ecc scheme) { byte[] raw = GetRandomNumber(scheme).ToArray(); GXPrivateKey pk = GXPrivateKey.FromRawBytes(raw); GXPublicKey pub = pk.GetPublicKey(); return(new KeyValuePair <GXPrivateKey, GXPublicKey>(pk, pub)); }
/// <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); }
/// <summary> /// Create the private key from DER. /// </summary> /// <param name="key">DER Base64 coded string.</param> /// <returns></returns> public static GXPrivateKey FromDer(string der) { der = der.Replace("\r\n", ""); der = der.Replace("\n", ""); byte[] key = GXCommon.FromBase64(der); GXAsn1Sequence seq = (GXAsn1Sequence)GXAsn1Converter.FromByteArray(key); if ((sbyte)seq[0] > 3) { throw new ArgumentOutOfRangeException("Invalid private key version."); } List <object> tmp = (List <object>)seq[2]; GXPrivateKey value = new GXPrivateKey(); X9ObjectIdentifier id = X9ObjectIdentifierConverter.FromString(tmp[0].ToString()); switch (id) { case X9ObjectIdentifier.Prime256v1: value.Scheme = Ecc.P256; break; case X9ObjectIdentifier.Secp384r1: value.Scheme = Ecc.P384; break; default: if (id == X9ObjectIdentifier.None) { throw new ArgumentOutOfRangeException("Invalid private key " + tmp[0].ToString() + "."); } else { throw new ArgumentOutOfRangeException("Invalid private key " + id + " " + tmp[0].ToString() + "."); } } value.RawValue = (byte[])seq[1]; if (seq[3] is byte[]) { value.publicKey = GXPublicKey.FromRawBytes((byte[])seq[3]); } else { //Open SSL PEM. value.publicKey = GXPublicKey.FromRawBytes(((GXAsn1BitString)((List <object>)seq[3])[0]).Value); } return(value); }
/// <summary> /// Get public key from private key. /// </summary> /// <param name="scheme">Used scheme.</param> /// <param name="privateKey">Private key bytes.</param> /// <returns>Public key.</returns> public GXPublicKey GetPublicKey() { GXBigInteger secret = new GXBigInteger(RawValue); GXCurve curve = new GXCurve(Scheme); GXEccPoint p = new GXEccPoint(curve.G.x, curve.G.y, new GXBigInteger(1)); p = GXEcdsa.JacobianMultiply(p, secret, curve.N, curve.A, curve.P); GXEcdsa.FromJacobian(p, curve.P); GXByteBuffer key = new GXByteBuffer(65); //Public key is un-compressed format. key.SetUInt8(4); byte[] tmp = p.x.ToArray(); key.Set(tmp, tmp.Length % 32, 32); tmp = p.y.ToArray(); key.Set(tmp, tmp.Length % 32, 32); return(GXPublicKey.FromRawBytes(key.Array())); }
/// <summary> /// Create the public key from raw bytes. /// </summary> /// <param name="key">Raw data</param> /// <returns>Public key.</returns> public static GXPublicKey FromRawBytes(byte[] key) { GXPublicKey value = new GXPublicKey(); if (key.Length == 65) { value.Scheme = Ecc.P256; value.RawValue = key; } else if (key.Length == 97) { value.Scheme = Ecc.P384; value.RawValue = key; } else { throw new ArgumentOutOfRangeException("Invalid public key."); } return(value); }
/// <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); }
/// <summary> /// Create the public key from raw bytes. /// </summary> /// <param name="key">Raw data</param> /// <returns>Public key.</returns> public static GXPublicKey FromRawBytes(byte[] key) { GXPublicKey value = new GXPublicKey(); if (key.Length == 65) { value.Scheme = Ecc.P256; value.RawValue = key; } else if (key.Length == 97) { value.Scheme = Ecc.P384; value.RawValue = key; } else if (key.Length == 64) { //Compression tag is not send in DLMS messages. value.Scheme = Ecc.P256; value.RawValue = new byte[65]; value.RawValue[0] = 4; Array.Copy(key, 0, value.RawValue, 1, 64); } else if (key.Length == 96) { //Compression tag is not send in DLMS messages. value.Scheme = Ecc.P384; value.RawValue = new byte[96]; value.RawValue[0] = 4; Array.Copy(key, 0, value.RawValue, 1, 96); } else { throw new ArgumentOutOfRangeException("Invalid public key."); } return(value); }
/// <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()); }
/// <summary> /// Constructor. /// </summary> /// <param name="key">Public key.</param> public GXEcdsa(GXPublicKey key) : this(key.Scheme) { PublicKey = key; }