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())); }
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)); }
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); }
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; } }
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); }
public SrpEphemeral GenerateServerEphemeral(string verifier) { return(_srpServer.GenerateEphemeral(verifier)); }