PBKDF2WithHmacSHA1算法

     主要用于明文密码加密字符串存入数据库。由棱镜门思考。目前大部分企业中都是明文密码。一旦被攻破。危害非常大。现在主流加密技术是MD5加密。不过MD5的存在小概率碰撞(根据密码学的定义,如果内容不同的明文,通过散列算法得出的结果(密码学称为信息摘要)相同,就称为发生了“碰撞”。).如何生成md5碰撞的算法论文http://www.infosec.sdu.edu.cn/paper/md5-attack.pdf。一些黑客破获密码的方法是一种被称为“跑字典”的方法。有两种方法得到字典,一种是日常搜集的用做密码的字符串表,另一种是用排列组合方法生成的,先用MD5程序计算出这些字典项的MD5值,然后再用目标的MD5值在这个字典中检索。即使假设密码的最大长度为8,同时密码只能是字母和数字,共26+26+10=62个字符,排列组合出的字典的项数则是P(62,1)+P (62,2)….+P(62,8),那也已经是一个很天文的数字了,存储这个字典就需要TB级的磁盘组,而且这种方法还有一个前提,就是能获得目标账户的 密码MD5值的情况下才可以。当如果用户的密码是弱密码的就很危险了。

  PBKDF2WithHmacSHA1算法比MD5算法更安全。它可以同样密码在不同时间生成不同加密Hash。跑字典将无效。下面是算法Demo。

  1 package hashpassword;

  2 import java.security.SecureRandom;

  3 import javax.crypto.spec.PBEKeySpec;

  4 import javax.crypto.SecretKeyFactory;

  5 import java.math.BigInteger;

  6 import java.security.NoSuchAlgorithmException;

  7 import java.security.spec.InvalidKeySpecException;

  8 

  9 /*

 10  * PBKDF2 salted password hashing.

 11  * Author: havoc AT defuse.ca

 12  * www: http://crackstation.net/hashing-security.htm

 13  */

 14 public class PasswordHash

 15 {

 16     public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";

 17 

 18     // The following constants may be changed without breaking existing hashes.

 19     public static final int SALT_BYTE_SIZE = 24;

 20     public static final int HASH_BYTE_SIZE = 24;

 21     public static final int PBKDF2_ITERATIONS = 10;

 22 

 23     public static final int ITERATION_INDEX = 0;

 24     public static final int SALT_INDEX = 1;

 25     public static final int PBKDF2_INDEX = 2;

 26 

 27     public static String createHash(String password)

 28         throws NoSuchAlgorithmException, InvalidKeySpecException

 29     {

 30         return createHash(password.toCharArray());

 31     }

 32 

 33     /**

 34      * Returns a salted PBKDF2 hash of the password.

 35      * 返回一个加盐后的PBKDF2哈希密码

 36      * @param   password    the password to hash

 37      * @return              a salted PBKDF2 hash of the password

 38      */

 39     public static String createHash(char[] password)

 40         throws NoSuchAlgorithmException, InvalidKeySpecException

 41     {

 42         // Generate a random salt 随即盐序列

 43         SecureRandom random = new SecureRandom();

 44         byte[] salt = new byte[SALT_BYTE_SIZE];

 45         random.nextBytes(salt);

 46 

 47         // Hash the password  生成哈希密码

 48         byte[] hash = pbkdf2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);

 49         // format iterations:salt:hash 格式化 迭代次数:盐:哈希

 50         return PBKDF2_ITERATIONS + ":" + toHex(salt) + ":" +  toHex(hash);

 51     }

 52 

 53     /**

 54      * Validates a password using a hash.

 55      *

 56      * @param   password        the password to check

 57      * @param   correctHash     the hash of the valid password

 58      * @return                  true if the password is correct, false if not

 59      */

 60     public static boolean validatePassword(String password, String correctHash)

 61         throws NoSuchAlgorithmException, InvalidKeySpecException

 62     {

 63         return validatePassword(password.toCharArray(), correctHash);

 64     }

 65 

 66     /**

 67      * Validates a password using a hash.

 68      *

 69      * @param   password        the password to check

 70      * @param   correctHash     the hash of the valid password

 71      * @return                  true if the password is correct, false if not

 72      */

 73     public static boolean validatePassword(char[] password, String correctHash)

 74         throws NoSuchAlgorithmException, InvalidKeySpecException

 75     {

 76         // Decode the hash into its parameters

 77         String[] params = correctHash.split(":");

 78         int iterations = Integer.parseInt(params[ITERATION_INDEX]);

 79         byte[] salt = fromHex(params[SALT_INDEX]);

 80         byte[] hash = fromHex(params[PBKDF2_INDEX]);

 81         // Compute the hash of the provided password, using the same salt, 

 82         // iteration count, and hash length

 83         byte[] testHash = pbkdf2(password, salt, iterations, hash.length);

 84         // Compare the hashes in constant time. The password is correct if

 85         // both hashes match.

 86         return slowEquals(hash, testHash);

 87     }

 88 

 89     /**

 90      * Compares two byte arrays in length-constant time. This comparison method

 91      * is used so that password hashes cannot be extracted from an on-line 

 92      * system using a timing attack and then attacked off-line.

 93      * 

 94      * @param   a       the first byte array

 95      * @param   b       the second byte array 

 96      * @return          true if both byte arrays are the same, false if not

 97      */

 98     private static boolean slowEquals(byte[] a, byte[] b)

 99     {

100         int diff = a.length ^ b.length;

101         for(int i = 0; i < a.length && i < b.length; i++)

102             diff |= a[i] ^ b[i];

103         return diff == 0;

104     }

