|
|
@ -3,7 +3,6 @@ package com.epmet.commons.tools.security.password; |
|
|
|
import java.io.ByteArrayOutputStream; |
|
|
|
import java.io.UnsupportedEncodingException; |
|
|
|
|
|
|
|
import java.nio.charset.StandardCharsets; |
|
|
|
import java.security.SecureRandom; |
|
|
|
|
|
|
|
/** |
|
|
@ -53,11 +52,11 @@ public class BCrypt { |
|
|
|
// Blowfish parameters
|
|
|
|
private static final int BLOWFISH_NUM_ROUNDS = 16; |
|
|
|
// Initial contents of key schedule
|
|
|
|
private static final int[] P_orig = { 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, |
|
|
|
private static final int P_orig[] = { 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, |
|
|
|
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, |
|
|
|
0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, |
|
|
|
0x9216d5d9, 0x8979fb1b }; |
|
|
|
private static final int[] S_orig = { 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, |
|
|
|
private static final int S_orig[] = { 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, |
|
|
|
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, |
|
|
|
0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, |
|
|
|
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, |
|
|
@ -229,16 +228,16 @@ public class BCrypt { |
|
|
|
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, |
|
|
|
0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 }; |
|
|
|
// bcrypt IV: "OrpheanBeholderScryDoubt"
|
|
|
|
static private final int[] bf_crypt_ciphertext = { 0x4f727068, 0x65616e42, |
|
|
|
static private final int bf_crypt_ciphertext[] = { 0x4f727068, 0x65616e42, |
|
|
|
0x65686f6c, 0x64657253, 0x63727944, 0x6f756274 }; |
|
|
|
// Table for Base64 encoding
|
|
|
|
static private final char[] base64_code = { '.', '/', 'A', 'B', 'C', 'D', 'E', 'F', |
|
|
|
static private final char base64_code[] = { '.', '/', 'A', 'B', 'C', 'D', 'E', 'F', |
|
|
|
'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', |
|
|
|
'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', |
|
|
|
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', |
|
|
|
'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; |
|
|
|
// Table for Base64 decoding
|
|
|
|
static private final byte[] index_64 = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
|
|
static private final byte index_64[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 54, 55, |
|
|
|
56, 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, 2, 3, 4, 5, 6, 7, |
|
|
@ -248,8 +247,8 @@ public class BCrypt { |
|
|
|
static final int MIN_LOG_ROUNDS = 4; |
|
|
|
static final int MAX_LOG_ROUNDS = 31; |
|
|
|
// Expanded Blowfish key
|
|
|
|
private int[] P; |
|
|
|
private int[] S; |
|
|
|
private int P[]; |
|
|
|
private int S[]; |
|
|
|
|
|
|
|
/** |
|
|
|
* Encode a byte array using bcrypt's slightly-modified base64 encoding scheme. Note |
|
|
@ -261,7 +260,7 @@ public class BCrypt { |
|
|
|
* @param rs the destination buffer for the base64-encoded string |
|
|
|
* @exception IllegalArgumentException if the length is invalid |
|
|
|
*/ |
|
|
|
static void encode_base64(byte[] d, int len, StringBuilder rs) |
|
|
|
static void encode_base64(byte d[], int len, StringBuilder rs) |
|
|
|
throws IllegalArgumentException { |
|
|
|
int off = 0; |
|
|
|
int c1, c2; |
|
|
@ -360,7 +359,7 @@ public class BCrypt { |
|
|
|
* @param lr an array containing the two 32-bit half blocks |
|
|
|
* @param off the position in the array of the blocks |
|
|
|
*/ |
|
|
|
private final void encipher(int[] lr, int off) { |
|
|
|
private final void encipher(int lr[], int off) { |
|
|
|
int i, n, l = lr[off], r = lr[off + 1]; |
|
|
|
|
|
|
|
l ^= P[0]; |
|
|
@ -389,7 +388,7 @@ public class BCrypt { |
|
|
|
* @param offp a "pointer" (as a one-entry array) to the current offset into data |
|
|
|
* @return the next word of material from data |
|
|
|
*/ |
|
|
|
private static int streamtoword(byte[] data, int[] offp) { |
|
|
|
private static int streamtoword(byte data[], int offp[]) { |
|
|
|
int i; |
|
|
|
int word = 0; |
|
|
|
int off = offp[0]; |
|
|
@ -407,18 +406,18 @@ public class BCrypt { |
|
|
|
* Initialise the Blowfish key schedule |
|
|
|
*/ |
|
|
|
private void init_key() { |
|
|
|
P = P_orig.clone(); |
|
|
|
S = S_orig.clone(); |
|
|
|
P = (int[]) P_orig.clone(); |
|
|
|
S = (int[]) S_orig.clone(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Key the Blowfish cipher |
|
|
|
* @param key an array containing the key |
|
|
|
*/ |
|
|
|
private void key(byte[] key) { |
|
|
|
private void key(byte key[]) { |
|
|
|
int i; |
|
|
|
int[] koffp = { 0 }; |
|
|
|
int[] lr = { 0, 0 }; |
|
|
|
int koffp[] = { 0 }; |
|
|
|
int lr[] = { 0, 0 }; |
|
|
|
int plen = P.length, slen = S.length; |
|
|
|
|
|
|
|
for (i = 0; i < plen; i++) { |
|
|
@ -444,11 +443,10 @@ public class BCrypt { |
|
|
|
* @param data salt information |
|
|
|
* @param key password information |
|
|
|
*/ |
|
|
|
private void ekskey(byte[] data, byte[] key) { |
|
|
|
private void ekskey(byte data[], byte key[]) { |
|
|
|
int i; |
|
|
|
int[] koffp = { 0 }; |
|
|
|
int[] doffp = { 0 }; |
|
|
|
int[] lr = { 0, 0 }; |
|
|
|
int koffp[] = { 0 }, doffp[] = { 0 }; |
|
|
|
int lr[] = { 0, 0 }; |
|
|
|
int plen = P.length, slen = S.length; |
|
|
|
|
|
|
|
for (i = 0; i < plen; i++) { |
|
|
@ -486,10 +484,10 @@ public class BCrypt { |
|
|
|
* @param log_rounds the binary logarithm of the number of rounds of hashing to apply |
|
|
|
* @return an array containing the binary hashed password |
|
|
|
*/ |
|
|
|
private byte[] crypt_raw(byte[] password, byte[] salt, int log_rounds) { |
|
|
|
int[] cdata = bf_crypt_ciphertext.clone(); |
|
|
|
private byte[] crypt_raw(byte password[], byte salt[], int log_rounds) { |
|
|
|
int cdata[] = (int[]) bf_crypt_ciphertext.clone(); |
|
|
|
int clen = cdata.length; |
|
|
|
byte[] ret; |
|
|
|
byte ret[]; |
|
|
|
|
|
|
|
long rounds = roundsForLogRounds(log_rounds); |
|
|
|
|
|
|
@ -526,9 +524,7 @@ public class BCrypt { |
|
|
|
public static String hashpw(String password, String salt) throws IllegalArgumentException { |
|
|
|
BCrypt B; |
|
|
|
String real_salt; |
|
|
|
byte[] passwordb; |
|
|
|
byte[] saltb; |
|
|
|
byte[] hashed; |
|
|
|
byte passwordb[], saltb[], hashed[]; |
|
|
|
char minor = (char) 0; |
|
|
|
int rounds, off = 0; |
|
|
|
StringBuilder rs = new StringBuilder(); |
|
|
@ -568,7 +564,12 @@ public class BCrypt { |
|
|
|
rounds = Integer.parseInt(salt.substring(off, off + 2)); |
|
|
|
|
|
|
|
real_salt = salt.substring(off + 3, off + 25); |
|
|
|
passwordb = (password + (minor >= 'a' ? "\000" : "")).getBytes(StandardCharsets.UTF_8); |
|
|
|
try { |
|
|
|
passwordb = (password + (minor >= 'a' ? "\000" : "")).getBytes("UTF-8"); |
|
|
|
} |
|
|
|
catch (UnsupportedEncodingException uee) { |
|
|
|
throw new AssertionError("UTF-8 is not supported"); |
|
|
|
} |
|
|
|
|
|
|
|
saltb = decode_base64(real_salt, BCRYPT_SALT_LEN); |
|
|
|
|
|
|
@ -602,7 +603,7 @@ public class BCrypt { |
|
|
|
throw new IllegalArgumentException("Bad number of rounds"); |
|
|
|
} |
|
|
|
StringBuilder rs = new StringBuilder(); |
|
|
|
byte[] rnd = new byte[BCRYPT_SALT_LEN]; |
|
|
|
byte rnd[] = new byte[BCRYPT_SALT_LEN]; |
|
|
|
|
|
|
|
random.nextBytes(rnd); |
|
|
|
|
|
|
|