Example #1
0
        // TODO add exceptions for operations with missing keys

        public Curve25519KeyPair()
        {
            byte[] privateKey;
            byte[] edPublicKey;
            byte[] xPrivateKey;
            byte[] xPublicKey;

            // Generates keys until the conversion algorithm works for that key (there is probably a <1/100000 chance of this, but hey)
            while (true)
            {
                privateKey = new byte[Ed25519PrivateKeyParameters.KeySize];
                Ed25519.GeneratePrivateKey(new SecureRandom(), privateKey);

                edPublicKey = new byte[Ed25519PublicKeyParameters.KeySize];
                Ed25519.GeneratePublicKey(privateKey, 0, edPublicKey, 0);

                xPrivateKey = ConvertEdPrivateKeyToMontgomery(privateKey);

                xPublicKey = new byte[X25519PublicKeyParameters.KeySize];
                X25519.GeneratePublicKey(xPrivateKey, 0, xPublicKey, 0);

                if (xPublicKey.SequenceEqual(ConvertEdPublicKeyToMontgomery(edPublicKey)))
                {
                    break;
                }
            }

            _edPrivateKey = privateKey;
            _XprivateKey  = xPrivateKey;

            _edPublicKey = edPublicKey;
            _XpublicKey  = xPublicKey;
        }
Example #2
0
        private static void CheckIterated(int count)
        {
            byte[] k = new byte[32]; k[0] = 9;
            byte[] u = new byte[32]; u[0] = 9;
            byte[] r = new byte[32];

            int iterations = 0;

            while (iterations < count)
            {
                X25519.ScalarMult(k, 0, u, 0, r, 0);

                Array.Copy(k, 0, u, 0, 32);
                Array.Copy(r, 0, k, 0, 32);

                switch (++iterations)
                {
                case 1:
                    CheckValue(k, "Iterated @1", "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079");
                    break;

                case 1000:
                    CheckValue(k, "Iterated @1000", "684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51");
                    break;

                case 1000000:
                    CheckValue(k, "Iterated @1000000", "7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424");
                    break;

                default:
                    break;
                }
            }
        }
Example #3
0
        public void TestECDH()
        {
            byte[] kA = new byte[32];
            byte[] kB = new byte[32];
            byte[] qA = new byte[32];
            byte[] qB = new byte[32];
            byte[] sA = new byte[32];
            byte[] sB = new byte[32];

            for (int i = 1; i <= 100; ++i)
            {
                // Each party generates an ephemeral private key, ...
                Random.NextBytes(kA);
                Random.NextBytes(kB);

                // ... publishes their public key, ...
                X25519.ScalarMultBase(kA, 0, qA, 0);
                X25519.ScalarMultBase(kB, 0, qB, 0);

                // ... computes the shared secret, ...
                X25519.ScalarMult(kA, 0, qB, 0, sA, 0);
                X25519.ScalarMult(kB, 0, qA, 0, sB, 0);

                // ... which is the same for both parties.
                //Assert.IsTrue(Arrays.AreEqual(sA, sB), "ECDH #" + i);
                if (!Arrays.AreEqual(sA, sB))
                {
                    Console.WriteLine(" " + i);
                }
            }
        }
        /// <inheritdoc />
        public void EncodeServerKeyExchangeMessage(ByteSpan output, object privateKey)
        {
            RSA rsaPrivateKey = privateKey as RSA;

            if (rsaPrivateKey == null)
            {
                throw new ArgumentException("Invalid private key", nameof(privateKey));
            }

            output[0] = (byte)ECCurveType.NamedCurve;
            output.WriteBigEndian16((ushort)NamedCurve.x25519, 1);
            output[3] = (byte)X25519.KeySize;
            X25519.Func(output.Slice(4, X25519.KeySize), this.privateAgreementKey);

            // Hash the key parameters
            byte[] paramterDigest = this.sha256.ComputeHash(output.GetUnderlyingArray(), output.Offset, 4 + X25519.KeySize);

            // Sign the paramter digest
            RSAPKCS1SignatureFormatter signer = new RSAPKCS1SignatureFormatter(rsaPrivateKey);

            signer.SetHashAlgorithm("SHA256");
            ByteSpan signature = signer.CreateSignature(paramterDigest);

            Debug.Assert(signature.Length == rsaPrivateKey.KeySize / 8);
            output[4 + X25519.KeySize] = (byte)HashAlgorithm.Sha256;
            output[5 + X25519.KeySize] = (byte)SignatureAlgorithm.RSA;
            output.Slice(6 + X25519.KeySize).WriteBigEndian16((ushort)signature.Length);
            signature.CopyTo(output.Slice(8 + X25519.KeySize));
        }
