Java版密码加密工具

Java版本:

  1 import java.security.SecureRandom;
  2 import javax.crypto.spec.PBEKeySpec;
  3 import javax.crypto.SecretKeyFactory;
  4 import java.security.NoSuchAlgorithmException;
  5 import java.security.spec.InvalidKeySpecException;
  6 import javax.xml.bind.DatatypeConverter;
  7 
  8 public class PasswordStorage
  9 {
 10 
 11     @SuppressWarnings("serial")
 12     static public class InvalidHashException extends Exception {
 13         public InvalidHashException(String message) {
 14             super(message);
 15         }
 16         public InvalidHashException(String message, Throwable source) {
 17             super(message, source);
 18         }
 19     }
 20 
 21     @SuppressWarnings("serial")
 22     static public class CannotPerformOperationException extends Exception {
 23         public CannotPerformOperationException(String message) {
 24             super(message);
 25         }
 26         public CannotPerformOperationException(String message, Throwable source) {
 27             super(message, source);
 28         }
 29     }
 30 
 31     public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";
 32 
 33     // These constants may be changed without breaking existing hashes.
 34     public static final int SALT_BYTE_SIZE = 24;
 35     public static final int HASH_BYTE_SIZE = 18;
 36     public static final int PBKDF2_ITERATIONS = 64000;
 37 
 38     // These constants define the encoding and may not be changed.
 39     public static final int HASH_SECTIONS = 5;
 40     public static final int HASH_ALGORITHM_INDEX = 0;
 41     public static final int ITERATION_INDEX = 1;
 42     public static final int HASH_SIZE_INDEX = 2;
 43     public static final int SALT_INDEX = 3;
 44     public static final int PBKDF2_INDEX = 4;
 45 
 46     public static String createHash(String password)
 47         throws CannotPerformOperationException
 48     {
 49         return createHash(password.toCharArray());
 50     }
 51 
 52     public static String createHash(char[] password)
 53         throws CannotPerformOperationException
 54     {
 55         // Generate a random salt
 56         SecureRandom random = new SecureRandom();
 57         byte[] salt = new byte[SALT_BYTE_SIZE];
 58         random.nextBytes(salt);
 59 
 60         // Hash the password
 61         byte[] hash = pbkdf2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
 62         int hashSize = hash.length;
 63 
 64         // format: algorithm:iterations:hashSize:salt:hash
 65         String parts = "sha1:" +
 66             PBKDF2_ITERATIONS +
 67             ":" + hashSize +
 68             ":" +
 69             toBase64(salt) +
 70             ":" +
 71             toBase64(hash);
 72         return parts;
 73     }
 74 
 75     public static boolean verifyPassword(String password, String correctHash)
 76         throws CannotPerformOperationException, InvalidHashException
 77     {
 78         return verifyPassword(password.toCharArray(), correctHash);
 79     }
 80 
 81     public static boolean verifyPassword(char[] password, String correctHash)
 82         throws CannotPerformOperationException, InvalidHashException
 83     {
 84         // Decode the hash into its parameters
 85         String[] params = correctHash.split(":");
 86         if (params.length != HASH_SECTIONS) {
 87             throw new InvalidHashException(
 88                 "Fields are missing from the password hash."
 89             );
 90         }
 91 
 92         // Currently, Java only supports SHA1.
 93         if (!params[HASH_ALGORITHM_INDEX].equals("sha1")) {
 94             throw new CannotPerformOperationException(
 95                 "Unsupported hash type."
 96             );
 97         }
 98 
 99         int iterations = 0;
100         try {
101             iterations = Integer.parseInt(params[ITERATION_INDEX]);
102         } catch (NumberFormatException ex) {
103             throw new InvalidHashException(
104                 "Could not parse the iteration count as an integer.",
105                 ex
106             );
107         }
108 
109         if (iterations < 1) {
110             throw new InvalidHashException(
111                 "Invalid number of iterations. Must be >= 1."
112             );
113         }
114 
115 
116         byte[] salt = null;
117         try {
118             salt = fromBase64(params[SALT_INDEX]);
119         } catch (IllegalArgumentException ex) {
120             throw new InvalidHashException(
121                 "Base64 decoding of salt failed.",
122                 ex
123             );
124         }
125 
126         byte[] hash = null;
127         try {
128             hash = fromBase64(params[PBKDF2_INDEX]);
129         } catch (IllegalArgumentException ex) {
130             throw new InvalidHashException(
131                 "Base64 decoding of pbkdf2 output failed.",
132                 ex
133             );
134         }
135 
136 
137         int storedHashSize = 0;
138         try {
139             storedHashSize = Integer.parseInt(params[HASH_SIZE_INDEX]);
140         } catch (NumberFormatException ex) {
141             throw new InvalidHashException(
142                 "Could not parse the hash size as an integer.",
143                 ex
144             );
145         }
146 
147         if (storedHashSize != hash.length) {
148             throw new InvalidHashException(
149                 "Hash length doesn't match stored hash length."
150             );
151         }
152 
153         // Compute the hash of the provided password, using the same salt, 
154         // iteration count, and hash length
155         byte[] testHash = pbkdf2(password, salt, iterations, hash.length);
156         // Compare the hashes in constant time. The password is correct if
157         // both hashes match.
158         return slowEquals(hash, testHash);
159     }
160 
161     private static boolean slowEquals(byte[] a, byte[] b)
162     {
163         int diff = a.length ^ b.length;
164         for(int i = 0; i < a.length && i < b.length; i++)
165             diff |= a[i] ^ b[i];
166         return diff == 0;
167     }
168 
169     private static byte[] pbkdf2(char[] password, byte[] salt, int iterations, int bytes)
170         throws CannotPerformOperationException
171     {
172         try {
173             PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, bytes * 8);
174             SecretKeyFactory skf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
175             return skf.generateSecret(spec).getEncoded();
176         } catch (NoSuchAlgorithmException ex) {
177             throw new CannotPerformOperationException(
178                 "Hash algorithm not supported.",
179                 ex
180             );
181         } catch (InvalidKeySpecException ex) {
182             throw new CannotPerformOperationException(
183                 "Invalid key spec.",
184                 ex
185             );
186         }
187     }
188 
189     private static byte[] fromBase64(String hex)
190         throws IllegalArgumentException
191     {
192         return DatatypeConverter.parseBase64Binary(hex);
193     }
194 
195     private static String toBase64(byte[] array)
196     {
197         return DatatypeConverter.printBase64Binary(array);
198     }
199 
200 }

 

C# .PHP版本, 详细见  https://github.com/defuse/password-hashing

 

posted @ 2017-11-10 11:12  RossKing  阅读(1551)  评论(0编辑  收藏  举报