Example #1
0
        public static void DeriveKeyWithDisposedSecret(KeyDerivationAlgorithm a)
        {
            var s = SharedSecret.Import(Utilities.RandomBytes.Slice(0, 32));

            s.Dispose();
            Assert.Throws <ObjectDisposedException>(() => a.DeriveKey(s, ReadOnlySpan <byte> .Empty, ReadOnlySpan <byte> .Empty, AeadAlgorithm.ChaCha20Poly1305));
        }
        public static void DeriveBytesWithDisposedSecretAndSpan(KeyDerivationAlgorithm a)
        {
            var s = SharedSecret.Import(Utilities.RandomBytes.Slice(0, 32));

            s.Dispose();
            Assert.Throws <ObjectDisposedException>(() => a.DeriveBytes(s, ReadOnlySpan <byte> .Empty, ReadOnlySpan <byte> .Empty, Span <byte> .Empty));
        }
Example #3
0
        public void TestHkdkf()
        {
            var hkdkf  = new HkdfSha512();
            var result = hkdkf.DeriveBytes(SharedSecret.Import(HkdfIkm), HkdfSalt, HkdfInfo, 42);

            Assert.Equal(HkdfOkm, result);
        }
Example #4
0
        public static void ExtractWithSpanTooLong()
        {
            var a = KeyDerivationAlgorithm.HkdfSha256;

            using var s = SharedSecret.Import(ReadOnlySpan <byte> .Empty);

            Assert.Throws <ArgumentException>("pseudorandomKey", () => a.Extract(s, ReadOnlySpan <byte> .Empty, new byte[a.PseudorandomKeySize + 1]));
        }
Example #5
0
 public static void ImportEmpty()
 {
     using (var s = SharedSecret.Import(ReadOnlySpan <byte> .Empty))
     {
         Assert.NotNull(s);
         Assert.Equal(0, s.Size);
     }
 }
Example #6
0
        public static void ImportZeros()
        {
            var b = new byte[64];

            using var s = SharedSecret.Import(b);
            Assert.NotNull(s);
            Assert.Equal(b.Length, s.Size);
        }
Example #7
0
        public static void ImportNonEmpty()
        {
            var b = Utilities.RandomBytes.Slice(0, 57);

            using var s = SharedSecret.Import(b);
            Assert.NotNull(s);
            Assert.Equal(b.Length, s.Size);
        }
Example #8
0
        public static void PropertiesAfterDispose()
        {
            var b = new byte[64];
            var s = SharedSecret.Import(b);

            s.Dispose();
            Assert.NotNull(s);
            Assert.Equal(b.Length, s.Size);
        }
Example #9
0
        public static void ExtractWithSpanTooLong()
        {
            var a = new HkdfSha512();

            using (var s = SharedSecret.Import(ReadOnlySpan <byte> .Empty))
            {
                Assert.Throws <ArgumentException>("pseudorandomKey", () => a.Extract(s, ReadOnlySpan <byte> .Empty, new byte[a.PseudorandomKeySize + 1]));
            }
        }
        public static void DeriveBytesWithDisposedSecret(Type algorithmType)
        {
            var a = (KeyDerivationAlgorithm)Activator.CreateInstance(algorithmType);

            var s = SharedSecret.Import(Utilities.RandomBytes.Slice(0, 32));

            s.Dispose();
            Assert.Throws <ObjectDisposedException>(() => a.DeriveBytes(s, ReadOnlySpan <byte> .Empty, ReadOnlySpan <byte> .Empty, 0));
        }
Example #11
0
        public static void DisposeMoreThanOnce()
        {
            var b = new byte[64];
            var s = SharedSecret.Import(b);

            Assert.NotNull(s);
            s.Dispose();
            s.Dispose();
            s.Dispose();
        }
Example #12
0
        public static void ImportNonEmpty()
        {
            var b = "00010203040506070809".DecodeHex();

            using (var s = SharedSecret.Import(b))
            {
                Assert.NotNull(s);
                Assert.Equal(b.Length, s.Size);
            }
        }
Example #13
0
        public static void TestOneStep(string ikm, string salt, string info, string expectedPrk, string expectedOkm)
        {
            var a = new HkdfSha256();

            using (var s = SharedSecret.Import(ikm.DecodeHex()))
            {
                var actualOkm = a.DeriveBytes(s, salt.DecodeHex(), info.DecodeHex(), expectedOkm.DecodeHex().Length);
                Assert.Equal(expectedOkm.DecodeHex(), actualOkm);
            }
        }