Example #5
0
        public void TestAgreement()
        {
            using (RandomNumberGenerator random = RandomNumberGenerator.Create())
            {
                byte[] clientPrivateKey = new byte[X25519.KeySize];
                random.GetBytes(clientPrivateKey);

                byte[] clientPublicKey = new byte[X25519.KeySize];
                X25519.Func(clientPublicKey, clientPrivateKey);

                byte[] serverPrivateKey = new byte[X25519.KeySize];
                random.GetBytes(serverPrivateKey);

                byte[] serverPublickey = new byte[X25519.KeySize];
                X25519.Func(serverPublickey, serverPrivateKey);

                // client key aggreement
                byte[] clientSharedSecret = new byte[X25519.KeySize];
                Assert.IsTrue(X25519.Func(clientSharedSecret, clientPrivateKey, serverPublickey));

                // server key agreement
                byte[] serverSharedSecret = new byte[X25519.KeySize];
                Assert.IsTrue(X25519.Func(serverSharedSecret, serverPrivateKey, clientPublicKey));

                CollectionAssert.AreEqual(clientSharedSecret, serverSharedSecret);
            }
        }
Example #6
0
        public static void Properties()
        {
            var a = new X25519();

            Assert.Equal(32, a.PublicKeySize);
            Assert.Equal(32, a.PrivateKeySize);
            Assert.Equal(32, a.SharedSecretSize);
        }
Example #7
0
 private static void CheckX25519Vector(string sk, string su, string se, string text)
 {
     byte[] k = Hex.Decode(sk);
     byte[] u = Hex.Decode(su);
     byte[] r = new byte[32];
     X25519.ScalarMult(k, 0, u, 0, r, 0);
     CheckValue(r, text, se);
 }
Example #8
0
        public byte[] CalculateSharedSecret(byte[] otherPublicKey)
        {
            var output = new byte[32];

            X25519.CalculateAgreement(_XprivateKey, 0, otherPublicKey, 0, output, 0);

            return(output);
        }
 public void GenerateSecret(X25519PublicKeyParameters publicKey, byte[] buf, int off)
 {
     byte[] encoded = new byte[X25519.PointSize];
     publicKey.Encode(encoded, 0);
     if (!X25519.CalculateAgreement(data, 0, encoded, 0, buf, off))
     {
         throw new InvalidOperationException("X25519 agreement failed");
     }
 }
Example #10
0
 public void TestVectors()
 {
     for (int ii = 0, nn = TestVectorData.Length; ii != nn; ++ii)
     {
         byte[] actual = new byte[32];
         bool   result = X25519.Func(actual, TestVectorData[ii].In, TestVectorData[ii].Base);
         Assert.IsTrue(result);
         CollectionAssert.AreEqual(TestVectorData[ii].Expect, actual, $"Test vector {ii} mismatch");
     }
 }
Example #11
0
        public static void DeriveBytesWithMaxSpan(Type algorithmType)
        {
            var a = (KeyDerivationAlgorithm)Activator.CreateInstance(algorithmType);
            var x = new X25519();

            using (var k = new Key(x))
                using (var s = x.Agree(k, k.PublicKey))
                {
                    a.DeriveBytes(s, ReadOnlySpan <byte> .Empty, ReadOnlySpan <byte> .Empty, new byte[a.MaxOutputSize]);
                }
        }
