/** * Creates a hash for a clear text password. * * @param rawPassword The password to hash. A randomly generated salt will be used * for hashing the password. * @return The encoded password hash. The value will be of the form * <pre> * "{" Base64(salt) "}" passwordHash * </pre> * Where passwordHash is the Base64 encoding of the bytes resulting from applying * the hash function to the byte array consisting of the salt bytes * and the UTF-8 encoding of the clear text password. */ @Override public String encode(final CharSequence rawPassword) { final byte[] salt = randomSalt(); return new StringBuilder() .append(PREFIX).append(Base64.getEncoder().encodeToString(salt)).append(SUFFIX) .append(Base64.getEncoder().encodeToString(digest(salt, rawPassword.toString()))) .toString(); }
/** * Creates a new encoder for a random number generator. * * @param rng The random number generator to use. * @param bcryptStrength The strength to use for creating BCrypt hashes. Value must be * >= 4 and <= 31. Note that a higher value will increase the time * it takes to compute a hash. A value around 10 is considered a good compromise * between security and computation time. * @throws NullPointerException if the RNG is {@code null}. * @throws IllegalArgumentException if BCrypt strength is < 4 or > 31. */ public SpringBasedHonoPasswordEncoder(final SecureRandom rng, final int bcryptStrength) { this.secureRandom = Objects.requireNonNull(rng); encoderForEncode = new BCryptPasswordEncoder(bcryptStrength, secureRandom); idForEncode = CredentialsConstants.HASH_FUNCTION_BCRYPT; encoders.put(idForEncode, encoderForEncode); encoders.put( CredentialsConstants.HASH_FUNCTION_SHA256, new MessageDigestPasswordEncoder(CredentialsConstants.HASH_FUNCTION_SHA256, secureRandom)); encoders.put( CredentialsConstants.HASH_FUNCTION_SHA512, new MessageDigestPasswordEncoder(CredentialsConstants.HASH_FUNCTION_SHA512, secureRandom)); LOG.info("using BCrypt [strength: {}] with PRNG [{}] for encoding clear text passwords", bcryptStrength, rng.getAlgorithm()); }
/** * Verifies that a clear text password matches a given encoded password hash. * <p> * The password hash is expected to be of the form * <pre> * "{" Base64(salt) "}" passwordHash * </pre> * Where passwordHash is the Base64 encoding of the bytes resulting from applying * the hash function to the byte array consisting of the salt bytes and the UTF-8 * encoding of the clear text password. * * @param rawPassword Password to verify in plain text * @param encodedPassword Encoded password on the record in {Base64(salt)}passwordHash format * @return {@code true} if encoded password hash matches the one on record, {@code false} otherwise * @throws IllegalArgumentException if the encodedPassword does not contain valid Base64 schema. */ @Override public boolean matches(final CharSequence rawPassword, final String encodedPassword) { final EncodedPassword password = new EncodedPassword(encodedPassword); final byte[] digested = digest(password.salt, rawPassword.toString()); final byte[] pwdHash = Base64.getDecoder().decode(password.password); return Arrays.equals(digested, pwdHash); }