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. A valid use case
015 * for generating a verifier using server code would be if a user lost their
016 * password and you were generating a temporary password and verifier to email
017 * out to the client.
018 *
019 * Certainly you SHOULD avoid this code ever being run against a real user password
020 * which is transmitted to the server which is something which SRP is designed to avoid.
021 */
022public class HexHashedVerifierGenerator {
023        protected final SRP6CryptoParams config;
024
025        public HexHashedVerifierGenerator(final SRP6CryptoParams config) {
026                this.config = config;
027        }
028
029        /**
030         * @param N
031         *            The large safe prime in radix10
032         * @param g
033         *            The safe prime generator in radix10
034         * @param hashName
035         *            The name of the hashing algorithm e.g. SHA256
036         */
037        public HexHashedVerifierGenerator(String N, String g, String hashName) {
038                config = new SRP6CryptoParams(
039                                SRP6JavascriptServerSession.fromDecimal(N),
040                                SRP6JavascriptServerSession.fromDecimal(g), hashName);
041        }
042
043        private String hashCredentials(String salt, String identity, String password) {
044                MessageDigest digest = config.getMessageDigestInstance();
045                return HexHashedRoutines.hashCredentials(digest, salt,
046                                identity, password);
047        }
048
049        // matches javascript client library does which is H(s | H(i | ":" | p))
050        private BigInteger generateX(String salt, String identity, String password) {
051                String hash = hashCredentials(salt, identity, password);
052                return fromHex(hash).mod(config.N);
053        }
054
055        /**
056         * Browser does string concat version of x = H(s | H(i | ":" | p)).
057         * Specification is RFC 5054 Which we repeat here to be able to reset the
058         * password in a java client.
059         * 
060         * @param salt
061         *            The random salt stored at user registration
062         * @param identity
063         *            The user username
064         * @param password
065         *            The user password. Note this should only ever be on java
066         *            clients and never sent to the java server.
067         * @return An SRP password verifier
068         */
069        public String generateVerifier(String salt, String identity, String password) {
070                BigInteger x = generateX(salt, identity, password);
071                BigInteger v = config.g.modPow(x, config.N);
072                return toHex(v).toLowerCase();
073        }
074
075}