Example #14
0
        public static void ExtractSuccess()
        {
            var a = KeyDerivationAlgorithm.HkdfSha256;

            using var s = SharedSecret.Import(ReadOnlySpan <byte> .Empty);

            var expected = s_prkForEmpty.DecodeHex();
            var actual   = a.Extract(s, ReadOnlySpan <byte> .Empty);

            Assert.Equal(expected, actual);
            Assert.Equal(a.PseudorandomKeySize, actual.Length);
        }
Example #15
0
        public static void TestTwoStep(string ikm, string salt, string info, string expectedPrk, string expectedOkm)
        {
            var a = new HkdfSha256();

            using (var s = SharedSecret.Import(ikm.DecodeHex()))
            {
                var actualPrk = a.Extract(s, salt.DecodeHex());
                Assert.Equal(expectedPrk.DecodeHex(), actualPrk);

                var actualOkm = a.Expand(actualPrk, info.DecodeHex(), expectedOkm.DecodeHex().Length);
                Assert.Equal(expectedOkm.DecodeHex(), actualOkm);
            }
        }
Example #16
0
        public static void ExtractWithSpanSuccess()
        {
            var a = KeyDerivationAlgorithm.HkdfSha256;

            using var s = SharedSecret.Import(ReadOnlySpan <byte> .Empty);

            var expected = s_prkForEmpty.DecodeHex();
            var actual   = new byte[expected.Length];

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

            Assert.Equal(expected, actual);
        }
Example #17
0
        public static void ExtractWithEmptySalt()
        {
            const int HashLen = 256 / 8;

            var a = KeyDerivationAlgorithm.HkdfSha256;

            using var s = SharedSecret.Import(ReadOnlySpan <byte> .Empty);

            var expected = a.Extract(s, new byte[HashLen]);
            var actual   = a.Extract(s, ReadOnlySpan <byte> .Empty);

            Assert.Equal(expected, actual);
        }
Example #18
0
        public static void ExtractWithEmptySalt()
        {
            const int HashLen = 512 / 8;

            var a = new HkdfSha512();

            using (var s = SharedSecret.Import(ReadOnlySpan <byte> .Empty))
            {
                var expected = a.Extract(s, new byte[HashLen]);
                var actual   = a.Extract(s, ReadOnlySpan <byte> .Empty);

                Assert.Equal(expected, actual);
            }
        }
Example #19
0
        public static void Test(string privateKey, string publicKey, string sharedSecret)
        {
            var a   = KeyAgreementAlgorithm.X25519;
            var kdf = KeyDerivationAlgorithm.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)) ?? throw new Xunit.Sdk.NotNullException();

            var expected = kdf.Extract(sharedSecretExpected, ReadOnlySpan <byte> .Empty);
            var actual   = kdf.Extract(sharedSecretActual, ReadOnlySpan <byte> .Empty);

            Assert.Equal(expected, actual);
        }
Example #20
0
        public static void ExtractWithSpanWithSaltOverlapping()
        {
            var a = KeyDerivationAlgorithm.HkdfSha256;

            using var s = SharedSecret.Import(ReadOnlySpan <byte> .Empty);

            var expected = new byte[a.PseudorandomKeySize];
            var actual   = Utilities.RandomBytes.Slice(0, a.PseudorandomKeySize).ToArray();

            a.Extract(s, actual, expected);
            a.Extract(s, actual, actual);

            Assert.Equal(expected, actual);
        }
Example #21
0
        public static void ExtractWithSpanSuccess()
        {
            var a = new HkdfSha512();

            using (var s = SharedSecret.Import(ReadOnlySpan <byte> .Empty))
            {
                var expected = s_prkForEmpty.DecodeHex();
                var actual   = new byte[expected.Length];

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

                Assert.Equal(expected, actual);
            }
        }
Example #22
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 #23
0
        public static void ExtractWithSpanWithEmptySalt()
        {
            const int HashLen = 256 / 8;

            var a = KeyDerivationAlgorithm.HkdfSha256;

            using var s = SharedSecret.Import(ReadOnlySpan <byte> .Empty);

            var expected = new byte[a.PseudorandomKeySize];
            var actual   = new byte[expected.Length];

            a.Extract(s, new byte[HashLen], expected);
            a.Extract(s, ReadOnlySpan <byte> .Empty, actual);

            Assert.Equal(expected, actual);
        }
