PBKDF2WithHmacSHA1 algorithm

PBKDF2WithHmacSHA1 algorithm

This article is transferred from: PBKDF2WithHmacSHA1 algorithm

View Image

PBKDF2WithHmacSHA1 algorithm:

      It is mainly used to store the plaintext password encrypted string into the database. Think by the prism gate. Clear text passwords are currently used in most enterprises. Once breached. The harm is very great. Now the mainstream encryption technology is MD5 encryption. However, MD5 has a small probability of collision (according to the definition of cryptography, if the content of plaintext is different, the result obtained by the hash algorithm (cryptography is called information digest) is the same, it is called a "collision".) The algorithm paper for generating md5 collision http://www.infosec.sdu.edu.cn/paper/md5-attack.pdf . Some hackers use a method known as "running a dictionary" to crack a password. There are two ways to get the dictionary, one is the string table of passwords collected daily, and the other is generated by permutation and combination method. First use the MD5 program to calculate the MD5 value of these dictionary items, and then use the target The MD5 value is retrieved in this dictionary. Even assuming that the maximum length of the password is 8, and the password can only be letters and numbers, a total of 26+26+10=62 characters, the number of entries in the permutation and combination dictionary is P(62,1)+P (62, 2)...+P(62,8), that is already an astronomical number. To store this dictionary, a TB-level disk group is required, and there is a prerequisite for this method, which is to obtain the password of the target account Only in the case of MD5 value. It is very dangerous if the user's password is weak. PBKDF2WithHmacSHA1 algorithm is more secure than the MD5 algorithm. It can generate different encrypted hashes with the same password at different times, it is recommended for everyone to use hashes with the PBKDF2WithHmacSHA1 algorithm for encryption.

Implementation:

package hashpassword; import java.security.SecureRandom; import javax.crypto.spec.PBEKeySpec; import javax.crypto.SecretKeyFactory; import java.math.BigInteger; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; /* * PBKDF2 salted password hashing. * Author: havoc AT defuse.ca * www: http://crackstation.net/hashing-security.htm */ public class PasswordHash { public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1"; //The following constants may be changed without breaking existing hashes. public static final int SALT_BYTE_SIZE = 24; public static final int HASH_BYTE_SIZE = 24; public static final int PBKDF2_ITERATIONS = 10; public static final int ITERATION_INDEX = 0; public static final int SALT_INDEX = 1; public static final int PBKDF2_INDEX = 2; public static String createHash(String password) throws NoSuchAlgorithmException, InvalidKeySpecException { return createHash(password.toCharArray()); } /** * Returns a salted PBKDF2 hash of the password. * Return a salted PBKDF2 hash password * @param password the password to hash * @return a salted PBKDF2 hash of the password */ public static String createHash(char[] password) throws NoSuchAlgorithmException, InvalidKeySpecException { //Generate a random salt random salt sequence SecureRandom random = new SecureRandom(); byte[] salt = new byte[SALT_BYTE_SIZE]; random.nextBytes(salt); //Hash the password generates a hash password byte[] hash = pbkdf2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE); //format iterations:salt:hash format iterations: salt: hash return PBKDF2_ITERATIONS + ":" + toHex(salt) + ":" + toHex(hash); } /** * Validates a password using a hash. * * @param password the password to check * @param correctHash the hash of the valid password * @return true if the password is correct, false if not */ public static boolean validatePassword(String password, String correctHash) throws NoSuchAlgorithmException, InvalidKeySpecException { return validatePassword(password.toCharArray(), correctHash); } /** * Validates a password using a hash. * * @param password the password to check * @param correctHash the hash of the valid password * @return true if the password is correct, false if not */ public static boolean validatePassword(char[] password, String correctHash) throws NoSuchAlgorithmException, InvalidKeySpecException { //Decode the hash into its parameters String[] params = correctHash.split(":"); int iterations = Integer.parseInt(params[ITERATION_INDEX]); byte[] salt = fromHex(params[SALT_INDEX]); byte[] hash = fromHex(params[PBKDF2_INDEX]); //Compute the hash of the provided password, using the same salt, //iteration count, and hash length byte[] testHash = pbkdf2(password, salt, iterations, hash.length); //Compare the hashes in constant time. The password is correct if //both hashes match. return slowEquals(hash, testHash); } /** * Compares two byte arrays in length-constant time. This comparison method * is used so that password hashes cannot be extracted from an on-line * system using a timing attack and then attacked off-line. * * @param a the first byte array * @param b the second byte array * @return true if both byte arrays are the same, false if not */ private static boolean slowEquals(byte[] a, byte[] b) { int diff = a.length ^ b.length; for(int i = 0; i <a.length && i <b.length; i++) diff |= a[i] ^ b[i]; return diff == 0; } /** * Computes the PBKDF2 hash of a password. * Calculate PBKDF2 hash password * @param password the password to hash. The plaintext password that needs to be encrypted * @param salt the salt Add seasoning to increase the difficulty of password cracking * @param iterations the iteration count (slowness factor) * @param bytes the length of the hash to compute in bytes * @return the PBDKF2 hash of the password */ private static byte[] pbkdf2(char[] password, byte[] salt, int iterations, int bytes) throws NoSuchAlgorithmException, InvalidKeySpecException { PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, bytes * 8); SecretKeyFactory skf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM); return skf.generateSecret(spec).getEncoded(); } /** * Converts a string of hexadecimal characters into a byte array. * * @param hex the hex string * @return the hex string decoded into a byte array */ private static byte[] fromHex(String hex) { byte[] binary = new byte[hex.length()/2]; for(int i = 0; i <binary.length; i++) { binary[i] = (byte)Integer.parseInt(hex.substring(2*i, 2*i+2), 16); } return binary; } /** * Converts a byte array into a hexadecimal string. * * @param array the byte array to convert * @return a length*2 character string encoding the byte array */ private static String toHex(byte[] array) { BigInteger bi = new BigInteger(1, array); String hex = bi.toString(16); int paddingLength = (array.length * 2)-hex.length(); if(paddingLength> 0) return String.format("%0" + paddingLength + "d", 0) + hex; else return hex; } /** * Tests the basic functionality of the PasswordHash class * * @param args ignored */ public static void main(String[] args) { try { //Print out 10 hashes for(int i = 0; i <10; i++) System.out.println(PasswordHash.createHash("p\r\nassw0Rd!")); //Test password validation boolean failure = false; System.out.println("Running tests..."); for(int i = 0; i <100; i++) { String password = ""+i; String hash = createHash(password); String secondHash = createHash(password); if(hash.equals(secondHash)) { System.out.println("FAILURE: TWO HASHES ARE EQUAL!"); failure = true; } String wrongPassword = ""+(i+1); if(validatePassword(wrongPassword, hash)) { System.out.println("FAILURE: WRONG PASSWORD ACCEPTED!"); failure = true; } if(!validatePassword(password, hash)) { System.out.println("FAILURE: GOOD PASSWORD NOT ACCEPTED!"); failure = true; } } if(failure) System.out.println("TESTS FAILED!"); else System.out.println("TESTS PASSED!"); } catch(Exception ex) { System.out.println("ERROR: "+ ex); } } }

 


Reference : https://blog.csdn.net/qq_31289187/article/details/85061439