Example #12
0
        public static void DeriveKeyWithNullAlgorithm(Type algorithmType)
        {
            var a = (KeyDerivationAlgorithm)Activator.CreateInstance(algorithmType);
            var x = new X25519();

            using (var k = new Key(x))
                using (var s = x.Agree(k, k.PublicKey))
                {
                    Assert.Throws <ArgumentNullException>("algorithm", () => a.DeriveKey(s, ReadOnlySpan <byte> .Empty, ReadOnlySpan <byte> .Empty, null));
                }
        }
Example #13
0
        public static void DeriveBytesWithNegativeCount(Type algorithmType)
        {
            var a = (KeyDerivationAlgorithm)Activator.CreateInstance(algorithmType);
            var x = new X25519();

            using (var k = new Key(x))
                using (var s = x.Agree(k, k.PublicKey))
                {
                    Assert.Throws <ArgumentOutOfRangeException>("count", () => a.DeriveBytes(s, ReadOnlySpan <byte> .Empty, ReadOnlySpan <byte> .Empty, -1));
                }
        }
Example #14
0
        private static void CheckX25519Vector(string sk, string su, string se, string text)
        {
            byte[] k = Hex.Decode(sk);
            Assert.AreEqual(X25519.ScalarSize, k.Length);

            byte[] u = Hex.Decode(su);
            Assert.AreEqual(X25519.PointSize, u.Length);

            byte[] r = new byte[X25519.PointSize];
            X25519.ScalarMult(k, 0, u, 0, r, 0);
            CheckValue(r, text, se);
        }
Example #15
0
        public static void DeriveBytesWithZeroCount(Type algorithmType)
        {
            var a = (KeyDerivationAlgorithm)Activator.CreateInstance(algorithmType);
            var x = new X25519();

            using (var k = new Key(x))
                using (var s = x.Agree(k, k.PublicKey))
                {
                    var b = a.DeriveBytes(s, ReadOnlySpan <byte> .Empty, ReadOnlySpan <byte> .Empty, 0);

                    Assert.NotNull(b);
                    Assert.Equal(0, b.Length);
                }
        }
Example #16
0
        public static void DeriveBytesWithInfoOverlapping(Type algorithmType)
        {
            var a = (KeyDerivationAlgorithm)Activator.CreateInstance(algorithmType);
            var x = new X25519();

            using (var k = new Key(x))
                using (var s = x.Agree(k, k.PublicKey))
                {
                    var b = new byte[200];

                    Assert.Throws <ArgumentException>("bytes", () => a.DeriveBytes(s, ReadOnlySpan <byte> .Empty, b.AsSpan().Slice(10, 100), b.AsSpan().Slice(60, 100)));
                    Assert.Throws <ArgumentException>("bytes", () => a.DeriveBytes(s, ReadOnlySpan <byte> .Empty, b.AsSpan().Slice(60, 100), b.AsSpan().Slice(10, 100)));
                }
        }
Example #17
0
        public static void DeriveBytesWithCountTooLarge(Type algorithmType)
        {
            var a = (KeyDerivationAlgorithm)Activator.CreateInstance(algorithmType);
            var x = new X25519();

            if (a.MaxOutputSize < int.MaxValue)
            {
                using (var k = new Key(x))
                    using (var s = x.Agree(k, k.PublicKey))
                    {
                        Assert.Throws <ArgumentOutOfRangeException>("count", () => a.DeriveBytes(s, ReadOnlySpan <byte> .Empty, ReadOnlySpan <byte> .Empty, a.MaxOutputSize + 1));
                    }
            }
        }
Example #18
0
        public static void TestAllZeros(string privateKey, string publicKey)
        {
            var a = new X25519();

            var pk = PublicKey.Import(a, publicKey.DecodeHex(), KeyBlobFormat.RawPublicKey);

            using (var k = Key.Import(a, privateKey.DecodeHex(), KeyBlobFormat.RawPrivateKey))
            {
                Assert.False(a.TryAgree(k, pk, out SharedSecret s));
                Assert.Null(s);

                Assert.Throws <CryptographicException>(() => a.Agree(k, pk));
            }
        }