Example #24
0
        public static void ExtractWithSpanWithEmptySalt()
        {
            const int HashLen = 512 / 8;

            var a = new HkdfSha512();

            using (var s = SharedSecret.Import(ReadOnlySpan <byte> .Empty))
            {
                var expected = new byte[a.PseudorandomKeySize];
                var actual   = new byte[expected.Length];

                a.Extract(s, new byte[HashLen], expected);
                a.Extract(s, ReadOnlySpan <byte> .Empty, actual);

                Assert.Equal(expected, actual);
            }
        }
Example #25
0
        public static void BitMaskedAgree(string privateKey, string publicKey, string sharedSecret)
        {
            var a   = KeyAgreementAlgorithm.X25519;
            var kdf = KeyDerivationAlgorithm.HkdfSha256;

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

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

            using var k = Key.Import(a, privateKey.DecodeHex(), KeyBlobFormat.RawPrivateKey);
            using var sharedSecretExpected = SharedSecret.Import(sharedSecret.DecodeHex());
            using var sharedSecretActual1  = a.Agree(k, PublicKey.Import(a, pk1, KeyBlobFormat.RawPublicKey)) ?? throw new Xunit.Sdk.NotNullException();
            using var sharedSecretActual2  = a.Agree(k, PublicKey.Import(a, pk2, KeyBlobFormat.RawPublicKey)) ?? throw new Xunit.Sdk.NotNullException();

            var expected = kdf.Extract(sharedSecretExpected, ReadOnlySpan <byte> .Empty);
            var actual1  = kdf.Extract(sharedSecretActual1, ReadOnlySpan <byte> .Empty);
            var actual2  = kdf.Extract(sharedSecretActual2, ReadOnlySpan <byte> .Empty);

            Assert.Equal(expected, actual1);
            Assert.Equal(expected, actual2);
        }
