From 07837098eb1d989ece5ac737a2ad5184e5fa3aeb Mon Sep 17 00:00:00 2001 From: exceptionfactory Date: Fri, 14 Jul 2023 08:39:18 -0500 Subject: [PATCH] Removed unused bcrypt password hashing methods (#852) Co-authored-by: Jeroen van Erp --- .../userauth/keyprovider/bcrypt/BCrypt.java | 379 +----------------- .../keyprovider/bcrypt/BCryptTest.java | 164 -------- 2 files changed, 14 insertions(+), 529 deletions(-) diff --git a/src/main/java/com/hierynomus/sshj/userauth/keyprovider/bcrypt/BCrypt.java b/src/main/java/com/hierynomus/sshj/userauth/keyprovider/bcrypt/BCrypt.java index 78b3fcc7..205899c8 100644 --- a/src/main/java/com/hierynomus/sshj/userauth/keyprovider/bcrypt/BCrypt.java +++ b/src/main/java/com/hierynomus/sshj/userauth/keyprovider/bcrypt/BCrypt.java @@ -14,11 +14,9 @@ package com.hierynomus.sshj.userauth.keyprovider.bcrypt; -import java.io.UnsupportedEncodingException; import java.security.DigestException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; /** * BCrypt implements OpenBSD-style Blowfish password hashing using @@ -30,32 +28,6 @@ import java.security.SecureRandom; * based on Bruce Schneier's Blowfish cipher. The work factor of * the algorithm is parameterised, so it can be increased as * computers get faster. - *

- * Usage is really simple. To hash a password for the first time, - * call the hashpw method with a random salt, like this: - *

- * - * String pw_hash = BCrypt.hashpw(plain_password, BCrypt.gensalt());
- *
- *

- * To check whether a plaintext password matches one that has been - * hashed previously, use the checkpw method: - *

- * - * if (BCrypt.checkpw(candidate_password, stored_hash))
- *     System.out.println("It matches");
- * else
- *     System.out.println("It does not match");
- *
- *

- * The gensalt() method takes an optional parameter (log_rounds) - * that determines the computational complexity of the hashing: - *

- * - * String strong_salt = BCrypt.gensalt(10)
- * String stronger_salt = BCrypt.gensalt(12)
- *
- *

* The amount of work increases exponentially (2**log_rounds), so * each increment is twice as much work. The default log_rounds is * 10, and the valid range is 4 to 30. @@ -64,22 +36,18 @@ import java.security.SecureRandom; * @version 0.2 */ public class BCrypt { - // BCrypt parameters - private static final int GENSALT_DEFAULT_LOG2_ROUNDS = 10; - private static final int BCRYPT_SALT_LEN = 16; - // Blowfish parameters private static final int BLOWFISH_NUM_ROUNDS = 16; // Initial contents of key schedule - private static final int P_orig[] = { + 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[] = { + private static final int[] S_orig = { 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, @@ -344,149 +312,9 @@ public class BCrypt { 0x66697368, 0x53776174, 0x44796e61, 0x6d697465, }; - // bcrypt IV: "OrpheanBeholderScryDoubt". The C implementation calls - // this "ciphertext", but it is really plaintext or an IV. We keep - // the name to make code comparison easier. - 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', '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, -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, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - -1, -1, -1, -1, -1, -1, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, -1, -1, -1, -1, -1 - }; - // Expanded Blowfish key - private int P[]; - private int S[]; - - /** - * Encode a byte array using bcrypt's slightly-modified base64 - * encoding scheme. Note that this is *not* compatible with - * the standard MIME-base64 encoding. - * - * @param d the byte array to encode - * @param len the number of bytes to encode - * @return base64-encoded string - * @exception IllegalArgumentException if the length is invalid - */ - private static String encode_base64(byte d[], int len) - throws IllegalArgumentException { - int off = 0; - StringBuffer rs = new StringBuffer(); - int c1, c2; - - if (len <= 0 || len > d.length) - throw new IllegalArgumentException ("Invalid len"); - - while (off < len) { - c1 = d[off++] & 0xff; - rs.append(base64_code[(c1 >> 2) & 0x3f]); - c1 = (c1 & 0x03) << 4; - if (off >= len) { - rs.append(base64_code[c1 & 0x3f]); - break; - } - c2 = d[off++] & 0xff; - c1 |= (c2 >> 4) & 0x0f; - rs.append(base64_code[c1 & 0x3f]); - c1 = (c2 & 0x0f) << 2; - if (off >= len) { - rs.append(base64_code[c1 & 0x3f]); - break; - } - c2 = d[off++] & 0xff; - c1 |= (c2 >> 6) & 0x03; - rs.append(base64_code[c1 & 0x3f]); - rs.append(base64_code[c2 & 0x3f]); - } - return rs.toString(); - } - - /** - * Look up the 3 bits base64-encoded by the specified character, - * range-checking againt conversion table - * @param x the base64-encoded value - * @return the decoded value of x - */ - private static byte char64(char x) { - if ((int)x < 0 || (int)x > index_64.length) - return -1; - return index_64[(int)x]; - } - - /** - * Decode a string encoded using bcrypt's base64 scheme to a - * byte array. Note that this is *not* compatible with - * the standard MIME-base64 encoding. - * @param s the string to decode - * @param maxolen the maximum number of bytes to decode - * @return an array containing the decoded bytes - * @throws IllegalArgumentException if maxolen is invalid - */ - private static byte[] decode_base64(String s, int maxolen) - throws IllegalArgumentException { - StringBuffer rs = new StringBuffer(); - int off = 0, slen = s.length(), olen = 0; - byte ret[]; - byte c1, c2, c3, c4, o; - - if (maxolen <= 0) - throw new IllegalArgumentException ("Invalid maxolen"); - - while (off < slen - 1 && olen < maxolen) { - c1 = char64(s.charAt(off++)); - c2 = char64(s.charAt(off++)); - if (c1 == -1 || c2 == -1) - break; - o = (byte)(c1 << 2); - o |= (c2 & 0x30) >> 4; - rs.append((char)o); - if (++olen >= maxolen || off >= slen) - break; - c3 = char64(s.charAt(off++)); - if (c3 == -1) - break; - o = (byte)((c2 & 0x0f) << 4); - o |= (c3 & 0x3c) >> 2; - rs.append((char)o); - if (++olen >= maxolen || off >= slen) - break; - c4 = char64(s.charAt(off++)); - o = (byte)((c3 & 0x03) << 6); - o |= c4; - rs.append((char)o); - ++olen; - } - - ret = new byte[olen]; - for (off = 0; off < olen; off++) - ret[off] = (byte)rs.charAt(off); - return ret; - } + private int[] P; + private int[] S; /** * Blowfish encipher a single 64-bit block encoded as @@ -494,7 +322,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 void encipher(int[] lr, int off) { int i, n, l = lr[off], r = lr[off + 1]; l ^= P[0]; @@ -524,7 +352,7 @@ public class BCrypt { * 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]; @@ -542,18 +370,18 @@ public class BCrypt { * Initialise the Blowfish key schedule */ private void init_key() { - P = (int[])P_orig.clone(); - S = (int[])S_orig.clone(); + P = P_orig.clone(); + S = 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++) @@ -579,10 +407,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 }, 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++) @@ -687,183 +515,4 @@ public class BCrypt { throw new RuntimeException(e); } } - - /** - * Perform the central password hashing step in the - * bcrypt scheme - * @param password the password to hash - * @param salt the binary salt to hash with the password - * @param log_rounds the binary logarithm of the number - * of rounds of hashing to apply - * @param cdata the plaintext to encrypt - * @return an array containing the binary hashed password - */ - public byte[] crypt_raw(byte password[], byte salt[], int log_rounds, - int cdata[]) { - int rounds, i, j; - int clen = cdata.length; - byte ret[]; - - if (log_rounds < 4 || log_rounds > 30) - throw new IllegalArgumentException ("Bad number of rounds"); - rounds = 1 << log_rounds; - if (salt.length != BCRYPT_SALT_LEN) - throw new IllegalArgumentException ("Bad salt length"); - - init_key(); - ekskey(salt, password); - for (i = 0; i != rounds; i++) { - key(password); - key(salt); - } - - for (i = 0; i < 64; i++) { - for (j = 0; j < (clen >> 1); j++) - encipher(cdata, j << 1); - } - - ret = new byte[clen * 4]; - for (i = 0, j = 0; i < clen; i++) { - ret[j++] = (byte)((cdata[i] >> 24) & 0xff); - ret[j++] = (byte)((cdata[i] >> 16) & 0xff); - ret[j++] = (byte)((cdata[i] >> 8) & 0xff); - ret[j++] = (byte)(cdata[i] & 0xff); - } - return ret; - } - - /** - * Hash a password using the OpenBSD bcrypt scheme - * @param password the password to hash - * @param salt the salt to hash with (perhaps generated - * using BCrypt.gensalt) - * @return the hashed password - */ - public static String hashpw(String password, String salt) { - BCrypt B; - String real_salt; - byte passwordb[], saltb[], hashed[]; - char minor = (char)0; - int rounds, off = 0; - StringBuffer rs = new StringBuffer(); - - if (salt.charAt(0) != '$' || salt.charAt(1) != '2') - throw new IllegalArgumentException ("Invalid salt version"); - if (salt.charAt(2) == '$') - off = 3; - else { - minor = salt.charAt(2); - if (minor != 'a' || salt.charAt(3) != '$') - throw new IllegalArgumentException ("Invalid salt revision"); - off = 4; - } - - // Extract number of rounds - if (salt.charAt(off + 2) > '$') - throw new IllegalArgumentException ("Missing salt rounds"); - rounds = Integer.parseInt(salt.substring(off, off + 2)); - - real_salt = salt.substring(off + 3, off + 25); - 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); - - B = new BCrypt(); - hashed = B.crypt_raw(passwordb, saltb, rounds, - (int[])bf_crypt_ciphertext.clone()); - - rs.append("$2"); - if (minor >= 'a') - rs.append(minor); - rs.append("$"); - if (rounds < 10) - rs.append("0"); - if (rounds > 30) { - throw new IllegalArgumentException( - "rounds exceeds maximum (30)"); - } - rs.append(Integer.toString(rounds)); - rs.append("$"); - rs.append(encode_base64(saltb, saltb.length)); - rs.append(encode_base64(hashed, - bf_crypt_ciphertext.length * 4 - 1)); - return rs.toString(); - } - - /** - * Generate a salt for use with the BCrypt.hashpw() method - * @param log_rounds the log2 of the number of rounds of - * hashing to apply - the work factor therefore increases as - * 2**log_rounds. - * @param random an instance of SecureRandom to use - * @return an encoded salt value - */ - public static String gensalt(int log_rounds, SecureRandom random) { - StringBuffer rs = new StringBuffer(); - byte rnd[] = new byte[BCRYPT_SALT_LEN]; - - random.nextBytes(rnd); - - rs.append("$2a$"); - if (log_rounds < 10) - rs.append("0"); - if (log_rounds > 30) { - throw new IllegalArgumentException( - "log_rounds exceeds maximum (30)"); - } - rs.append(Integer.toString(log_rounds)); - rs.append("$"); - rs.append(encode_base64(rnd, rnd.length)); - return rs.toString(); - } - - /** - * Generate a salt for use with the BCrypt.hashpw() method - * @param log_rounds the log2 of the number of rounds of - * hashing to apply - the work factor therefore increases as - * 2**log_rounds. - * @return an encoded salt value - */ - public static String gensalt(int log_rounds) { - return gensalt(log_rounds, new SecureRandom()); - } - - /** - * Generate a salt for use with the BCrypt.hashpw() method, - * selecting a reasonable default for the number of hashing - * rounds to apply - * @return an encoded salt value - */ - public static String gensalt() { - return gensalt(GENSALT_DEFAULT_LOG2_ROUNDS); - } - - /** - * Check that a plaintext password matches a previously hashed - * one - * @param plaintext the plaintext password to verify - * @param hashed the previously-hashed password - * @return true if the passwords match, false otherwise - */ - public static boolean checkpw(String plaintext, String hashed) { - byte hashed_bytes[]; - byte try_bytes[]; - try { - String try_pw = hashpw(plaintext, hashed); - hashed_bytes = hashed.getBytes("UTF-8"); - try_bytes = try_pw.getBytes("UTF-8"); - } catch (UnsupportedEncodingException uee) { - return false; - } - if (hashed_bytes.length != try_bytes.length) - return false; - byte ret = 0; - for (int i = 0; i < try_bytes.length; i++) - ret |= hashed_bytes[i] ^ try_bytes[i]; - return ret == 0; - } } diff --git a/src/test/java/com/hierynomus/sshj/userauth/keyprovider/bcrypt/BCryptTest.java b/src/test/java/com/hierynomus/sshj/userauth/keyprovider/bcrypt/BCryptTest.java index 7fd350ca..50bb3c7d 100644 --- a/src/test/java/com/hierynomus/sshj/userauth/keyprovider/bcrypt/BCryptTest.java +++ b/src/test/java/com/hierynomus/sshj/userauth/keyprovider/bcrypt/BCryptTest.java @@ -19,8 +19,6 @@ import org.junit.Test; import java.util.Arrays; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; /** * JUnit unit tests for BCrypt routines @@ -28,168 +26,6 @@ import static org.junit.Assert.assertTrue; * @version 0.2 */ public class BCryptTest { - String[][] test_vectors = { - { "", - "$2a$06$DCq7YPn5Rq63x1Lad4cll.", - "$2a$06$DCq7YPn5Rq63x1Lad4cll.TV4S6ytwfsfvkgY8jIucDrjc8deX1s." }, - { "", - "$2a$08$HqWuK6/Ng6sg9gQzbLrgb.", - "$2a$08$HqWuK6/Ng6sg9gQzbLrgb.Tl.ZHfXLhvt/SgVyWhQqgqcZ7ZuUtye" }, - { "", - "$2a$10$k1wbIrmNyFAPwPVPSVa/ze", - "$2a$10$k1wbIrmNyFAPwPVPSVa/zecw2BCEnBwVS2GbrmgzxFUOqW9dk4TCW" }, - { "", - "$2a$12$k42ZFHFWqBp3vWli.nIn8u", - "$2a$12$k42ZFHFWqBp3vWli.nIn8uYyIkbvYRvodzbfbK18SSsY.CsIQPlxO" }, - { "a", - "$2a$06$m0CrhHm10qJ3lXRY.5zDGO", - "$2a$06$m0CrhHm10qJ3lXRY.5zDGO3rS2KdeeWLuGmsfGlMfOxih58VYVfxe" }, - { "a", - "$2a$08$cfcvVd2aQ8CMvoMpP2EBfe", - "$2a$08$cfcvVd2aQ8CMvoMpP2EBfeodLEkkFJ9umNEfPD18.hUF62qqlC/V." }, - { "a", - "$2a$10$k87L/MF28Q673VKh8/cPi.", - "$2a$10$k87L/MF28Q673VKh8/cPi.SUl7MU/rWuSiIDDFayrKk/1tBsSQu4u" }, - { "a", - "$2a$12$8NJH3LsPrANStV6XtBakCe", - "$2a$12$8NJH3LsPrANStV6XtBakCez0cKHXVxmvxIlcz785vxAIZrihHZpeS" }, - { "abc", - "$2a$06$If6bvum7DFjUnE9p2uDeDu", - "$2a$06$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i" }, - { "abc", - "$2a$08$Ro0CUfOqk6cXEKf3dyaM7O", - "$2a$08$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm" }, - { "abc", - "$2a$10$WvvTPHKwdBJ3uk0Z37EMR.", - "$2a$10$WvvTPHKwdBJ3uk0Z37EMR.hLA2W6N9AEBhEgrAOljy2Ae5MtaSIUi" }, - { "abc", - "$2a$12$EXRkfkdmXn2gzds2SSitu.", - "$2a$12$EXRkfkdmXn2gzds2SSitu.MW9.gAVqa9eLS1//RYtYCmB1eLHg.9q" }, - { "abcdefghijklmnopqrstuvwxyz", - "$2a$06$.rCVZVOThsIa97pEDOxvGu", - "$2a$06$.rCVZVOThsIa97pEDOxvGuRRgzG64bvtJ0938xuqzv18d3ZpQhstC" }, - { "abcdefghijklmnopqrstuvwxyz", - "$2a$08$aTsUwsyowQuzRrDqFflhge", - "$2a$08$aTsUwsyowQuzRrDqFflhgekJ8d9/7Z3GV3UcgvzQW3J5zMyrTvlz." }, - { "abcdefghijklmnopqrstuvwxyz", - "$2a$10$fVH8e28OQRj9tqiDXs1e1u", - "$2a$10$fVH8e28OQRj9tqiDXs1e1uxpsjN0c7II7YPKXua2NAKYvM6iQk7dq" }, - { "abcdefghijklmnopqrstuvwxyz", - "$2a$12$D4G5f18o7aMMfwasBL7Gpu", - "$2a$12$D4G5f18o7aMMfwasBL7GpuQWuP3pkrZrOAnqP.bmezbMng.QwJ/pG" }, - { "~!@#$%^&*() ~!@#$%^&*()PNBFRD", - "$2a$06$fPIsBO8qRqkjj273rfaOI.", - "$2a$06$fPIsBO8qRqkjj273rfaOI.HtSV9jLDpTbZn782DC6/t7qT67P6FfO" }, - { "~!@#$%^&*() ~!@#$%^&*()PNBFRD", - "$2a$08$Eq2r4G/76Wv39MzSX262hu", - "$2a$08$Eq2r4G/76Wv39MzSX262huzPz612MZiYHVUJe/OcOql2jo4.9UxTW" }, - { "~!@#$%^&*() ~!@#$%^&*()PNBFRD", - "$2a$10$LgfYWkbzEvQ4JakH7rOvHe", - "$2a$10$LgfYWkbzEvQ4JakH7rOvHe0y8pHKF9OaFgwUZ2q7W2FFZmZzJYlfS" }, - { "~!@#$%^&*() ~!@#$%^&*()PNBFRD", - "$2a$12$WApznUOJfkEGSmYRfnkrPO", - "$2a$12$WApznUOJfkEGSmYRfnkrPOr466oFDCaj4b6HY3EXGvfxm43seyhgC" }, - }; - - /** - * Test method for 'BCrypt.hashpw(String, String)' - */ - @Test - public void testHashpw() { - System.out.print("BCrypt.hashpw(): "); - for (int i = 0; i < test_vectors.length; i++) { - String plain = test_vectors[i][0]; - String salt = test_vectors[i][1]; - String expected = test_vectors[i][2]; - String hashed = BCrypt.hashpw(plain, salt); - assertEquals(hashed, expected); - System.out.print("."); - } - } - - /** - * Test method for 'BCrypt.gensalt(int)' - */ - @Test - public void testGensaltInt() { - System.out.print("BCrypt.gensalt(log_rounds):"); - for (int i = 4; i <= 12; i++) { - System.out.print(" " + i + ":"); - for (int j = 0; j < test_vectors.length; j += 4) { - String plain = test_vectors[j][0]; - String salt = BCrypt.gensalt(i); - String hashed1 = BCrypt.hashpw(plain, salt); - String hashed2 = BCrypt.hashpw(plain, hashed1); - assertEquals(hashed1, hashed2); - System.out.print("."); - } - } - } - - /** - * Test method for 'BCrypt.gensalt()' - */ - @Test - public void testGensalt() { - System.out.print("BCrypt.gensalt(): "); - for (int i = 0; i < test_vectors.length; i += 4) { - String plain = test_vectors[i][0]; - String salt = BCrypt.gensalt(); - String hashed1 = BCrypt.hashpw(plain, salt); - String hashed2 = BCrypt.hashpw(plain, hashed1); - assertEquals(hashed1, hashed2); - System.out.print("."); - } - } - - /** - * Test method for 'BCrypt.checkpw(String, String)' - * expecting success - */ - @Test - public void testCheckpw_success() { - System.out.print("BCrypt.checkpw w/ good passwords: "); - for (int i = 0; i < test_vectors.length; i++) { - String plain = test_vectors[i][0]; - String expected = test_vectors[i][2]; - assertTrue(BCrypt.checkpw(plain, expected)); - System.out.print("."); - } - } - - /** - * Test method for 'BCrypt.checkpw(String, String)' - * expecting failure - */ - @Test - public void testCheckpw_failure() { - System.out.print("BCrypt.checkpw w/ bad passwords: "); - for (int i = 0; i < test_vectors.length; i++) { - int broken_index = (i + 4) % test_vectors.length; - String plain = test_vectors[i][0]; - String expected = test_vectors[broken_index][2]; - assertFalse(BCrypt.checkpw(plain, expected)); - System.out.print("."); - } - } - - /** - * Test for correct hashing of non-US-ASCII passwords - */ - @Test - public void testInternationalChars() { - System.out.print("BCrypt.hashpw w/ international chars: "); - String pw1 = "\u2605\u2605\u2605\u2605\u2605\u2605\u2605\u2605"; - String pw2 = "????????"; - - String h1 = BCrypt.hashpw(pw1, BCrypt.gensalt()); - assertFalse(BCrypt.checkpw(pw2, h1)); - System.out.print("."); - - String h2 = BCrypt.hashpw(pw2, BCrypt.gensalt()); - assertFalse(BCrypt.checkpw(pw1, h2)); - System.out.print("."); - } private static class BCryptHashTV { private final byte[] pass;