예제 #1
0
        private AuthResponse AuthStep1(AuthRequest authRequest)
        {
            // first step never fails: User -> Host: I, A = g^a (identifies self, a = random number)
            var userName = authRequest.GetUserName();
            var clientEphemeralPublic = authRequest.GetClientPublicEphemeral();
            var account = AuthRepository.FindByName(userName);

            if (account != null)
            {
                // save the data for the second authentication step
                var salt            = account.Salt;
                var verifier        = account.Verifier;
                var serverEphemeral = SrpServer.GenerateEphemeral(verifier);
                PendingAuthentications[authRequest.GetLoginSession()] = new Step1Data
                {
                    Account = account,
                    ClientEphemeralPublic = clientEphemeralPublic,
                    ServerEphemeral       = serverEphemeral,
                };

                // Host -> User: s, B = kv + g^b (sends salt, b = random number)
                return(ResponseStep1(salt, serverEphemeral.Public, authRequest.GetLoginSession()));
            }

            var fakeSalt      = SrpParameters.Hash(userName + UnknownUserSalt).ToHex();
            var fakeEphemeral = SrpServer.GenerateEphemeral(fakeSalt);

            return(ResponseStep1(fakeSalt, fakeEphemeral.Public, authRequest.GetLoginSession()));
        }
예제 #2
0
        private AuthResponseMessage AuthStep1(AuthRequestMessage authRequest)
        {
            // first step never fails: User -> Host: I, A = g^a (identifies self, a = random number)
            var userName = (string)authRequest.Credentials[SrpProtocolConstants.SRP_USERNAME];
            var clientEphemeralPublic = (string)authRequest.Credentials[SrpProtocolConstants.SRP_CLIENT_PUBLIC_EPHEMERAL];
            var account = AuthRepository.FindByName(userName);

            if (account != null)
            {
                // save the data for the second authentication step
                var salt            = account.Salt;
                var verifier        = account.Verifier;
                var serverEphemeral = SrpServer.GenerateEphemeral(verifier);
                PendingAuthentications[authRequest.SessionID] = new Step1Data
                {
                    Account = account,
                    ClientEphemeralPublic = clientEphemeralPublic,
                    ServerEphemeral       = serverEphemeral
                };

                // Host -> User: s, B = kv + g^b (sends salt, b = random number)
                return(ResponseStep1(salt, serverEphemeral.Public));
            }

            // generate fake salt and B values so that attacker cannot tell whether the given user exists or not
            var fakeSalt      = SrpParameters.Hash(userName + UnknownUserSalt).ToHex();
            var fakeEphemeral = SrpServer.GenerateEphemeral(fakeSalt);

            return(ResponseStep1(fakeSalt, fakeEphemeral.Public));
        }
예제 #3
0
        public async Task ParallelAuthenticationTest()
        {
            var username   = "******";
            var password   = "******";
            var parameters = new SrpParameters();
            var server     = new SrpServer(parameters);

            // spawn multiple parallel threads reusing the same SrpParameters instance
            var tasks = Enumerable.Range(0, 100).Select(i => Task.Run(() =>
            {
                var client = new SrpClient(parameters);

                // sign up
                var salt       = client.GenerateSalt();
                var privateKey = client.DerivePrivateKey(salt, username, password);
                var verifier   = client.DeriveVerifier(privateKey);

                // authenticate
                var clientEphemeral = client.GenerateEphemeral();
                var serverEphemeral = server.GenerateEphemeral(verifier);
                var clientSession   = client.DeriveSession(clientEphemeral.Secret, serverEphemeral.Public, salt, username, privateKey);

                var serverSession = server.DeriveSession(serverEphemeral.Secret, clientEphemeral.Public, salt, username, verifier, clientSession.Proof);
                client.VerifySession(clientEphemeral.Public, clientSession, serverSession.Proof);

                // make sure both the client and the server have the same session key
                Assert.AreEqual(clientSession.Key, serverSession.Key);

                // verify padded length of all parameters
                Assert.AreEqual(verifier.Length, parameters.PaddedLength);
                Assert.AreEqual(clientEphemeral.Public.Length, parameters.PaddedLength);
                Assert.AreEqual(clientEphemeral.Secret.Length, parameters.HashSizeBytes * 2);
                Assert.AreEqual(serverEphemeral.Public.Length, parameters.PaddedLength);
                Assert.AreEqual(serverEphemeral.Secret.Length, parameters.HashSizeBytes * 2);
                Assert.AreEqual(serverSession.Key.Length, parameters.HashSizeBytes * 2);
                Assert.AreEqual(clientSession.Key.Length, parameters.HashSizeBytes * 2);
                Assert.AreEqual(serverSession.Proof.Length, parameters.HashSizeBytes * 2);
                Assert.AreEqual(clientSession.Proof.Length, parameters.HashSizeBytes * 2);
            }));

            await Task.WhenAll(tasks);
        }