Example #26
0
        public static void BitMaskedAgree(string privateKey, string publicKey, string sharedSecret)
        {
            var a   = new X25519();
            var kdf = new HkdfSha256();

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

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

            using (var k = Key.Import(a, privateKey.DecodeHex(), KeyBlobFormat.RawPrivateKey))
                using (var sharedSecretExpected = SharedSecret.Import(sharedSecret.DecodeHex()))
                    using (var sharedSecretActual1 = a.Agree(k, PublicKey.Import(a, pk1, KeyBlobFormat.RawPublicKey)))
                        using (var sharedSecretActual2 = a.Agree(k, PublicKey.Import(a, pk2, KeyBlobFormat.RawPublicKey)))
                        {
                            var expected = kdf.Extract(sharedSecretExpected, ReadOnlySpan <byte> .Empty);
                            var actual1  = kdf.Extract(sharedSecretActual1, ReadOnlySpan <byte> .Empty);
                            var actual2  = kdf.Extract(sharedSecretActual2, ReadOnlySpan <byte> .Empty);

                            Assert.Equal(expected, actual1);
                            Assert.Equal(expected, actual2);
                        }
        }
        internal Tlv HandlePairSetupM5Raw(ConnectionSession session, out KeyPair keyPair)
        {
            var hdkf      = new HkdfSha512();
            var accessory = hdkf.DeriveBytes(
                SharedSecret.Import(SrpInteger.FromHex(session.ServerSession.Key).ToByteArray()),
                Encoding.UTF8.GetBytes("Pair-Setup-Accessory-Sign-Salt"),
                Encoding.UTF8.GetBytes("Pair-Setup-Accessory-Sign-Info"), 32);

            keyPair = KeyGenerator.GenerateNewPair();

            var serverUsername = Encoding.UTF8.GetBytes(HapControllerServer.HapControllerId);
            var material       = accessory.Concat(serverUsername).Concat(keyPair.PublicKey).ToArray();

            var signature = Chaos.NaCl.Ed25519.Sign(material, keyPair.PrivateKey);


            var encoder = new Tlv();

            encoder.AddType(Constants.Identifier, serverUsername);
            encoder.AddType(Constants.PublicKey, keyPair.PublicKey);
            encoder.AddType(Constants.Signature, signature);

            return(encoder);
        }
        public byte[] decrypt(byte[] data)
        {
            SharedSecret secret = SharedSecret.Import(motherKey);

            byte[] seconds = new byte[4];
            Array.Copy(data, 0, seconds, 0, 4);
            Console.WriteLine("Seconds size: " + seconds.Length);
            Console.WriteLine("Seconds: " + BitConverter.ToInt32(seconds));

            byte[] IV = new byte[12];
            Array.Copy(data, 4, IV, 0, 12);
            Console.WriteLine("IV size: " + IV.Length);
            Console.WriteLine("IV: " + BitConverter.ToString(IV));

            byte[] ciphertext = new byte[data.Length - 16];
            Array.Copy(data, 16, ciphertext, 0, ciphertext.Length);
            Console.WriteLine("Ciphertext size: " + ciphertext.Length);
            Console.WriteLine("Ciphertext: " + BitConverter.ToString(ciphertext));

            Key keyCipher = KeyDerivationAlgorithm.HkdfSha256.DeriveKey(secret, seconds, null, ChaCha20Poly1305.ChaCha20Poly1305);

            byte[] plaintext = new byte[ciphertext.Length - ChaCha20Poly1305.ChaCha20Poly1305.TagSize];

            bool decrypt = ChaCha20Poly1305.ChaCha20Poly1305.Decrypt(keyCipher, new Nonce(IV, 0), null, ciphertext, plaintext);

            if (decrypt)
            {
                Console.WriteLine("Decryption successful, plaintext: " + BitConverter.ToString(plaintext));
                return(plaintext);
            }
            else
            {
                Console.WriteLine("Decryption unsuccessful");
                return(null);
            }
        }
        public PairSetupReturn Post(Tlv parts)
        {
            var customParams = SrpParameters.Create3072 <SHA512>();

            var state = parts.GetTypeAsInt(Constants.State);

            if (state == 1) //srp sign up
            {
                var rnd = new Random();
                _salt = new byte[16];
                rnd.NextBytes(_salt);

                _saltInt = SrpInteger.FromByteArray(_salt);

                var srp = new SrpClient(customParams);
                _privateKey = srp.DerivePrivateKey(_saltInt.ToHex(), Username, _code);
                _verifier   = srp.DeriveVerifier(_privateKey);

                _server          = new SrpServer(customParams);
                _serverEphemeral = _server.GenerateEphemeral(_verifier);

                var responseTlv = new Tlv();
                responseTlv.AddType(Constants.State, 2);
                responseTlv.AddType(Constants.PublicKey, StringToByteArray(_serverEphemeral.Public));
                responseTlv.AddType(Constants.Salt, _salt);

                return(new PairSetupReturn
                {
                    State = 1,
                    TlvData = responseTlv,
                    Ok = true
                });
            }

            if (state == 3) //srp authenticate
            {
                _logger.LogDebug("Pair Setup Step 3/6");
                _logger.LogDebug("SRP Verify Request");

                var pubKey = parts.GetType(Constants.PublicKey);
                var proof  = parts.GetType(Constants.Proof);

                var iOsPublicKey = SrpInteger.FromByteArray(pubKey);
                var iOsProof     = SrpInteger.FromByteArray(proof);


                var responseTlv = new Tlv();
                responseTlv.AddType(Constants.State, 4);
                var ok = true;
                try
                {
                    _serverSession = _server.DeriveSession(_serverEphemeral.Secret, iOsPublicKey.ToHex(), _saltInt.ToHex(), Username, _verifier,
                                                           iOsProof.ToHex());
                    _logger.LogInformation("Verification was successful. Generating Server Proof (M2)");

                    responseTlv.AddType(Constants.Proof, StringToByteArray(_serverSession.Proof));
                }
                catch (Exception)
                {
                    ok = false;
                    _logger.LogError("Verification failed as iOS provided code was incorrect");
                    responseTlv.AddType(Constants.Error, ErrorCodes.Authentication);
                }
                return(new PairSetupReturn
                {
                    State = 3,
                    Ok = ok,
                    TlvData = responseTlv
                });
            }

            if (state == 5)
            {
                _logger.LogDebug("Pair Setup Step 5/6");
                _logger.LogDebug("Exchange Response");

                try
                {
                    var iOsEncryptedData = parts.GetType(Constants.EncryptedData).AsSpan(); // A
                    var zeros            = new byte[] { 0, 0, 0, 0 };
                    var nonce            = new Nonce(zeros, Encoding.UTF8.GetBytes("PS-Msg05"));
                    var hdkf             = new HkdfSha512();
                    var hkdfEncKey       = hdkf.DeriveBytes(
                        SharedSecret.Import(SrpInteger.FromHex(_serverSession.Key).ToByteArray()),
                        Encoding.UTF8.GetBytes("Pair-Setup-Encrypt-Salt"),
                        Encoding.UTF8.GetBytes("Pair-Setup-Encrypt-Info"), 32);


                    var decrypt = AeadAlgorithm.ChaCha20Poly1305.Decrypt(
                        Key.Import(AeadAlgorithm.ChaCha20Poly1305, hkdfEncKey, KeyBlobFormat.RawSymmetricKey), nonce,
                        new byte[0], iOsEncryptedData, out var output);
                    var responseTlv = new Tlv();
                    responseTlv.AddType(Constants.State, 6);
                    if (!decrypt)
                    {
                        responseTlv.AddType(Constants.Error, ErrorCodes.Authentication);
                        return(new PairSetupReturn
                        {
                            State = 5,
                            TlvData = responseTlv,
                            Ok = false
                        });
                    }

                    var subData = TlvParser.Parse(output);

                    byte[] username = subData.GetType(Constants.Identifier);
                    byte[] ltpk     = subData.GetType(Constants.PublicKey);
                    byte[] proof    = subData.GetType(Constants.Signature);


                    var okm = hdkf.DeriveBytes(
                        SharedSecret.Import(SrpInteger.FromHex(_serverSession.Key).ToByteArray()),
                        Encoding.UTF8.GetBytes("Pair-Setup-Controller-Sign-Salt"),
                        Encoding.UTF8.GetBytes("Pair-Setup-Controller-Sign-Info"), 32);

                    var completeData = okm.Concat(username).Concat(ltpk).ToArray();


                    if (!SignatureAlgorithm.Ed25519.Verify(
                            PublicKey.Import(SignatureAlgorithm.Ed25519, ltpk, KeyBlobFormat.RawPublicKey), completeData,
                            proof))
                    {
                        var errorTlv = new Tlv();
                        errorTlv.AddType(Constants.Error, ErrorCodes.Authentication);
                        return(new PairSetupReturn
                        {
                            State = 5,
                            TlvData = errorTlv,
                            Ok = false
                        });
                    }

                    var accessory = hdkf.DeriveBytes(
                        SharedSecret.Import(SrpInteger.FromHex(_serverSession.Key).ToByteArray()),
                        Encoding.UTF8.GetBytes("Pair-Setup-Accessory-Sign-Salt"),
                        Encoding.UTF8.GetBytes("Pair-Setup-Accessory-Sign-Info"), 32);


                    var seed = new byte[32];
                    RandomNumberGenerator.Create().GetBytes(seed);
                    Chaos.NaCl.Ed25519.KeyPairFromSeed(out var accessoryLtpk, out var accessoryLtsk, seed);

                    var serverUsername = Encoding.UTF8.GetBytes(HapControllerServer.HapControllerId);
                    var material       = accessory.Concat(serverUsername).Concat(accessoryLtpk).ToArray();

                    var signature = Chaos.NaCl.Ed25519.Sign(material, accessoryLtsk);


                    var encoder = new Tlv();
                    encoder.AddType(Constants.Identifier, serverUsername);
                    encoder.AddType(Constants.PublicKey, accessoryLtpk);
                    encoder.AddType(Constants.Signature, signature);

                    var plaintext = TlvParser.Serialise(encoder);

                    var nonce6 = new Nonce(zeros, Encoding.UTF8.GetBytes("PS-Msg06"));

                    var encryptedOutput = AeadAlgorithm.ChaCha20Poly1305.Encrypt(
                        Key.Import(AeadAlgorithm.ChaCha20Poly1305, hkdfEncKey, KeyBlobFormat.RawSymmetricKey), nonce6,
                        new byte[0], plaintext);

                    responseTlv.AddType(Constants.EncryptedData, encryptedOutput);

                    return(new PairSetupReturn
                    {
                        State = 5,
                        TlvData = responseTlv,
                        Ok = true,
                        Ltsk = ByteArrayToString(accessoryLtsk),
                        Ltpk = ByteArrayToString(ltpk)
                    });
                }
                catch (Exception e)
                {
                    _logger.LogError(e, "Could not exchange request");
                    throw;
                }
            }

            return(null);
        }
Example #30
0
        public static void ImportTooLong()
        {
            var b = new byte[129];

            Assert.Throws <ArgumentException>("sharedSecret", () => SharedSecret.Import(b));
        }