Looks like SrpParameters aren't thread safe because HashAlgorithm.ComputeHash isn't thread safe.
The issue is easily reproduced like this:
[Test]
public async Task ParallelAuthenticationTest()
{
var username = "demo";
var password = "insecure";
var parameters = new SrpParameters();
var server = new SrpServer(parameters);
// spawn multiple threads reusing the same SrpParameters instance
var tasks = Enumerable.Range(0, 10).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);
}));
await Task.WhenAll(tasks);
}
Looks like SrpParameters aren't thread safe because HashAlgorithm.ComputeHash isn't thread safe. The issue is easily reproduced like this: