diff --git a/P/Sda1/HashProvider/src/main/java/de/hdm_stuttgart/mi/sda1/hashprovider/HashProvider.java b/P/Sda1/HashProvider/src/main/java/de/hdm_stuttgart/mi/sda1/hashprovider/HashProvider.java index 2b7fe7644db7ba835bedcddb22abf71e38da9e49..6c8c3d26fec99ae2334a169e9d754c2d9d0dc2db 100644 --- a/P/Sda1/HashProvider/src/main/java/de/hdm_stuttgart/mi/sda1/hashprovider/HashProvider.java +++ b/P/Sda1/HashProvider/src/main/java/de/hdm_stuttgart/mi/sda1/hashprovider/HashProvider.java @@ -20,66 +20,87 @@ import org.apache.logging.log4j.Logger; * */ public class HashProvider { - - static private final Logger log = LogManager.getLogger(HashProvider.class); - - // The higher the number of iterations the more - // expensive computing the hash is for us - // and also for a brute force attack. - private static final int iterations = 10*1024; - private static final int saltLen = 32; - private static final int desiredKeyLen = 256; - /** - * Computes a salted PBKDF2 hash of given plain text password + static final Logger log = LogManager.getLogger(HashProvider.class); + + /** + * Separator between password hash and seed. Consider: + * + * GWTllfNq1vUHaY2iGm+QI1i21fUOEaU7shVvHzNgi+g=$v3juEYYE4fNAqAVnkQLROr8E2hReZHxE2ijpxcey5Yc= + * + * With "$" being the separator token "GWTllfNq1vUHaY2iGm+QI1i21fUOEaU7shVvHzNgi+g=" + * will be the password's hash and "v3juEYYE4fNAqAVnkQLROr8E2hReZHxE2ijpxcey5Yc=" + * its corresponding seed both being base64 encoded. + */ + static public final char separatorToken = '$'; + + // The higher the number of iterations the more + // expensive computing the hash is for us + // and also for a brute force attack. + private static final int iterations = 10*1024; + private static final int saltLen = 32; + private static final int desiredKeyLen = 256; + + /** + * Computes a salted PBKDF2 hash of given plain text password suitable for storing in a database - - * @param password The plain text password - * @return the generated hash separated from salt by "$" - */ - public static String getSaltedHash(char [] password) { + + * @param password The plain text password + * @return the generated hash separated from salt by "$" + */ + public static String getSaltedHash(char [] password) { try { - final byte[] salt = SecureRandom.getInstance("SHA1PRNG").generateSeed(saltLen); + final byte[] salt = + SecureRandom.getInstance("SHA1PRNG").generateSeed(saltLen); // store the salt with the password - return Base64.encodeBase64String(salt) + "$" + hash(password, salt); + return Base64.encodeBase64String(salt) + separatorToken + + hash(password, salt); } catch (final NoSuchAlgorithmException e) { log.fatal("Unable to create hash: " + e); } return null; - } + } - /** - * Checks whether given plain text password corresponds + /** + * Checks whether given plain text password corresponds to a stored salted hash of the password. - * @param password The plain text password - * @param stored the salt/hash to be verified against - * @return true if input matches, false otherwise - */ - public static boolean check(char[] password, String stored){ - final String[] saltAndPass = stored.split("\\$"); - if (saltAndPass.length != 2) { - log.error("No salt detected!"); - return false; - } else { - final String hashOfInput = hash(password, Base64.decodeBase64(saltAndPass[0])); - return null != hashOfInput && hashOfInput.equals(saltAndPass[1]); - } - } + * @param password The plain text password + * @param stored the salt/hash to be verified against + * @return true if input matches, false otherwise + */ + public static boolean check(final char[] password, final String stored) { + + if (null == password || null == stored) { + return false; + } else { // Find hash / seed separator token + final int separatorPosition = stored.indexOf(separatorToken); - // using PBKDF2 from Sun, an alternative is https://github.com/wg/scrypt - // cf. http://www.unlimitednovelty.com/2012/03/dont-use-bcrypt.html - private static String hash(char [] password, byte[] salt) { + if (separatorPosition < 0) { + log.info("No salt detected!"); + return false; + } else { + final String hashOfInput = hash(password,Base64.decodeBase64( + stored.substring(0, separatorPosition))); + return null != hashOfInput && hashOfInput.equals( + stored.substring(1 + separatorPosition)); + } + } + } + + // using PBKDF2 from Sun, an alternative is https://github.com/wg/scrypt + // cf. http://www.unlimitednovelty.com/2012/03/dont-use-bcrypt.html + private static String hash(char [] password, byte[] salt) { try { - final SecretKey key = - SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret( - new PBEKeySpec(password, salt, iterations, desiredKeyLen)); - + final SecretKey key = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"). + generateSecret( + new PBEKeySpec(password, salt, iterations, desiredKeyLen)); + return Base64.encodeBase64String(key.getEncoded()); - } catch (NoSuchAlgorithmException e) { + } catch (final NoSuchAlgorithmException e) { log.fatal("Unable to create hash: " + e); - } catch (InvalidKeySpecException e) { + } catch (final InvalidKeySpecException e) { log.fatal("Unable to create hash: " + e); } return null; - } + } } \ No newline at end of file diff --git a/P/Sda1/HashProvider/src/main/resources/log4j2.xml b/P/Sda1/HashProvider/src/main/resources/log4j2.xml index 8856705274a36926428cf3e5958f57f3ce8b3c21..cc36ed921c978bbd495ef9531f3ab700a7b8096f 100644 --- a/P/Sda1/HashProvider/src/main/resources/log4j2.xml +++ b/P/Sda1/HashProvider/src/main/resources/log4j2.xml @@ -14,7 +14,7 @@ <Logger name="de.hdm_stuttgart.mi.sda1.alignimg.App" level="warn"> <AppenderRef ref="A1"/> </Logger> - <Root level="warn"> + <Root level="info"> <AppenderRef ref="STDOUT"/> </Root> </Loggers> diff --git a/P/Sda1/HashProvider/src/test/java/de/hdm_stuttgart/mi/sda1/hashprovider/test/TestDecrypt.java b/P/Sda1/HashProvider/src/test/java/de/hdm_stuttgart/mi/sda1/hashprovider/test/TestDecrypt.java index e794b3a697fa67ce676843d5d356b5f60c96a791..9ac81d9323871be8b10494c45e97410b81c41d74 100644 --- a/P/Sda1/HashProvider/src/test/java/de/hdm_stuttgart/mi/sda1/hashprovider/test/TestDecrypt.java +++ b/P/Sda1/HashProvider/src/test/java/de/hdm_stuttgart/mi/sda1/hashprovider/test/TestDecrypt.java @@ -18,5 +18,6 @@ public class TestDecrypt { System.out.println(saltedHash); Assert.assertTrue(HashProvider.check(clearText.toCharArray(), saltedHash)); + Assert.assertFalse(HashProvider.check(clearText.toCharArray(), "noDollarSeparatorSign")); } }