|
|
|
@ -526,35 +526,47 @@ public class BCrypt { |
|
|
|
* @param safety bit 16 is set when the safety measure is requested |
|
|
|
* @param safety bit 16 is set when the safety measure is requested |
|
|
|
* @return an array containing the binary hashed password |
|
|
|
* @return an array containing the binary hashed password |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private byte[] crypt_raw(byte password[], byte salt[], int log_rounds, boolean sign_ext_bug, int safety) { |
|
|
|
private byte[] crypt_raw(byte password[], byte salt[], int log_rounds, boolean sign_ext_bug, int safety, |
|
|
|
int rounds, i, j; |
|
|
|
boolean for_check) { |
|
|
|
int cdata[] = bf_crypt_ciphertext.clone(); |
|
|
|
int cdata[] = bf_crypt_ciphertext.clone(); |
|
|
|
int clen = cdata.length; |
|
|
|
int clen = cdata.length; |
|
|
|
byte ret[]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
long rounds; |
|
|
|
if (log_rounds < 4 || log_rounds > 31) { |
|
|
|
if (log_rounds < 4 || log_rounds > 31) { |
|
|
|
|
|
|
|
if (!for_check) { |
|
|
|
|
|
|
|
throw new IllegalArgumentException("Bad number of rounds"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (log_rounds != 0) { |
|
|
|
|
|
|
|
throw new IllegalArgumentException("Bad number of rounds"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
rounds = 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
rounds = roundsForLogRounds(log_rounds); |
|
|
|
|
|
|
|
if (rounds < 16 || rounds > Integer.MAX_VALUE) { |
|
|
|
throw new IllegalArgumentException("Bad number of rounds"); |
|
|
|
throw new IllegalArgumentException("Bad number of rounds"); |
|
|
|
} |
|
|
|
} |
|
|
|
rounds = 1 << log_rounds; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (salt.length != BCRYPT_SALT_LEN) { |
|
|
|
if (salt.length != BCRYPT_SALT_LEN) { |
|
|
|
throw new IllegalArgumentException("Bad salt length"); |
|
|
|
throw new IllegalArgumentException("Bad salt length"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
init_key(); |
|
|
|
init_key(); |
|
|
|
ekskey(salt, password, sign_ext_bug, safety); |
|
|
|
ekskey(salt, password, sign_ext_bug, safety); |
|
|
|
for (i = 0; i < rounds; i++) { |
|
|
|
for (int i = 0; i < rounds; i++) { |
|
|
|
key(password, sign_ext_bug, safety); |
|
|
|
key(password, sign_ext_bug, safety); |
|
|
|
key(salt, false, safety); |
|
|
|
key(salt, false, safety); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 64; i++) { |
|
|
|
for (int i = 0; i < 64; i++) { |
|
|
|
for (j = 0; j < (clen >> 1); j++) { |
|
|
|
for (int j = 0; j < (clen >> 1); j++) { |
|
|
|
encipher(cdata, j << 1); |
|
|
|
encipher(cdata, j << 1); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ret = new byte[clen * 4]; |
|
|
|
byte[] ret = new byte[clen * 4]; |
|
|
|
for (i = 0, j = 0; i < clen; i++) { |
|
|
|
for (int i = 0, j = 0; i < clen; i++) { |
|
|
|
ret[j++] = (byte) ((cdata[i] >> 24) & 0xff); |
|
|
|
ret[j++] = (byte) ((cdata[i] >> 24) & 0xff); |
|
|
|
ret[j++] = (byte) ((cdata[i] >> 16) & 0xff); |
|
|
|
ret[j++] = (byte) ((cdata[i] >> 16) & 0xff); |
|
|
|
ret[j++] = (byte) ((cdata[i] >> 8) & 0xff); |
|
|
|
ret[j++] = (byte) ((cdata[i] >> 8) & 0xff); |
|
|
|
@ -563,6 +575,10 @@ public class BCrypt { |
|
|
|
return ret; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static String hashpwforcheck(byte[] passwordb, String salt) { |
|
|
|
|
|
|
|
return hashpw(passwordb, salt, true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Hash a password using the OpenBSD bcrypt scheme |
|
|
|
* Hash a password using the OpenBSD bcrypt scheme |
|
|
|
* @param password the password to hash |
|
|
|
* @param password the password to hash |
|
|
|
@ -584,6 +600,10 @@ public class BCrypt { |
|
|
|
* @return the hashed password |
|
|
|
* @return the hashed password |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static String hashpw(byte passwordb[], String salt) { |
|
|
|
public static String hashpw(byte passwordb[], String salt) { |
|
|
|
|
|
|
|
return hashpw(passwordb, salt, false); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static String hashpw(byte passwordb[], String salt, boolean for_check) { |
|
|
|
BCrypt B; |
|
|
|
BCrypt B; |
|
|
|
String real_salt; |
|
|
|
String real_salt; |
|
|
|
byte saltb[], hashed[]; |
|
|
|
byte saltb[], hashed[]; |
|
|
|
@ -633,7 +653,7 @@ public class BCrypt { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
B = new BCrypt(); |
|
|
|
B = new BCrypt(); |
|
|
|
hashed = B.crypt_raw(passwordb, saltb, rounds, minor == 'x', minor == 'a' ? 0x10000 : 0); |
|
|
|
hashed = B.crypt_raw(passwordb, saltb, rounds, minor == 'x', minor == 'a' ? 0x10000 : 0, for_check); |
|
|
|
|
|
|
|
|
|
|
|
rs.append("$2"); |
|
|
|
rs.append("$2"); |
|
|
|
if (minor >= 'a') { |
|
|
|
if (minor >= 'a') { |
|
|
|
@ -740,7 +760,8 @@ public class BCrypt { |
|
|
|
* @return true if the passwords match, false otherwise |
|
|
|
* @return true if the passwords match, false otherwise |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static boolean checkpw(String plaintext, String hashed) { |
|
|
|
public static boolean checkpw(String plaintext, String hashed) { |
|
|
|
return equalsNoEarlyReturn(hashed, hashpw(plaintext, hashed)); |
|
|
|
byte[] passwordb = plaintext.getBytes(StandardCharsets.UTF_8); |
|
|
|
|
|
|
|
return equalsNoEarlyReturn(hashed, hashpwforcheck(passwordb, hashed)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -751,7 +772,7 @@ public class BCrypt { |
|
|
|
* @since 5.3 |
|
|
|
* @since 5.3 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static boolean checkpw(byte[] passwordb, String hashed) { |
|
|
|
public static boolean checkpw(byte[] passwordb, String hashed) { |
|
|
|
return equalsNoEarlyReturn(hashed, hashpw(passwordb, hashed)); |
|
|
|
return equalsNoEarlyReturn(hashed, hashpwforcheck(passwordb, hashed)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static boolean equalsNoEarlyReturn(String a, String b) { |
|
|
|
static boolean equalsNoEarlyReturn(String a, String b) { |
|
|
|
|