BouncyCastle SRP6

Started by
2 comments, last by MatsK 12 years, 5 months ago
Has anyone here used the library available from BouncyCastle?
I'm trying to get SRP6 to work using this library (in C#), but I'm confused.

As of right now, I'm doing:

Client sends: Username, N, G, Verification (which is generated by calling Srp6VerifierGenerator.GenerateVerifier()) and PublicEphemeralValueA (which is generated by calling Srp6Client.GenerateClientCredentials).
Server receives all of this and uses it to generate its secret.

What I don't get is... how does the server know that the client has the right password? Right now the server and client each has their own secret (which can be used to encrypt communication), but the server has no way of knowing if the client issued the right password!

I tried doing this:

/// <summary>
/// Verifies the client's credentials.
/// </summary>
/// <returns>Returns true if the credentials were valid, otherwise returns false.</returns>
public bool VerifyClient()
{
if (m_Secret.Equals(m_Server.CalculateSecret(m_PublicEphemeralValueA)))
return true;

return false;
}



But it keeps returning false.

The test-case included with the library does this:

private void testWithRandomParams(int bits)
{
DHParametersGenerator paramGen = new DHParametersGenerator();
paramGen.Init(bits, 25, random);
DHParameters parameters = paramGen.GenerateParameters();

BigInteger g = parameters.G;
BigInteger p = parameters.P;

testMutualVerification(p, g);
}

private void testMutualVerification(BigInteger N, BigInteger g)
{
byte[] I = Encoding.UTF8.GetBytes("username");
byte[] P = Encoding.UTF8.GetBytes("password");
byte[] s = new byte[16];
random.NextBytes(s);

Srp6VerifierGenerator gen = new Srp6VerifierGenerator();
gen.Init(N, g, new Sha256Digest());
BigInteger v = gen.GenerateVerifier(s, I, P);

Srp6Client client = new Srp6Client();
client.Init(N, g, new Sha256Digest(), random);

Srp6Server server = new Srp6Server();
server.Init(N, g, v, new Sha256Digest(), random);

BigInteger A = client.GenerateClientCredentials(s, I, P);
BigInteger B = server.GenerateServerCredentials();

BigInteger clientS = client.CalculateSecret(B);
BigInteger serverS = server.CalculateSecret(A);

if (!clientS.Equals(serverS))
{
Fail("SRP agreement failed - client/server calculated different secrets");
}
}



I still fail to see how the server knows if the client issued the right password! Has anyone used the SRP6 part of this library before (it's a pretty huge library)? Does anyone have any tips?
Advertisement
First, why are you not using SSL/TLS? SSL/TLS is built into all OS-es these days, and is highly compatible with the web in general. It is also highly robust, having been vetted over many years by a large body of both security researchers and attempted hackers.

Second, if the process you're running is intended to do a Diffie-Hellman exchange, then you should know that this *only* sets up a shared encryption secret such that place A can send data to place B without anyone between them being able to decrypt it. It does not do authentication. It also does not guard against an active man-in-the-middle, because that man-in-the-middle can just run the DH exchange both ways, establishing two connections.

Thus, to authenticate the remote end, you must have shared data of some sort. Typically, you will use a public/private key with the server keeping the public part of the client, and the client keeping the public part of the server. You can install that certificate as part of your game.

Once you have a verified, secure channel, you can then establish that the client is who he/she says he/she is, by using something like a challenge/response authentication method (if the server stores an unhashed copy of the player's password somewhere), or simply by sending the password encrypted using the server public key AND a random nonce, thus not de-cryptable by a man in the middle and the encrypted key is not re-usable for replay attacks because of the nonce.
enum Bool { True, False, FileNotFound };
I've not used the library, but I do know about SRP6. You seem to have missed something - SRP allows you to verify a username/password - but not create one. It must have been created some other way beforehand.


Client sends: Username, N, G, Verification (which is generated by calling Srp6VerifierGenerator.GenerateVerifier()) and PublicEphemeralValueA (which is generated by calling Srp6Client.GenerateClientCredentials).
Server receives all of this and uses it to generate its secret.


No, you have it somewhat backward - the client only sends the username and A. N and G are pre-defined by the server, and never, ever change through the life of the system.

The verifier and salt are also generated by the server when the username/password are defined beforehand, and kept secret by the server.

The client must not dictate the values of N, G, verifier or the salt. If you send the verifier over the channel, the security is broken.


What I don't get is... how does the server know that the client has the right password? Right now the server and client each has their own secret (which can be used to encrypt communication), but the server has no way of knowing if the client issued the right password!


Basic SRP uses 'proof' messages which are exchanged after the session key is calculated. This is basically a hash of the key, username, and other pieces of data. If the server receives the same 'proof' it has generated itself, the client must know the password.

With SRP/TLS, there are no proof messages. But if the client has generated the wrong session key (i.e. didn't know the password) then the traffic will not decrypt correctly - nor will the HMAC be valid, and the connection will be terminated.

Effectively, proof that the client knows the password is implicit. If the client can send you messages you can decrypt, they must know the password.

The authors' papers on SRP are very helpful, just google and you will find them. Hope that's helpful.
Thanks guys.
I reverted to using the native .NET CryptoStream class for encryption and password hashing for authentication. It seems to work well enough.

This topic is closed to new replies.

Advertisement