All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bitbucket.thinbus.srp6.js.SRP6JavascriptServerSession Maven / Gradle / Ivy

package com.bitbucket.thinbus.srp6.js;

import static com.nimbusds.srp6.BigIntegerUtils.fromHex;
import static com.nimbusds.srp6.BigIntegerUtils.toHex;

import java.io.Serializable;
import java.math.BigInteger;

import com.nimbusds.srp6.SRP6CryptoParams;
import com.nimbusds.srp6.SRP6Exception;
import com.nimbusds.srp6.SRP6Routines;
import com.nimbusds.srp6.SRP6ServerSession;
import com.nimbusds.srp6.SRP6ServerSession.State;

abstract public class SRP6JavascriptServerSession implements Serializable {

	final SRP6Routines srp6Routines = new SRP6Routines();

	/**
	 * Serializable class version number
	 */
	private static final long serialVersionUID = -5998252135527603869L;

	/**
	 * Returns the one-time server challenge `B` encoded as hex. 
	 * Increments this SRP-6a authentication session to {@link State#STEP_1}.
	 * 
	 * @param username
	 *            The identity 'I' of the authenticating user. Must not be
	 *            {@code null} or empty.
	 * @param salt
	 *            The password salt 's'. Must not be {@code null}.
	 * @param v
	 *            The password verifier 'v'. Must not be {@code null}.
	 * 
	 * @return The server public value 'B' as hex encoded number.
	 * 
	 * @throws IllegalStateException
	 *             If the mehod is invoked in a state other than
	 *             {@link State#INIT}.
	 */
	public String step1(final String username, final String salt, final String v) {
		BigInteger B = session.step1(username, fromHex(salt), fromHex(v));
		return toHex(B);
	}

	/**
	 * Validates a password proof `M1` based on the client one-tiem public key `A`. 
	 * Increments this SRP-6a authentication session to {@link State#STEP_2}.
	 * 
	 * @param A
	 *            The client public value. Must not be {@code null}.
	 * @param M1
	 *            The client evidence message. Must not be {@code null}.
	 * 
	 * @return The server evidence message 'M2' has hex encoded number with
	 *         leading zero padding to match the 256bit hash length.
	 * 
	 * @throws SRP6Exception
	 *             If the client public value 'A' is invalid or the user
	 *             credentials are invalid.
	 * 
	 * @throws IllegalStateException
	 *             If the mehod is invoked in a state other than
	 *             {@link State#STEP_1}.
	 */
	public String step2(final String A, final String M1) throws Exception {
		BigInteger M2 = session.step2(fromHex(A), fromHex(M1));
		String M2str = toHex(M2);
		M2str = HexHashedRoutines.leadingZerosPad(M2str, HASH_HEX_LENGTH);
		return M2str;
	}

	/**
	 * Returns the underlying session state as a String for JavaScript testing.
	 * 
	 * @return The current state.
	 */
	public String getState() {
		return session.getState().name();
	}

	/**
	 * Gets the identity 'I' of the authenticating user.
	 *
	 * @return The user identity 'I', null if undefined.
	 */
	public String getUserID() {
		return session.getUserID();
	}

	/**
	 * The crypto parameters for the SRP-6a protocol. These must be agreed
	 * between client and server before authentication and consist of a large
	 * safe prime 'N', a corresponding generator 'g' and a hash function
	 * algorithm 'H'. You can generate your own with openssl using
	 * {@link OpenSSLCryptoConfigConverter}
	 * 
	 */
	protected final SRP6CryptoParams config;

	/**
	 * The underlying Nimbus session which will be configure for JavaScript
	 * interactions
	 */
	protected final SRP6ServerSession session;
	
	/**
	 * Constructs a JavaScript compatible server session which configures an
	 * underlying Nimbus SRP6ServerSession.
	 * 
	 * @param srp6CryptoParams
	 *            cryptographic constants which must match those being used by
	 *            the client.
	 */
	public SRP6JavascriptServerSession(SRP6CryptoParams srp6CryptoParams) {
		this.config = srp6CryptoParams;
		session = new SRP6ServerSession(config);
		session.setHashedKeysRoutine(new HexHashedURoutine());
		session.setClientEvidenceRoutine(new HexHashedClientEvidenceRoutine());
		session.setServerEvidenceRoutine(new HexHashedServerEvidenceRoutine());
	}

	/**
	 * k is actually fixed and done with hash padding routine which uses
	 * java.net.BigInteger byte array constructor so this is a convenience
	 * method to get at the Java generated value to use in the configuration of
	 * the Javascript
	 * 
	 * @return 'k' calculated as H( N, g )
	 */
	public String k() {
		return toHex(this.srp6Routines.computeK(config.getMessageDigestInstance(), config.N, config.g));
	}

	/**
	 * Turn a radix10 string into a java.net.BigInteger
	 * 
	 * @param base10
	 *            the radix10 string
	 * @return the BigInteger representation of the number
	 */
	public static BigInteger fromDecimal(String base10) {
		return new BigInteger(base10, 10);
	}

	/**
	 * This must match the expected character length of the specified algorithm
	 */
	public static int HASH_HEX_LENGTH;

	/**
	 * Outputs the configuration in the way which can be used to configure
	 * JavaScript.
	 * 
	 * Note that 'k' is fixed but uses the byte array constructor of BigInteger
	 * which is not available in JavaScript to you must set it as configuration.
	 * 
	 * @return Parameters required by JavaScript client.
	 */
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append(String.format("g: %s\n", config.g.toString(10)));
		builder.append(String.format("N: %s\n", config.N.toString(10)));
		builder.append(String.format("k: %s\n", k()));
		return builder.toString();
	}

	/**
	 * Gets the password salt 's'.
	 * 
	 * @deprecated This value is returned by step1 having a getter means holding onto more memory see issue #4 at https://bitbucket.org/simon_massey/thinbus-srp-js/issues/4
	 * 
	 * @return The salt 's' if available, else {@code null}.
	 */
	@Deprecated 
	public String getSalt() {
		return toHex(session.getSalt());
	}

	/**
	 * Gets the public server value 'B'.
	 * 
	 * @deprecated This value is returned by step1 having a getter means holding onto more memory see issue #4 at https://bitbucket.org/simon_massey/thinbus-srp-js/issues/4
	 * 
	 * @return The public server value 'B' if available, else {@code null}.
	 */
	@Deprecated 
	public String getPublicServerValue() {
		return toHex(session.getPublicServerValue());
	}

	/**
	 * Gets the server evidence message 'M2'.
	 *
	 * @deprecated This value is returned by step2 having a getter means holding onto more memory see issue #4 at https://bitbucket.org/simon_massey/thinbus-srp-js/issues/4
	 * 
	 * @return The server evidence message 'M2' if available, else {@code null}.
	 */
	@Deprecated 
	public String getServerEvidenceMessage() {
		return toHex(session.getServerEvidenceMessage());
	}

	/**
	 * Gets the shared session key 'S' or its hash H(S).
	 *
	 * @param doHash
	 *            If {@code true} the hash H(S) of the session key will be
	 *            returned instead of the raw value.
	 *
	 * @return The shared session key 'S' or its hash H(S). {@code null} will be
	 *         returned if authentication failed or the method is invoked in a
	 *         session state when the session key 'S' has not been computed yet.
	 */
	public String getSessionKey(boolean doHash) {
		String S = toHex(session.getSessionKey());
		if (doHash) {
			String K = HexHashedRoutines.toHexString(this.config
					.getMessageDigestInstance().digest(
					S.getBytes(HexHashedRoutines.utf8)));
			return K;
		} else {
			return S;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy