package auth; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.util.Arrays; import exceptions.PoseidonException; import org.apache.commons.codec.binary.Base64; import play.mvc.Http; public class PasswordHasher { public PasswordHash createHash(String givenPassword) throws NoSuchAlgorithmException, InvalidKeySpecException { String defaultAlgorithm = "PBKDF2WithHmacSHA1"; int defaultIterations = 20000; byte[] salt = generateSalt(); byte[] encrypted = getEncryptedPassword(givenPassword, salt, defaultAlgorithm, defaultIterations); return new PasswordHash(defaultAlgorithm, defaultIterations, Base64.encodeBase64String(salt), Base64.encodeBase64String(encrypted)); } public boolean authenticate(String attemptedPassword, PasswordHash storedHash) { byte[] encryptedAttemptedPassword; try { encryptedAttemptedPassword = getEncryptedPassword(attemptedPassword, Base64.decodeBase64(storedHash.salt), storedHash.algorithm, storedHash.iterations); } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { throw new PoseidonException(Http.Status.INTERNAL_SERVER_ERROR,e.getMessage()); } return Arrays.equals(Base64.decodeBase64(storedHash.hash), encryptedAttemptedPassword); } public byte[] getEncryptedPassword(String password, byte[] salt, String algorithm, int iterations) throws NoSuchAlgorithmException, InvalidKeySpecException { int derivedKeyLength = 160; KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, derivedKeyLength); SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm); return f.generateSecret(spec).getEncoded(); } public byte[] generateSalt() throws NoSuchAlgorithmException { SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); byte[] salt = new byte[8]; random.nextBytes(salt); return salt; } }