Example #19
0
        public static void DeriveBytesWithUnusedSalt(Type algorithmType)
        {
            var a = (KeyDerivationAlgorithm)Activator.CreateInstance(algorithmType);

            if (!a.SupportsSalt)
            {
                var x = new X25519();

                using (var k = new Key(x))
                    using (var s = x.Agree(k, k.PublicKey))
                    {
                        Assert.Throws <ArgumentException>("salt", () => a.DeriveBytes(s, new byte[1], ReadOnlySpan <byte> .Empty, 0));
                    }
            }
        }
Example #20
0
        public void TestLowOrderPoints()
        {
            using (RandomNumberGenerator random = RandomNumberGenerator.Create())
            {
                byte[] scalar = new byte[X25519.KeySize];
                random.GetBytes(scalar);

                for (int ii = 0, nn = LowOrderPoints.Length; ii != nn; ++ii)
                {
                    ByteSpan output = new byte[X25519.KeySize];
                    bool     result = X25519.Func(output, scalar, LowOrderPoints[ii]);
                    Assert.IsFalse(result, $"Multiplication by low order point {ii} succeeded: should have failed");
                }
            }
        }
Example #21
0
        public static void Test(string privateKey, string publicKey, string sharedSecret)
        {
            var a   = new X25519();
            var kdf = new HkdfSha256();

            using (var k = Key.Import(a, privateKey.DecodeHex(), KeyBlobFormat.RawPrivateKey))
                using (var sharedSecretExpected = SharedSecret.Import(sharedSecret.DecodeHex()))
                    using (var sharedSecretActual = a.Agree(k, PublicKey.Import(a, publicKey.DecodeHex(), KeyBlobFormat.RawPublicKey)))
                    {
                        var expected = kdf.Extract(sharedSecretExpected, ReadOnlySpan <byte> .Empty);
                        var actual   = kdf.Extract(sharedSecretActual, ReadOnlySpan <byte> .Empty);

                        Assert.Equal(expected, actual);
                    }
        }
Example #22
0
        public void TestConsistency()
        {
            byte[] u  = new byte[32];    u[0] = 9;
            byte[] k  = new byte[32];
            byte[] rF = new byte[32];
            byte[] rV = new byte[32];

            for (int i = 1; i <= 100; ++i)
            {
                Random.NextBytes(k);
                X25519.ScalarMultBase(k, 0, rF, 0);
                X25519.ScalarMult(k, 0, u, 0, rV, 0);
                Assert.IsTrue(Arrays.AreEqual(rF, rV), "Consistency #" + i);
            }
        }
Example #23
0
        public static void BitMaskedEquals(string privateKey, string publicKey, string sharedSecret)
        {
            var a = new X25519();

            var pk1 = publicKey.DecodeHex();
            var pk2 = publicKey.DecodeHex();

            pk1[pk1.Length - 1] &= 0x7F;
            pk2[pk2.Length - 1] |= 0x80;

            var p1 = PublicKey.Import(a, pk1, KeyBlobFormat.RawPublicKey);
            var p2 = PublicKey.Import(a, pk2, KeyBlobFormat.RawPublicKey);

            Assert.True(p1.Equals(p2));
        }
        /// <inheritdoc />
        public bool VerifyClientMessageAndGenerateSharedKey(ByteSpan output, ByteSpan clientKeyExchangeMessage)
        {
            if (clientKeyExchangeMessage.Length != ClientMessageSize)
            {
                return(false);
            }
            else if (clientKeyExchangeMessage[0] != (byte)X25519.KeySize)
            {
                return(false);
            }

            ByteSpan othersPublicKey = clientKeyExchangeMessage.Slice(1);

            return(X25519.Func(output, this.privateAgreementKey, othersPublicKey));
        }
        public static void DeriveBytesWithSpanTooLarge(Type algorithmType)
        {
            var a = (KeyDerivationAlgorithm)Activator.CreateInstance(algorithmType);
            var x = new X25519();

            if (a.MaxOutputSize == int.MaxValue)
            {
                return;
            }

            using (var k = new Key(x))
                using (var s = x.Agree(k, k.PublicKey))
                {
                    Assert.Throws <ArgumentException>("bytes", () => a.DeriveBytes(s, ReadOnlySpan <byte> .Empty, ReadOnlySpan <byte> .Empty, new byte[a.MaxOutputSize + 1]));
                }
        }
