org.bouncycastle.crypto.agreement.srp.SRP6Server Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bcprov-ext-debug-jdk18on Show documentation
Show all versions of bcprov-ext-debug-jdk18on Show documentation
The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for Java 1.8 and later with debug enabled.
The newest version!
package org.bouncycastle.crypto.agreement.srp;
import java.math.BigInteger;
import java.security.SecureRandom;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.params.SRP6GroupParameters;
/**
* Implements the server side SRP-6a protocol. Note that this class is stateful, and therefore NOT threadsafe.
* This implementation of SRP is based on the optimized message sequence put forth by Thomas Wu in the paper
* "SRP-6: Improvements and Refinements to the Secure Remote Password Protocol, 2002"
*/
public class SRP6Server
{
protected BigInteger N;
protected BigInteger g;
protected BigInteger v;
protected SecureRandom random;
protected Digest digest;
protected BigInteger A;
protected BigInteger b;
protected BigInteger B;
protected BigInteger u;
protected BigInteger S;
protected BigInteger M1;
protected BigInteger M2;
protected BigInteger Key;
public SRP6Server()
{
}
/**
* Initialises the server to accept a new client authentication attempt
* @param N The safe prime associated with the client's verifier
* @param g The group parameter associated with the client's verifier
* @param v The client's verifier
* @param digest The digest algorithm associated with the client's verifier
* @param random For key generation
*/
public void init(BigInteger N, BigInteger g, BigInteger v, Digest digest, SecureRandom random)
{
this.N = N;
this.g = g;
this.v = v;
this.random = random;
this.digest = digest;
}
public void init(SRP6GroupParameters group, BigInteger v, Digest digest, SecureRandom random)
{
init(group.getN(), group.getG(), v, digest, random);
}
/**
* Generates the server's credentials that are to be sent to the client.
* @return The server's public value to the client
*/
public BigInteger generateServerCredentials()
{
BigInteger k = SRP6Util.calculateK(digest, N, g);
this.b = selectPrivateValue();
this.B = k.multiply(v).mod(N).add(g.modPow(b, N)).mod(N);
return B;
}
/**
* Processes the client's credentials. If valid the shared secret is generated and returned.
* @param clientA The client's credentials
* @return A shared secret BigInteger
* @throws CryptoException If client's credentials are invalid
*/
public BigInteger calculateSecret(BigInteger clientA) throws CryptoException
{
this.A = SRP6Util.validatePublicValue(N, clientA);
this.u = SRP6Util.calculateU(digest, N, A, B);
this.S = calculateS();
return S;
}
protected BigInteger selectPrivateValue()
{
return SRP6Util.generatePrivateValue(digest, N, g, random);
}
private BigInteger calculateS()
{
return v.modPow(u, N).multiply(A).mod(N).modPow(b, N);
}
/**
* Authenticates the received client evidence message M1 and saves it only if correct.
* To be called after calculating the secret S.
* @param clientM1 the client side generated evidence message
* @return A boolean indicating if the client message M1 was the expected one.
* @throws CryptoException
*/
public boolean verifyClientEvidenceMessage(BigInteger clientM1) throws CryptoException
{
// Verify pre-requirements
if (this.A == null || this.B == null || this.S == null)
{
throw new CryptoException("Impossible to compute and verify M1: " +
"some data are missing from the previous operations (A,B,S)");
}
// Compute the own client evidence message 'M1'
BigInteger computedM1 = SRP6Util.calculateM1(digest, N, A, B, S);
if (computedM1.equals(clientM1))
{
this.M1 = clientM1;
return true;
}
return false;
}
/**
* Computes the server evidence message M2 using the previously verified values.
* To be called after successfully verifying the client evidence message M1.
* @return M2: the server side generated evidence message
* @throws CryptoException
*/
public BigInteger calculateServerEvidenceMessage() throws CryptoException
{
// Verify pre-requirements
if (this.A == null || this.M1 == null || this.S == null)
{
throw new CryptoException("Impossible to compute M2: " +
"some data are missing from the previous operations (A,M1,S)");
}
// Compute the server evidence message 'M2'
this.M2 = SRP6Util.calculateM2(digest, N, A, M1, S);
return M2;
}
/**
* Computes the final session key as a result of the SRP successful mutual authentication
* To be called after calculating the server evidence message M2.
* @return Key: the mutual authenticated symmetric session key
* @throws CryptoException
*/
public BigInteger calculateSessionKey() throws CryptoException
{
// Verify pre-requirements
if (this.S == null || this.M1 == null || this.M2 == null)
{
throw new CryptoException("Impossible to compute Key: " +
"some data are missing from the previous operations (S,M1,M2)");
}
this.Key = SRP6Util.calculateKey(digest, N, S);
return Key;
}
}