Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions src/main/java/org/mindrot/jbcrypt/BCrypt.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
27 changes: 27 additions & 0 deletions src/test/java/org/mindrot/jbcrypt/BCryptTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}