예제 #4
0
        private void SrpAuthentication(string username, string password, SrpParameters parameters = null)
        {
            // use default parameters if not specified: sha256, 2048-bit prime number
            var client = new SrpClient(parameters);
            var server = new SrpServer(parameters);

            // sign up
            var salt       = client.GenerateSalt();
            var privateKey = client.DerivePrivateKey(salt, username, password);
            var verifier   = client.DeriveVerifier(privateKey);

            // authenticate
            var clientEphemeral = client.GenerateEphemeral();
            var serverEphemeral = server.GenerateEphemeral(verifier);
            var clientSession   = client.DeriveSession(clientEphemeral.Secret, serverEphemeral.Public, salt, username, privateKey);

            try
            {
                var serverSession = server.DeriveSession(serverEphemeral.Secret, clientEphemeral.Public, salt, username, verifier, clientSession.Proof);
                client.VerifySession(clientEphemeral.Public, clientSession, serverSession.Proof);

                // make sure both the client and the server have the same session key
                Assert.AreEqual(clientSession.Key, serverSession.Key);
            }
            catch
            {
                // generate the regression test code
                Console.WriteLine("// regression test:");
                Console.WriteLine($"var parameters = {parameters?.ToString() ?? "new SrpParameters()"};");
                Console.WriteLine($"var serverEphemeral = new SrpEphemeral");
                Console.WriteLine($"{{");
                Console.WriteLine($"	Secret = \"{serverEphemeral.Secret}\",");
                Console.WriteLine($"	Public = \"{serverEphemeral.Public}\",");
                Console.WriteLine($"}};");
                Console.WriteLine();
                Console.WriteLine($"var clientEphemeral = new SrpEphemeral");
                Console.WriteLine($"{{");
                Console.WriteLine($"	Secret = \"{clientEphemeral.Secret}\",");
                Console.WriteLine($"	Public = \"{clientEphemeral.Public}\",");
                Console.WriteLine($"}};");
                Console.WriteLine();
                Console.WriteLine($"var salt = \"{salt}\";");
                Console.WriteLine($"var username = \"{username}\";");
                Console.WriteLine($"var privateKey = \"{privateKey}\";");
                Console.WriteLine($"var verifier = \"{verifier}\";");
                Console.WriteLine($"var clientSessionProof = \"{clientSession.Proof}\";");
                Console.WriteLine($"var serverSessionKey = \"{clientSession.Key}\";");
                Console.WriteLine($"var serverSessionProof = \"????\";");
                Console.WriteLine();
                Console.WriteLine($"var clientSession = new SrpClient(parameters).DeriveSession(clientEphemeral.Secret, serverEphemeral.Public, salt, username, privateKey);");
                Console.WriteLine($"Assert.IsNotNull(clientSession);");
                Console.WriteLine($"Assert.AreEqual(serverSessionKey, clientSession.Key);");
                Console.WriteLine($"Assert.AreEqual(clientSessionProof, clientSession.Proof);");
                Console.WriteLine();
                Console.WriteLine($"var serverSession = new SrpServer(parameters).DeriveSession(serverEphemeral.Secret, clientEphemeral.Public, salt, username, verifier, clientSessionProof);");
                Console.WriteLine($"Assert.IsNotNull(serverSession);");
                Console.WriteLine($"Assert.AreEqual(serverSessionKey, serverSession.Key);");
                Console.WriteLine($"Assert.AreEqual(serverSessionProof, serverSession.Proof);");
                throw;
            }
        }
예제 #5
0
        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);
        }
예제 #6
0
 public SrpEphemeral GenerateServerEphemeral(string verifier)
 {
     return(_srpServer.GenerateEphemeral(verifier));
 }