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}