public void SrpClientVerifiesSession() { var clientEphemeralPublic = "30fca5854c2391faa219fd863487c31f2591f5ba9988ce5129319906929ff2d23bc4e24c3f36f6ed12034111881ca705b033edfb782a1714e0f4d892f17c7d8432a1089c311c3170848bba0a0f64930d3f097c670b08384f1641a73833edaf9d1493744e655043df0d68f0c18a1571cc1c07c41ad817b57c262f48dde991d413628c0f3fa1de55afcf2d87e994c7f6e25c07cf1a803d41f555158997cd8703da68a48e54598b5b4947cc661d5c0138a5ecaa55996d5d6b566578f9de3b1ca1e128ff223c290595252497835646b9f8c0e330f4d6a3e61f31ff3eb8e305f563cb112ca90942e770f94cd02396041ab4c47e0c58675ded8bb0026640f9723b4d67"; var clientSessionKey = "0bb4c696fd6f240fa0b268f3ce267044b05d620ac5f9871d21e4f89a3b0ac841"; var clientSessionProof = "50a240e5b5f4d0db633e147d92a32aa0c9451e5d0508bded623b40200d237eef"; var serverSessionProof = "a06d7fe3d45542f993c39b145ea3a0e3f5d6943373af35af355bb82692d692e8"; var clientSession = new SrpSession { Key = clientSessionKey, Proof = clientSessionProof, }; new SrpClient().VerifySession(clientEphemeralPublic, clientSession, serverSessionProof); }
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); }