View Javadoc
1   /**
2    * Copyright By Grandsoft Company Limited.  
3    * 2014年3月18日 上午10:31:11
4    */
5   package gboat2.base.bridge.util.security;
6   import java.security.Key;
7   import java.security.NoSuchAlgorithmException;
8   import java.security.SecureRandom;
9   import java.util.Arrays;
10  
11  import javax.crypto.KeyGenerator;
12  import javax.crypto.SecretKey;
13  import javax.crypto.SecretKeyFactory;
14  import javax.crypto.spec.DESKeySpec;
15  import javax.crypto.spec.SecretKeySpec;
16  
17  import org.apache.commons.codec.binary.Base64;
18  import org.apache.commons.lang3.StringUtils;
19  /**
20   * DES 加密、解密工具类,支持 DES、DESede(TripleDES,就是3DES)、AES、Blowfish、RC2、RC4(ARCFOUR)
21   * 等加密算法。
22   * <pre>
23   * DES                  key size must be equal to 56 
24   * DESede(TripleDES)    key size must be equal to 112 or 168 
25   * AES                  key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available 
26   * Blowfish             key size must be multiple of 8, and can only range from 32 to 448 (inclusive) 
27   * RC2                  key size must be between 40 and 1024 bits 
28   * RC4(ARCFOUR)         key size must be between 40 and 1024 bits
29   * 
30   * 
31   * Java 和 .NET 程序进行 3DES 加解密数据交互的示例:
32   * <code>
33   * String data = "hemw, 你好!";
34   * String key = "F8-DC-2F-AA-C8-A6-82-E3-EB-35-2A-E2-DC-EA-38-FD";
35   * 
36   * System.out.println("加密前:" + data);
37   * System.out.println("  密钥:" + key);
38   * 
39   * Key k = DESUtil.getSecretKey(key, DESUtil.DESEDE, true);
40   * String encryptedText = DESUtil.encrypt(data, k, DESUtil.DESEDE_WITH_DOTNET);
41   * System.out.println("加密后:" + encryptedText); // .NET 可以直接对该密文进行解密
42   * 
43   * // encryptedText 为 .NET 加密后的密文
44   * String decryptedText = DESUtil.decrypt(encryptedText, k, DESUtil.DESEDE_WITH_DOTNET);
45   * System.out.println("解密后:" + decryptedText);
46   * </code>
47   * </pre>
48   * 在使用该工具类进行加密、解密操作时,一定要注意不同加密算法对密钥的长度要求。更多内容请参考
49   * <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html" target ="_blank">
50   * http://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html
51   * </a>
52   * 
53   * @author <a href="mailto:[email protected]">何明旺</a>
54   * @since 3.0
55   * @date 2014年3月18日
56   */
57  public class DESUtil {
58  
59      /** key size must be equal to 56, default key size is 56 bits */
60      public static final String DES = "DES";
61      
62      /**
63       * (TripleDES) key size must be equal to 112 or 168, default key size is 168 bits<br>
64       * A keysize of 112 will generate a Triple DES key with 2 intermediate keys,
65       * and a keysize of 168 will generate a Triple DES key with 3 intermediate
66       * keys.<br>
67       * Due to the "Meet-In-The-Middle" problem, even though 112 or 168 bits of
68       * key material are used, the effective keysize is 80 or 112 bits
69       * respectively.
70       */
71      public static final String DESEDE = "DESede";
72      
73      /** key size must be equal to 128, 192 or 256,but 192 and 256 bits, may not be available, default key size is 128 bits */
74      public static final String AES = "AES";
75      
76      /** key size must be multiple of 8, and can only range from 32 to 448 (inclusive), default key size is 128 bits */
77      public static final String BLOWFISH = "Blowfish";
78  
79      /** key size must be between 40 and 1024 bits (inclusive), default key size is 128 bits */
80      public static final String RC2 = "RC2";
81      
82      /** (ARCFOUR)   Keysize must range between 40 and 1024 bits (inclusive), default key size is 128 bits */
83      public static final String RC4 = "RC4";
84      
85      /** .NET 默认的 3DES 加密的算法模型,值为 {@value} */
86      public static final String DESEDE_WITH_DOTNET = "DESede/ECB/PKCS5Padding";
87  
88      /**
89       * 生成 DES 密钥
90       * 
91       * @return
92       */
93      public static String generateKey() {
94          return generateKey(null);
95      }
96  
97      /**
98       * 生成 DES 密钥
99       * 
100      * @param seed 种子
101      * @return 经过 BASE64 编码的密钥字符串
102      */
103     public static String generateKey(String seed) {
104         return generateKey(seed, DES);
105     }
106 
107     /**
108      * 生成密钥
109      * 
110      * @param seed 种子
111      * @param algorithm 加密算法名称,支持的算法: {@link #DES}、 {@link #DESEDE}、{@link #AES}、
112      *            {@link #BLOWFISH}、{@link #RC2}、 {@link #RC4}
113      * @return 经过 BASE64 编码的密钥字符串
114      */
115     public static String generateKey(String seed, String algorithm) {
116         SecureRandom secureRandom = (seed == null) ? new SecureRandom() : new SecureRandom(Base64.decodeBase64(seed));
117         KeyGenerator kg = Encryptor.getKeyGenerator(algorithm);
118         kg.init(secureRandom);
119         SecretKey secretKey = kg.generateKey();
120         return Base64.encodeBase64String(secretKey.getEncoded());
121     }
122 
123     /**
124      * 将 DES 密钥字符串转换为密钥实例对象
125      * @param desKey 经过 BASE64 编码的密钥字符串
126      * @return 密钥实例对象
127      */
128     public static SecretKey getSecretKey(String desKey){
129         return getSecretKey(desKey, DES);
130     }
131     
132     /**
133      * 将密钥字符串转换为密钥实例对象
134      * @param desKey 经过 BASE64 编码的密钥字符串
135      * @param algorithm 加密算法名称,支持的算法: {@link #DES}、 {@link #DESEDE}、{@link #AES}、
136      *            {@link #BLOWFISH}、{@link #RC2}、 {@link #RC4}
137      * @return 密钥实例对象
138      */
139     public static SecretKey getSecretKey(String desKey, String algorithm) {
140         if(StringUtils.isBlank(desKey))
141             throw new IllegalArgumentException("密钥不能为空。");
142         return getSecretKey(Base64.decodeBase64(desKey), algorithm);
143     }
144     
145     /**
146      * 将密钥字符串转换为密钥实例对象
147      * 
148      * @param key 密钥字符串
149      * @param algorithm 加密算法名称,支持的算法: {@link #DES}、 {@link #DESEDE}、{@link #AES}、
150      *            {@link #BLOWFISH}、{@link #RC2}、 {@link #RC4}
151      * @param md5 密钥字符串是否需要经过 MD5 加密,如果为 true,则会对 key 进行加密处理,如果值为 false,则对 key
152      *            进行 BASE64 解码处理。.NET 进行 3DES 加密时,默认会对 key 进行 MD5 加密处理,所以与 .NET
153      *            程序进行 3DES 加解密数据交互时,需要将该参数值高为 ture。
154      * @return 密钥实例对象
155      */
156     public static SecretKey getSecretKey(String key, String algorithm, boolean md5) {
157         if(StringUtils.isBlank(key))
158             throw new IllegalArgumentException("密钥不能为空。");
159         
160         byte[] keyBytes = null;
161         if(md5) {
162             final byte[] digestOfKey = Encryptor.digest(key, Encryptor.MD5);
163             keyBytes = Arrays.copyOf(digestOfKey, 24);
164             for (int j = 0, k = 16; j < 8;) {
165                 keyBytes[k++] = keyBytes[j++];
166             }
167         } else {
168             keyBytes = Base64.decodeBase64(key);
169         }
170         
171         return getSecretKey(keyBytes, algorithm);
172     }
173     
174     /** 
175      * 将密钥字符串转换为密钥实例对象
176      *  
177      * @param desKey 密钥
178      * @param algorithm 加密算法名称,支持的算法: {@link #DES}、 {@link #DESEDE}、{@link #AES}、
179      *            {@link #BLOWFISH}、{@link #RC2}、 {@link #RC4}
180      * @return 
181      */  
182     public static SecretKey getSecretKey(byte[] desKey, String algorithm) {
183         if(DES.equalsIgnoreCase(algorithm)) {
184             try {
185                 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);  
186                 DESKeySpec dks = new DESKeySpec(desKey);  
187                 return keyFactory.generateSecret(dks);
188             } catch (NoSuchAlgorithmException e) {
189                 throw new GboatSecurityException("算法 [" + algorithm + "] 不存在,或当前  JDK 不支持该算法。", e);
190             } catch (Exception e) {
191                 throw new IllegalArgumentException("将密钥字符串转换为密钥实例对象失败。", e);
192             }  
193         }
194   
195         return new SecretKeySpec(desKey, algorithm);
196     }
197     
198     /**
199      * 对数据进行 DES 加密
200      * @param data 要加密的数据
201      * @param key 经过 BASE64 编码的密钥字符串
202      * @return 经过 BASE64 编码的密文
203      */
204     public static String encrypt(String data, String key) {
205         byte[] entryptBytes = encrypt(data.getBytes(), key);
206         return Base64.encodeBase64String(entryptBytes);
207     }
208 
209     /**
210      * 对数据进行 DES 加密
211      * @param data 要加密的数据
212      * @param key 经过 BASE64 编码的密钥字符串
213      * @return 密文
214      */
215     public static byte[] encrypt(byte[] data, String key) {
216         return encrypt(data, key, DES);
217     }
218     
219     /**
220      * 对数据进行加密
221      * 
222      * @param data 要加密的明文数据
223      * @param key 经过 BASE64 编码的密钥字符串
224      * @param transformation the name of the transformation, format is "Algorithm/Modes/Paddings", e.g.,
225      *            DES/CBC/PKCS5Padding. See Appendix A in the <a target="_blank"
226      *            href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA">
227      *            Java Cryptography Architecture Reference Guide</a> for information about standard transformation names.
228      * <pre>
229      * The following table lists cipher algorithms available in the SunJCE provider:
230      * AlgorithmName                            Modes                                               Paddings
231      * AES              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB128, OFB, OFB8..OFB128  NOPADDING, PKCS5PADDING, ISO10126PADDING
232      * Blowfish         ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
233      * DES              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
234      * DESede           ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
235      * RC2              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
236      * ARCFOUR          ECB                                                             NOPADDING
237      * </pre>
238      * 
239      * @return 密文
240      */
241     public static byte[] encrypt(byte[] data, String key, String transformation) {  
242         Key k = getSecretKey(key, Encryptor.getAlgorithmFromTransformation(transformation));  
243         return Encryptor.encrypt(data, k, transformation);
244     }
245     
246     /**
247      * 对数据进行加密
248      * 
249      * @param data 要加密的明文数据
250      * @param key 经过 BASE64 编码的密钥字符串
251      * @param transformation the name of the transformation, format is "Algorithm/Modes/Paddings", e.g.,
252      *            DES/CBC/PKCS5Padding. See Appendix A in the <a target="_blank"
253      *            href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA">
254      *            Java Cryptography Architecture Reference Guide</a> for information about standard transformation names.
255      * <pre>
256      * The following table lists cipher algorithms available in the SunJCE provider:
257      * AlgorithmName                            Modes                                               Paddings
258      * AES              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB128, OFB, OFB8..OFB128  NOPADDING, PKCS5PADDING, ISO10126PADDING
259      * Blowfish         ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
260      * DES              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
261      * DESede           ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
262      * RC2              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
263      * ARCFOUR          ECB                                                             NOPADDING
264      * </pre>
265      * 
266      * @return 经过 BASE64 编码的密文字符串
267      */
268     public static String encrypt(String data, String key, String transformation) {
269         Key k = getSecretKey(key, Encryptor.getAlgorithmFromTransformation(transformation));
270         return encrypt(data, k, transformation);
271     }
272     
273     /**
274      * 对数据进行加密
275      * 
276      * @param data 要加密的明文数据
277      * @param key 密钥
278      * @param transformation the name of the transformation, format is "Algorithm/Modes/Paddings", e.g.,
279      *            DES/CBC/PKCS5Padding. See Appendix A in the <a target="_blank"
280      *            href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA">
281      *            Java Cryptography Architecture Reference Guide</a> for information about standard transformation names.
282      * <pre>
283      * The following table lists cipher algorithms available in the SunJCE provider:
284      * AlgorithmName                            Modes                                               Paddings
285      * AES              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB128, OFB, OFB8..OFB128  NOPADDING, PKCS5PADDING, ISO10126PADDING
286      * Blowfish         ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
287      * DES              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
288      * DESede           ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
289      * RC2              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
290      * ARCFOUR          ECB                                                             NOPADDING
291      * </pre>
292      * 
293      * @return 经过 BASE64 编码的密文字符串
294      */
295     public static String encrypt(String data, Key key, String transformation) { 
296         byte[] entryptBytes = Encryptor.encrypt(data.getBytes(), key, transformation);
297         return Base64.encodeBase64String(entryptBytes);
298     }
299   
300 
301     /**
302      * 对数据进行 DES 解密
303      * @param data 要解密的数据
304      * @param key 经过 BASE64 编码的密钥字符串
305      * @return 经过 BASE64 编码的密文
306      */
307     public static String decrypt(String data, String key) {
308         byte[] entryptBytes = decrypt(data.getBytes(), key);
309         return Base64.encodeBase64String(entryptBytes);
310     }
311 
312     /**
313      * 对数据进行 DES 解密
314      * @param data 要解密的数据
315      * @param key 经过 BASE64 编码的密钥字符串
316      * @return 密文
317      */
318     public static byte[] decrypt(byte[] data, String key) {
319         return decrypt(data, key, DES);
320     }
321     
322     /**
323      * 对数据进行解密
324      * 
325      * @param data 要解密的明文数据
326      * @param key 经过 BASE64 编码的密钥字符串
327      * @param transformation the name of the transformation, format is "Algorithm/Modes/Paddings", e.g.,
328      *            DES/CBC/PKCS5Padding. See Appendix A in the <a target="_blank"
329      *            href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA">
330      *            Java Cryptography Architecture Reference Guide</a> for information about standard transformation names.
331      * <pre>
332      * The following table lists cipher algorithms available in the SunJCE provider:
333      * AlgorithmName                            Modes                                               Paddings
334      * AES              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB128, OFB, OFB8..OFB128  NOPADDING, PKCS5PADDING, ISO10126PADDING
335      * Blowfish         ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
336      * DES              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
337      * DESede           ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
338      * RC2              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
339      * ARCFOUR          ECB                                                             NOPADDING
340      * </pre>
341      * 
342      * @return 密文
343      */
344     public static byte[] decrypt(byte[] data, String key, String transformation) {  
345         Key k = getSecretKey(key, Encryptor.getAlgorithmFromTransformation(transformation));  
346         return Encryptor.decrypt(data, k, transformation);
347     }
348     
349     /**
350      * 对数据进行解密
351      * 
352      * @param data 要解密的明文数据
353      * @param key 经过 BASE64 编码的密钥字符串
354      * @param transformation the name of the transformation, format is "Algorithm/Modes/Paddings", e.g.,
355      *            DES/CBC/PKCS5Padding. See Appendix A in the <a target="_blank"
356      *            href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA">
357      *            Java Cryptography Architecture Reference Guide</a> for information about standard transformation names.
358      * <pre>
359      * The following table lists cipher algorithms available in the SunJCE provider:
360      * AlgorithmName                            Modes                                               Paddings
361      * AES              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB128, OFB, OFB8..OFB128  NOPADDING, PKCS5PADDING, ISO10126PADDING
362      * Blowfish         ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
363      * DES              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
364      * DESede           ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
365      * RC2              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
366      * ARCFOUR          ECB                                                             NOPADDING
367      * </pre>
368      * 
369      * @return 经过 BASE64 编码的密文字符串
370      */
371     public static String decrypt(String data, String key, String transformation) {
372         Key k = getSecretKey(key, Encryptor.getAlgorithmFromTransformation(transformation));
373         return decrypt(data, k, transformation);
374     }
375     
376     /**
377      * 对数据进行解密
378      * 
379      * @param data 要解密的明文数据
380      * @param key 密钥
381      * @param transformation the name of the transformation, format is "Algorithm/Modes/Paddings", e.g.,
382      *            DES/CBC/PKCS5Padding. See Appendix A in the <a target="_blank"
383      *            href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA">
384      *            Java Cryptography Architecture Reference Guide</a> for information about standard transformation names.
385      * <pre>
386      * The following table lists cipher algorithms available in the SunJCE provider:
387      * AlgorithmName                            Modes                                               Paddings
388      * AES              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB128, OFB, OFB8..OFB128  NOPADDING, PKCS5PADDING, ISO10126PADDING
389      * Blowfish         ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
390      * DES              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
391      * DESede           ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
392      * RC2              ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, OFB8..OFB64    NOPADDING, PKCS5PADDING, ISO10126PADDING
393      * ARCFOUR          ECB                                                             NOPADDING
394      * </pre>
395      * 
396      * @return 经过 BASE64 编码的密文字符串
397      */
398     public static String decrypt(String data, Key key, String transformation) { 
399         byte[] dataBytes = Base64.decodeBase64(data);
400         byte[] decryptedBytes = Encryptor.decrypt(dataBytes, key, transformation);
401         return new String(decryptedBytes);
402     }
403 
404 }