Example #26
0
        public static void ExpandWithInfoOverlapping()
        {
            var a = new HkdfSha256();
            var x = new X25519();

            using (var k = new Key(x))
                using (var s = x.Agree(k, k.PublicKey))
                {
                    var b = new byte[200];

                    var prk = a.Extract(s, ReadOnlySpan <byte> .Empty);

                    Assert.Throws <ArgumentException>("bytes", () => a.Expand(prk, b.AsSpan().Slice(10, 100), b.AsSpan().Slice(60, 100)));
                    Assert.Throws <ArgumentException>("bytes", () => a.Expand(prk, b.AsSpan().Slice(60, 100), b.AsSpan().Slice(10, 100)));
                }
        }
        public static void DeriveBytesWithMaxCount(Type algorithmType)
        {
            var a = (KeyDerivationAlgorithm)Activator.CreateInstance(algorithmType);
            var x = new X25519();

            using (var k = new Key(x))
                using (var s = x.Agree(k, k.PublicKey))
                {
                    var count = Math.Min(a.MaxOutputSize, 500173);

                    var b = a.DeriveBytes(s, ReadOnlySpan <byte> .Empty, ReadOnlySpan <byte> .Empty, count);

                    Assert.NotNull(b);
                    Assert.Equal(count, b.Length);
                }
        }
Example #28
0
        public static void PkixPublicKeyText()
        {
            var a = new X25519();
            var b = Utilities.RandomBytes.Slice(0, a.PrivateKeySize);

            using (var k = Key.Import(a, b, KeyBlobFormat.RawPrivateKey))
            {
                var expected = Encoding.UTF8.GetBytes(
                    "-----BEGIN PUBLIC KEY-----\r\n" +
                    Convert.ToBase64String(k.Export(KeyBlobFormat.PkixPublicKey)) + "\r\n" +
                    "-----END PUBLIC KEY-----\r\n");

                var actual = k.Export(KeyBlobFormat.PkixPublicKeyText);

                Assert.Equal(expected, actual);
            }
        }
Example #29
0
        public static void DeriveBytesWithSaltOverlapping(Type algorithmType)
        {
            var a = (KeyDerivationAlgorithm)Activator.CreateInstance(algorithmType);
            var x = new X25519();

            using (var k = new Key(x))
                using (var s = x.Agree(k, k.PublicKey))
                {
                    var actual   = new byte[100];
                    var expected = new byte[100];
                    Utilities.RandomBytes.Slice(0, 100).CopyTo(actual);

                    a.DeriveBytes(s, actual, ReadOnlySpan <byte> .Empty, expected);
                    a.DeriveBytes(s, actual, ReadOnlySpan <byte> .Empty, actual);

                    Assert.Equal(expected, actual);
                }
        }
Example #30
0
        public static void PkixPublicKey()
        {
            var a = new X25519();
            var b = Utilities.RandomBytes.Slice(0, a.PrivateKeySize);

            using (var k = Key.Import(a, b, KeyBlobFormat.RawPrivateKey))
            {
                var publicKeyBytes = k.Export(KeyBlobFormat.RawPublicKey);
                var blob           = k.Export(KeyBlobFormat.PkixPublicKey);

                var reader = new Asn1Reader(blob);
                reader.BeginSequence();
                reader.BeginSequence();
                Assert.Equal(s_oid, reader.ObjectIdentifier().ToArray());
                reader.End();
                Assert.Equal(publicKeyBytes, reader.BitString().ToArray());
                reader.End();
                Assert.True(reader.SuccessComplete);
            }
        }