diff --git a/src/main/java/org/mindrot/jbcrypt/BCrypt.java b/src/main/java/org/mindrot/jbcrypt/BCrypt.java index 3a1dca1..49530e9 100755 --- a/src/main/java/org/mindrot/jbcrypt/BCrypt.java +++ b/src/main/java/org/mindrot/jbcrypt/BCrypt.java @@ -770,6 +770,61 @@ public static boolean checkpw(String plaintext, String hashed) { return equalsNoEarlyReturn(hashed, hashpw(plaintext, hashed)); } + /** + * Retrieve the salt from a hashed password + * @param hashed the previously-hashed password + * @return the salt the password has been hashed with + */ + public static String getsalt(String hashed) { + int minor, off; + if (hashed.charAt(0) != '$' || hashed.charAt(1) != '2') { + throw new IllegalArgumentException("Invalid salt version"); + } + if (hashed.charAt(2) == '$') { + off = 3; + } else { + minor = hashed.charAt(2); + if (minor != 'a' || hashed.charAt(3) != '$') { + throw new IllegalArgumentException("Invalid salt revision"); + } + off = 4; + } + if (hashed.charAt(off + 2) != '$') { + throw new IllegalArgumentException("Missing salt rounds"); + } + if (hashed.length() - off < 25) { + throw new IllegalArgumentException("Invalid salt"); + } + return hashed.substring(0, off + 25); + } + + /** + * Retrieve the log2 of the number of rounds of hashing applied + * @param saltOrHashed the salt generated by BCrypt.gensalt() or + * the previously-hashed password + * @return the log2 of the number of rounds of hashing applied. + */ + public static int getlogrounds(String saltOrHashed) { + int log_rounds, minor, off; + if (saltOrHashed.charAt(0) != '$' || saltOrHashed.charAt(1) != '2') { + throw new IllegalArgumentException("Invalid saltOrHashed version"); + } + if (saltOrHashed.charAt(2) == '$') { + off = 3; + } else { + minor = saltOrHashed.charAt(2); + if (minor != 'a' || saltOrHashed.charAt(3) != '$') { + throw new IllegalArgumentException("Invalid saltOrHashed revision"); + } + off = 4; + } + if (saltOrHashed.charAt(off + 2) != '$') { + throw new IllegalArgumentException("Missing saltOrHashed rounds"); + } + log_rounds = Integer.parseInt(saltOrHashed.substring(off, off + 2)); + return log_rounds; + } + static boolean equalsNoEarlyReturn(String a, String b) { char[] caa = a.toCharArray(); char[] cab = b.toCharArray(); diff --git a/src/test/java/org/mindrot/jbcrypt/BCryptTest.java b/src/test/java/org/mindrot/jbcrypt/BCryptTest.java index 30cf35a..7bcb1cd 100755 --- a/src/test/java/org/mindrot/jbcrypt/BCryptTest.java +++ b/src/test/java/org/mindrot/jbcrypt/BCryptTest.java @@ -341,4 +341,31 @@ public void equalsOnStringsIsCorrect() assertFalse(BCrypt.equalsNoEarlyReturn("test", "pass")); } + + @Test + public void testGetSalt() + { + String password = "password"; + String salt = BCrypt.gensalt(); + String hashedPassword = BCrypt.hashpw(password, salt); + assertEquals(salt, BCrypt.getsalt(hashedPassword)); + } + + @Test + public void testGetLogRoundsFromSalt() + { + int logRounds = 11; + String salt = BCrypt.gensalt(logRounds); + assertEquals(logRounds, BCrypt.getlogrounds(salt)); + } + + @Test + public void testGetLogRoundsFromHashed() + { + String password = "password"; + int logRounds = 11; + String salt = BCrypt.gensalt(logRounds); + String hashed = BCrypt.hashpw(password, salt); + assertEquals(logRounds, BCrypt.getlogrounds(hashed)); + } }