001package com.bitbucket.thinbus.srp6.js;
002
003import static com.nimbusds.srp6.BigIntegerUtils.fromHex;
004import static com.nimbusds.srp6.BigIntegerUtils.toHex;
005
006import java.math.BigInteger;
007import java.security.MessageDigest;
008
009import com.nimbusds.srp6.SRP6CryptoParams;
010
011/**
012 * Generates a SRP6 verifier. WARNING: You should use the JavaScript client not
013 * the Java client for generating the verifier. See the
014 * TestSRP6JavascriptClientSessionSHA256.js for an example. This class is only
015 * for systems which let users login from Java clients in addition to JavaScript
016 * clients who additionally wish to implement user registration of password
017 * reset logic in their Java clients which subsequently let users login via a
018 * browser. It is probably better to implement user registration or password
019 * rest logic only via the browser. Certainly you SHOULD to avoid this code ever
020 * being run on the server as that would require the password to be transmitted
021 * to the server which is something which SRP is designed to avoid.
022 */
023public class HexHashedVerifierGenerator {
024        protected final SRP6CryptoParams config;
025
026        /**
027         * @param N
028         *            The large safe prime in radix10
029         * @param g
030         *            The safe prime generator in radix10
031         * @param hashName
032         *            The name of the hashing algorithm e.g. SHA256
033         */
034        public HexHashedVerifierGenerator(String N, String g, String hashName) {
035                config = new SRP6CryptoParams(
036                                SRP6JavascriptServerSession.fromDecimal(N),
037                                SRP6JavascriptServerSession.fromDecimal(g), hashName);
038        }
039
040        private String hashCredentials(String salt, String identity, String password) {
041                MessageDigest digest = config.getMessageDigestInstance();
042                return HexHashedRoutines.hashCredentials(digest, salt,
043                                identity, password);
044        }
045
046        // matches javascript client library does which is H(s | H(i | ":" | p))
047        private BigInteger generateX(String salt, String identity, String password) {
048                String hash = hashCredentials(salt, identity, password);
049                return fromHex(hash).mod(config.N);
050        }
051
052        /**
053         * Browser does string concat version of x = H(s | H(i | ":" | p)).
054         * Specification is RFC 5054 Which we repeat here to be able to reset the
055         * password in a java client.
056         * 
057         * @param salt
058         *            The random salt stored at user registration
059         * @param identity
060         *            The user username
061         * @param password
062         *            The user password. Note this should only ever be on java
063         *            clients and never sent to the java server.
064         * @return An SRP password verifier
065         */
066        public String generateVerifier(String salt, String identity, String password) {
067                BigInteger x = generateX(salt, identity, password);
068                BigInteger v = config.g.modPow(x, config.N);
069                return toHex(v).toLowerCase();
070        }
071
072}