Example #1
0
        public void TestSrpVerifier()
        {
            var privateKey = _srpClient.DerivePrivateKey(_saltInt.ToHex(), SrpUser, SrpPass);
            var verifier   = _srpClient.DeriveVerifier(privateKey);

            var clientEp = new SrpEphemeral
            {
                Secret = SrpInteger.FromByteArray(SrpAPrivate).ToHex(),
                Public = SrpInteger.FromByteArray(SrpAPublic).ToHex()
            };

            var serverEp = new SrpEphemeral
            {
                Secret = SrpInteger.FromByteArray(SrpBPrivate).ToHex(),
                Public = SrpInteger.FromByteArray(SrpBPublic).ToHex()
            };

            Assert.Equal(SrpV, SrpInteger.FromHex(verifier).ToByteArray());


            var clientSession = _srpClient.DeriveSession(clientEp.Secret,
                                                         serverEp.Public, _saltInt.ToHex(), SrpUser, privateKey);

            Assert.Equal(SrpK, SrpInteger.FromHex(clientSession.Key).ToByteArray());
            Assert.Equal(SrpM1, SrpInteger.FromHex(clientSession.Proof).ToByteArray());

            _srpClient.VerifySession(clientEp.Public, clientSession,
                                     SrpInteger.FromByteArray(SrpM2).ToHex());
        }
Example #2
0
        public SrpTests()
        {
            var customParams = SrpParameters.Create3072 <SHA512>();

            _saltInt   = SrpInteger.FromByteArray(SrpSalt);
            _srpClient = new SrpClient(customParams);
        }
Example #3
0
        public string DerivePrivateKey(string salt, string userName, string password)
        {
            var privateKey = _srpGenerator.DerivePrivateKey(SrpInteger.FromByteArray(GenerateSalt(16)).ToHex(), "Pair-Setup", "031-45-154");

            Assert.Equal(ExpectedPrivateKey, privateKey);

            return(privateKey);
        }
Example #4
0
        public void SrpIntegerFromToByteArrayRoundtrip()
        {
            var expected = new byte[] { 0xff, 1, 2, 3, 4, 5, 0xca, 0xfe, 0xba, 0xbe };
            var si       = SrpInteger.FromByteArray(expected);
            var actual   = si.ToByteArray();

            Assert.IsTrue(Enumerable.SequenceEqual(expected, actual));

            expected = new byte[512];
            RandomNumberGenerator.Create().GetBytes(expected);
            si     = SrpInteger.FromByteArray(expected);
            actual = si.ToByteArray();
            Assert.IsTrue(Enumerable.SequenceEqual(expected, actual));
        }
Example #5
0
        public void SrpIntegerFromBytes()
        {
            var si = SrpInteger.FromByteArray(new byte[] { 0x12 });

            Assert.AreEqual("12", si.ToHex());

            si = SrpInteger.FromByteArray(new byte[] { 0xff });
            Assert.AreEqual("ff", si.ToHex());

            si = SrpInteger.FromByteArray(new byte[] { 0x12, 0x34 });
            Assert.AreEqual("1234", si.ToHex());

            si = SrpInteger.FromByteArray(new byte[] { 0xfa, 0xc3 });
            Assert.AreEqual("fac3", si.ToHex());

            si = SrpInteger.FromByteArray(null);
            Assert.AreEqual(SrpInteger.Zero, si);

            si = SrpInteger.FromByteArray(new byte[0]);
            Assert.AreEqual(SrpInteger.Zero, si);
        }
        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 #7
0
        public void M5SetupTest()
        {
            var clientPubKey = FixedSaltGenerator.ExpectedClientPubKey;
            var clientProof  = FixedSaltGenerator.ExpectedClientProof;
            var inputData    =
                "059ac2e1aa3fef6c4bc067cd9d26a05b53fa6ad29f953af80c90968757a18fcb270118987a5c26e50f2f8e274750584929d5d5a176a62af5ef0d4002ed6333ee75b0f75d0ee4dbef345f6ae15345cfdcb97e3300d18bf8f827701f6dfcc6cc213dff5ae1cffa03235853df30d8eb6ceec068dc64e9ef8049ce3d9396bbd32c7b2e329005023cf06ed8a60e3e51491b7f7193a807f1f244369a5ee9fd060105";
            var expectedTlvHexReponse =
                "0601060587b0e4a7aa382866e824db4159cc0ecd24900136be360fd6ae64481bf799b1ecc918ecb887285a8dcd5b6f90aa410253451fd1bc638cae716cbab166f763108633555a6bfa311662986ea2d1eb83b76d195724b9bbddf7902dfd3a16e1bbd5bb8e5a5a6e3a56e8eec21c3f06ed2cce21ea17426407d0a1b35c9d692f5a5ee15ecb7ac662ade25ab7";

            var tlv = TlvParser.Parse(Automatica.Core.Driver.Utility.Utils.StringToByteArray(inputData));

            var fixedSrpGenerator = new FixedSaltGenerator();

            var session = new ConnectionSession
            {
                Salt            = fixedSrpGenerator.GenerateSalt(16),
                Verifier        = FixedSaltGenerator.ExpectedVerifier,
                ServerEphemeral = fixedSrpGenerator.GenerateServerEphemeral(FixedSaltGenerator.ExpectedVerifier)
            };

            session.ServerSession = fixedSrpGenerator.DeriveServerSession(session.ServerEphemeral.Secret, clientPubKey, SrpInteger.FromByteArray(session.Salt).ToHex(), "Pair-Setup", session.Verifier, clientProof);

            var setupController = new PairSetupController(NullLogger.Instance, "031-45-154")
            {
                SrpGenerator = fixedSrpGenerator, KeyGenerator = new FixedEd25519KeyGenerator()
            };

            var ret = setupController.Post(tlv, session);

            var expectedTlvResponse =
                TlvParser.Parse(Automatica.Core.Driver.Utility.Utils.StringToByteArray(expectedTlvHexReponse));

            var decryptedPayload = TlvParser.Parse(Automatica.Core.Driver.Utility.Utils.StringToByteArray(
                                                       "011146433a32323a33443a45333a43453a4632032083e6d70e7064effd0c6df6d19451b1ded53f7e2d0dd86e33d4aa1993f5e9cded0a402ac3063b1d193c4d365c546019c51cac8299a23a99c9f8eb2348c46af24b185a53f1f75a92d57193bdeb4dfbc47ccadccc4f9f4e3dc8191eef364d15cd921207"));
            var raw = setupController.HandlePairSetupM5Raw(session, out _);

            Assert.Equal(decryptedPayload.GetType(Constants.Identifier), raw.GetType(Constants.Identifier));
            Assert.Equal(decryptedPayload.GetType(Constants.PublicKey), raw.GetType(Constants.PublicKey));
            Assert.Equal(decryptedPayload.GetType(Constants.Signature), raw.GetType(Constants.Signature));

            var expectedEncryptedData =
                Automatica.Core.Driver.Utility.Utils.ByteArrayToString(expectedTlvResponse.GetType(Constants.EncryptedData).AsSpan());
            var retEncryptedData =
                Automatica.Core.Driver.Utility.Utils.ByteArrayToString(ret.TlvData.GetType(Constants.EncryptedData).AsSpan());

            Assert.Equal(expectedEncryptedData, retEncryptedData);
            Assert.Equal(expectedTlvResponse.GetType(Constants.State), ret.TlvData.GetType(Constants.State));
            Assert.Equal(expectedTlvResponse.GetType(Constants.EncryptedData), ret.TlvData.GetType(Constants.EncryptedData));

            var expectedHttpResponse =
                "485454502F312E3120323030204F4B0D0A436F6E74656E742D4C656E6774683A203134300D0A436F6E74656E742D547970653A206170706C69636174696F6E2F70616972696E672B746C76380D0A446174653A2053756E2C203139204A616E20323032302031353A33313A313320474D540D0A436F6E6E656374696F6E3A206B6565702D616C6976650D0A0D0A0601060587B0E4A7AA382866E824DB4159CC0ECD24900136BE360FD6AE64481BF799B1ECC918ECB887285A8DCD5B6F90AA410253451FD1BC638CAE716CBAB166F763108633555A6BFA311662986EA2D1EB83B76D195724B9BBDDF7902DFD3A16E1BBD5BB8E5A5A6E3A56E8EEC21C3F06ED2CCE21EA17426407D0A1B35C9D692F5A5EE15ECB7AC662ADE25AB7";
            var expectedHttpResponseArray =
                Automatica.Core.Driver.Utility.Utils.StringToByteArray(expectedHttpResponse);

            var requestTime  = new DateTime(2020, 01, 19, 15, 31, 13, DateTimeKind.Utc);
            var httpResponse =
                HttpServerConnection.GetHttpResponse("HTTP/1.1", PairSetupReturn.ContentType, TlvParser.Serialize(ret.TlvData), requestTime);

            Assert.Equal(expectedHttpResponseArray, httpResponse);
        }
        public PairSetupReturn Post(Tlv parts, ConnectionSession session)
        {
            var state = parts.GetTypeAsInt(Constants.State);

            if (session.Salt == null)
            {
                session.Salt = SrpGenerator.GenerateSalt(16);
            }

            _logger.LogDebug($"State is {state}");

            if (state == 1) //srp sign up
            {
                var saltInt = SrpInteger.FromByteArray(session.Salt);

                var privateKey = SrpGenerator.DerivePrivateKey(saltInt.ToHex(), Username, _code);
                session.Verifier = SrpGenerator.DeriveVerifier(privateKey);

                session.ServerEphemeral = SrpGenerator.GenerateServerEphemeral(session.Verifier);

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

                _logger.LogDebug($"return salt {saltInt.ToHex()}, pub {session.ServerEphemeral.Public} and state 2");

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

            if (state == 3) //srp authenticate
            {
                _logger.LogDebug("Pair Setup Step 3/5");
                _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
                {
                    session.ServerSession = SrpGenerator.DeriveServerSession(session.ServerEphemeral.Secret, iOsPublicKey.ToHex(), SrpInteger.FromByteArray(session.Salt).ToHex(), Username, session.Verifier,
                                                                             iOsProof.ToHex());
                    _logger.LogInformation("Verification was successful. Generating Server Proof (M2)");

                    responseTlv.AddType(Constants.Proof, StringToByteArray(session.ServerSession.Proof));


                    _logger.LogDebug($"return proof {session.ServerSession.Proof}, secret {session.ServerEphemeral.Secret} and state 4");
                }
                catch (Exception e)
                {
                    ok = false;
                    _logger.LogError(e, "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)
            {
                return(HandlePairSetupM5(parts, session));
            }

            return(null);
        }