105 

106     /**

107      *  Computes the PBKDF2 hash of a password.

108      *  计算PBKDF2哈希密码

109      * @param   password    the password to hash.   需要加密的明文密码

110      * @param   salt        the salt                盐增加调味 增加密码破解难度

111      * @param   iterations  the iteration count (slowness factor)  迭代次数

112      * @param   bytes       the length of the hash to compute in bytes  计算密码后的 哈希长度

113      * @return              the PBDKF2 hash of the password

114      */

115     private static byte[] pbkdf2(char[] password, byte[] salt, int iterations, int bytes)

116         throws NoSuchAlgorithmException, InvalidKeySpecException

117     {

118         PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, bytes * 8);

119         SecretKeyFactory skf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);

120         return skf.generateSecret(spec).getEncoded();

121     }

122 

123     /**

124      * Converts a string of hexadecimal characters into a byte array.

125      *

126      * @param   hex         the hex string

127      * @return              the hex string decoded into a byte array

128      */

129     private static byte[] fromHex(String hex)

130     {

131         byte[] binary = new byte[hex.length() / 2];

132         for(int i = 0; i < binary.length; i++)

133         {

134             binary[i] = (byte)Integer.parseInt(hex.substring(2*i, 2*i+2), 16);

135         }

136         return binary;

137     }

138 

139     /**

140      * Converts a byte array into a hexadecimal string.

141      *

142      * @param   array       the byte array to convert

143      * @return              a length*2 character string encoding the byte array

144      */

145     private static String toHex(byte[] array)

146     {

147         BigInteger bi = new BigInteger(1, array);

148         String hex = bi.toString(16);

149         int paddingLength = (array.length * 2) - hex.length();

150         if(paddingLength > 0) 

151             return String.format("%0" + paddingLength + "d", 0) + hex;

152         else

153             return hex;

154     }

155 

156     /**

157      * Tests the basic functionality of the PasswordHash class

158      *

159      * @param   args        ignored

160      */

161     public static void main(String[] args)

162     {

163         try

164         {

165             // Print out 10 hashes

166             for(int i = 0; i < 10; i++)

167                 System.out.println(PasswordHash.createHash("p\r\nassw0Rd!"));

168 

169             // Test password validation

170             boolean failure = false;

171             System.out.println("Running tests...");

172             for(int i = 0; i < 100; i++)

173             {

174                 String password = ""+i;

175                 String hash = createHash(password);

176                 String secondHash = createHash(password);

177                 if(hash.equals(secondHash)) {

178                     System.out.println("FAILURE: TWO HASHES ARE EQUAL!");

179                     failure = true;

180                 }

181                 String wrongPassword = ""+(i+1);

182                 if(validatePassword(wrongPassword, hash)) {

183                     System.out.println("FAILURE: WRONG PASSWORD ACCEPTED!");

184                     failure = true;

185                 }

186                 if(!validatePassword(password, hash)) {

187                     System.out.println("FAILURE: GOOD PASSWORD NOT ACCEPTED!");

188                     failure = true;

189                 }

190             }

191             if(failure)

192                 System.out.println("TESTS FAILED!");

193             else

194                 System.out.println("TESTS PASSED!");

195         }

196         catch(Exception ex)

197         {

198             System.out.println("ERROR: " + ex);

199         }

200     }

201 

202 }

 https://crackstation.net/hashing-security.htm

你可能感兴趣的:(with)