Double encryption of password with SHA256 (questions can be explained in the comments) gives you valuable insights in exchange for red shame So, let's try the password ~~ encryption ~~ hashing with BCrypt and PBKDF2 that you introduced immediately. This time is BCrypt edition.
This time, BCrypt ~~ encryption ~~ hashing will be performed using the spring-security that was taught in the comment of the above article. I don't need the whole Spring, so I borrowed only the spring-security jar from mvn repository. ..
String passStr = "password_desu_4";
String hashStr;
//Encode
BCryptPasswordEncoder bpe = new BCryptPasswordEncoder();
hashStr = bpe.encode(passStr);
System.out.println("original string : " + passStr);
System.out.println("encoded by Bcrypt : " + hashStr);
//Authentication
boolean isMatch = bpe.matches(passStr, hashStr);
System.out.println("result : " + (isMatch ? "match" : "not match"));
smart!
The result looks like this
original string : password_desu_4
encoded by Bcrypt : $2a$10$HQwFeyajSohLrmbHTEzJbuHzPgITU7CJ/fQbJfEBCkBJXz5lCk8ke
result : match
You can set the strength by passing an int from 4 to 31 to the constructor of the BCryptPasswordEncoder class. It's strength, not stretch times. It seems to stretch the multiplier of 2 for the argument.
Naturally, the processing time will also increase exponentially. Good luck, it's a 32-bit i7 core laptop.
= strength : 4, streach times : 16 ========
encoding time : 0.003 sec.
verifying time : 0.002 sec.
= strength : 5, streach times : 32 ========
encoding time : 0.004 sec.
verifying time : 0.004 sec.
= strength : 6, streach times : 64 ========
encoding time : 0.007 sec.
verifying time : 0.008 sec.
= strength : 7, streach times : 128 ========
encoding time : 0.015 sec.
verifying time : 0.014 sec.
= strength : 8, streach times : 256 ========
encoding time : 0.029 sec.
verifying time : 0.030 sec.
= strength : 9, streach times : 512 ========
encoding time : 0.058 sec.
verifying time : 0.060 sec.
= strength : 10, streach times : 1024 ========★ Default strength
encoding time : 0.118 sec.
verifying time : 0.117 sec.
= strength : 11, streach times : 2048 ========
encoding time : 0.240 sec.
verifying time : 0.231 sec.
= strength : 12, streach times : 4096 ========
encoding time : 0.462 sec.
verifying time : 0.463 sec.
= strength : 13, streach times : 8192 ========
encoding time : 0.924 sec.
verifying time : 0.926 sec.
= strength : 14, streach times : 16384 ========
encoding time : 1.847 sec.
verifying time : 1.840 sec.
= strength : 15, streach times : 32768 ========
encoding time : 3.702 sec.
verifying time : 3.691 sec.
= strength : 16, streach times : 65536 ========
encoding time : 7.440 sec.
verifying time : 7.402 sec.
= strength : 17, streach times : 131072 ========
encoding time : 14.867 sec.
verifying time : 14.776 sec.
= strength : 18, streach times : 262144 ========
encoding time : 30.416 sec.
verifying time : 29.593 sec.
= strength : 19, streach times : 524288 ========
encoding time : 60.6590 sec.
verifying time : 60.180 sec.
= strength : 20, streach times : 1048576 ========
Well, the processing time depends on the environment, so it wouldn't make much sense to record the exact number of seconds in my environment. So, the tendency that can be read so far is as follows.
--The time required for hashing and the time required for authentication are approximately the same. ――If strength increases by 1, the processing time will be doubled.
… It's natural because the amount of processing is doubled.
So if you give a simplified theoretical value
strength | processing time |
---|---|
20 | 2 minutes |
21 | 4 minutes |
22 | 8 minutes |
23 | 16 minutes |
24 | 32 minutes |
25 | 1 hour 4 minutes |
26 | 2 hours 8 minutes |
27 | 4 hours 16 minutes |
28 | 8 hours 32 minutes |
29 | 17 hours 4 minutes |
30 | 1 day and 10 hours 8 minutes |
31 | 2 days and 20 hours 16 minutes |
Exponential function is scary.
This amount of processing is required for one password, although it will naturally shrink if done in a high-spec environment. The strength is 10 (stretch 1024 times) by default, but even considering the waiting time for normal login, I think that the limit is about 0.5 seconds (strength = 12 in this environment) at most.
This can be a security measure. I realized it for myself. I'm glad I didn't try until ~~ 31 ~~
import java.math.BigInteger;
import java.util.Date;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class CryptUtil {
/**
*Hash with Bcypt while measuring processing time
* @param passStr password string
* @param strength The number of hashes. 4-31 (how many of 2)
*/
public static String testBcryptEncode(String passStr, int strength) {
//Start time
long startTime = (new Date()).getTime();
//Hashing with BCrypt
BCryptPasswordEncoder bpe = new BCryptPasswordEncoder(strength);
String hashStr = bpe.encode(passStr);
//Hashing end time
long endTime = (new Date()).getTime();
String timeDelta = String.format("%.4f", ((float)(endTime - startTime) / 1000));
System.out.println("encoding time : " + timeDelta + " sec.");
return hashStr;
}
/**
*Authentication whether the raw password and hash match while measuring the processing time
* @param passStr raw
* @param hashStr hash
* @param strength
*/
public static void testBcyptVerify(String passStr, String hashStr, int strength) {
//Start time
long startTime = (new Date()).getTime();
//Check if the password matches the hash
BCryptPasswordEncoder bpe = new BCryptPasswordEncoder(strength);
boolean isMatch = bpe.matches(passStr, hashStr);
//Verification end time
long endTime = (new Date()).getTime();
String timeDelta = String.format("%.4f", ((float)(endTime - startTime) / 1000));
if (isMatch) {
System.out.println("verifying time : " + timeDelta + " sec.");
} else {
}
}
public static void main(String[] args) {
String passStr = "password_desu_4";
String hashStr;
//Simple encoding and authentication
BCryptPasswordEncoder bpe = new BCryptPasswordEncoder();
hashStr = bpe.encode(passStr);
System.out.println("original string : " + passStr);
System.out.println("encoded by Bcrypt : " + hashStr);
boolean isMatch = bpe.matches(passStr, hashStr);
System.out.println("result : " + (isMatch ? "match" : "not match"));
System.out.println("");
//Time measurement for each strength
double streachTimes;
for (int strength=4; strength<=31; strength++) {
streachTimes = Math.pow(2, strength);
System.out.println("= strength : " + strength + ", streach times : " + String.format("%1$.0f", streachTimes) + " ========");
hashStr = testBcryptEncode(passStr, strength);
testBcyptVerify(passStr, hashStr, strength);
}
}
}
Recommended Posts