001package com.nimbusds.srp6;
002
003
004import java.math.BigInteger;
005import java.nio.charset.Charset;
006import java.security.SecureRandom;
007
008
009/**
010 * Generator of password verifier 'v' values.
011 *
012 * <p>{@link SRP6Routines#generateRandomSalt} may be used to create a random
013 * salt 's' of a specified byte size.
014 *
015 * @author Vladimir Dzhuvinov
016 */
017public class SRP6VerifierGenerator {
018
019        final protected SRP6Routines srp6Routines;
020
021
022        /**
023         * The crypto configuration.
024         */
025        private SRP6CryptoParams config;
026        
027        
028        /**
029         * Custom routine for password key 'x' computation.
030         */
031        private XRoutine xRoutine = null;
032        
033        
034        /**
035         * Creates a new generator of password verifier 'v' values.
036         *
037         * @param config The SRP-6a crypto parameters configuration. Must not 
038         *                be {@code null}.
039         */
040        public SRP6VerifierGenerator(final SRP6CryptoParams config) {
041                this(config, new SRP6Routines());
042        }
043
044        /**
045         * Creates a new generator of password verifier 'v' values.
046         *
047         * @param config The SRP-6a crypto parameters configuration. Must not
048         *                be {@code null}.
049         * @param srp6Routines The cryptographic routines.
050         */
051        public SRP6VerifierGenerator(final SRP6CryptoParams config, SRP6Routines srp6Routines) {
052
053                if (config == null)
054                        throw new IllegalArgumentException("The SRP-6a crypto parameters must not be null");
055
056                this.config = config;
057
058                this.srp6Routines = srp6Routines;
059        }
060        
061        /**
062         * Generates a random salt 's'. 
063         *
064         * <p>This method is a shortcut to
065         * {@link SRP6Routines#generateRandomSalt}.
066         *
067         * @param numBytes The number of bytes the salt 's' must have.
068         *
069         * @return The salt 's' as a byte array.
070         */
071        public byte[] generateRandomSalt(final int numBytes) {
072        
073                return srp6Routines.generateRandomSalt(numBytes);
074        }
075
076        /**
077         * Generates a random salt 's'.
078         *
079         * <p>This method is a shortcut to
080         * {@link SRP6Routines#generateRandomSalt}.
081         *
082         * @param numBytes The number of bytes the salt 's' must have.
083         * @param random A secure random number generator.
084         *
085         * @return The salt 's' as a byte array.
086         */
087        public byte[] generateRandomSalt(final int numBytes, SecureRandom random) {
088
089                return srp6Routines.generateRandomSalt(numBytes, random);
090        }
091        
092        
093        /**
094         * Generates a random 16-byte salt 's'. 
095         *
096         * <p>This method is a shortcut to
097         * {@link SRP6Routines#generateRandomSalt}.
098         *
099         * @return The salt 's' as a byte array.
100         */
101        public byte[] generateRandomSalt() {
102        
103                return srp6Routines.generateRandomSalt(16);
104        }
105        
106        
107        /**
108         * Sets a custom routine for the password key 'x' computation.
109         *
110         * @param routine The password key 'x' routine or {@code null} to use 
111         *                the {@link SRP6Routines#computeX default one}
112         *                instead.
113         */
114        public void setXRoutine(final XRoutine routine) {
115        
116                xRoutine = routine;
117        }
118        
119        
120        /**
121         * Gets the custom routine for the password key 'x' computation.
122         *
123         * @return The routine instance or {@code null} if the default 
124         *         {@link SRP6Routines#computeX default one} is used.
125         */
126        public XRoutine getXRoutine() {
127        
128                return xRoutine;
129        }
130        
131        
132        /**
133         * Generates a new verifier 'v' from the specified parameters.
134         *
135         * <p>The verifier is computed as v = g^x (mod N). If a custom
136         * {@link #setXRoutine 'x' computation routine} is set it will be used
137         * instead of the {@link SRP6Routines#computeX default one}.
138         *
139         * <p>Tip: To convert a string to a byte array you can use 
140         * {@code String.getBytes()} or 
141         * {@code String.getBytes(java.nio.charset.Charset)}. To convert a big
142         * integer to a byte array you can use {@code BigInteger.toByteArray()}.
143         *
144         * @param salt     The salt 's'. Must not be {@code null}.
145         * @param userID   The user identity 'I'. May be {@code null} if the
146         *                 default 'x' routine is used or the custom one
147         *                 ignores it.
148         * @param password The user password 'P'. Must not be {@code null}. 
149         *
150         * @return The resulting verifier 'v'.
151         */
152        public BigInteger generateVerifier(final byte[] salt, final byte[] userID, final byte[] password) {
153        
154                if (salt == null)
155                        throw new IllegalArgumentException("The salt 's' must not be null");
156                
157                if (password == null)
158                        throw new IllegalArgumentException("The password 'P' must not be null");
159        
160                // Compute the password key 'x'
161                BigInteger x;
162                
163                if (xRoutine != null) {
164                        
165                        // With custom routine
166                        x = xRoutine.computeX(config.getMessageDigestInstance(), 
167                                              salt,
168                                              userID,
169                                              password);                     
170                }
171                else {
172                        // With default routine
173                        x = srp6Routines.computeX(config.getMessageDigestInstance(), salt, password);
174                }
175                
176                return srp6Routines.computeVerifier(config.N, config.g, x);
177        }
178        
179        
180        /**
181         * Generates a new verifier 'v' from the specified parameters.
182         *
183         * <p>The verifier is computed as v = g^x (mod N). If a custom
184         * {@link #setXRoutine 'x' computation routine} is set it will be used
185         * instead of the {@link SRP6Routines#computeX default one}.
186         *
187         * @param salt     The salt 's'. Must not be {@code null}.
188         * @param userID   The user identity 'I', as an UTF-8 encoded string. 
189         *                 May be {@code null} if the default 'x' routine is 
190         *                 used or the custom one ignores it.
191         * @param password The user password 'P', as an UTF-8 encoded string. 
192         *                 Must not be {@code null}. 
193         *
194         * @return The resulting verifier 'v'.
195         */
196        public BigInteger generateVerifier(final BigInteger salt, final String userID, final String password) {
197        
198                byte[] userIDBytes = null;
199                
200                if (userID != null)
201                        userIDBytes = userID.getBytes(Charset.forName("UTF-8"));
202
203                byte[] passwordBytes = password.getBytes(Charset.forName("UTF-8"));
204
205                byte[] saltBytes = BigIntegerUtils.bigIntegerToBytes(salt);
206
207                return generateVerifier(saltBytes, userIDBytes, passwordBytes);
208        }
209        
210        
211        /**
212         * Generates a new verifier 'v' from the specified parameters with the
213         * user identifier 'I' omitted.
214         *
215         * <p>The verifier is computed as v = g^x (mod N). If a custom
216         * {@link #setXRoutine 'x' computation routine} is set it must omit the
217         * user identity 'I' as well.
218         *
219         * <p>Tip: To convert a string to a byte array you can use 
220         * {@code String.getBytes()} or 
221         * {@code String.getBytes(java.nio.charset.Charset)}. To convert a big
222         * integer to a byte array you can use {@code BigInteger.toByteArray()}.
223         *
224         * @param salt     The salt 's'. Must not be {@code null}.
225         * @param password The user password 'P'. Must not be {@code null}. 
226         *
227         * @return The resulting verifier 'v'.
228         */
229        public BigInteger generateVerifier(final byte[] salt, final byte[] password) {
230        
231                return generateVerifier(salt, null, password);
232        }
233        
234        
235        /**
236         * Generates a new verifier 'v' from the specified parameters with the
237         * user identifier 'I' omitted.
238         *
239         * <p>The verifier is computed as v = g^x (mod N). If a custom
240         * {@link #setXRoutine 'x' computation routine} is set it must omit the
241         * user identity 'I' as well.
242         *
243         * @param salt     The salt 's'. Must not be {@code null}.
244         * @param password The user password 'P', as an UTF-8 encoded string. 
245         *                 Must not be {@code null}. 
246         *
247         * @return The resulting verifier 'v'.
248         */
249        public BigInteger generateVerifier(final BigInteger salt, final String password) {
250        
251                return generateVerifier(salt, null, password);
252        }
253}