Fork me on GitHub

使用java实现AES加密

   公司最近做agent项目,需要对一些远程重要的请求参数进行加密。加密之前选型,选择了AES,而DES算法加密,容易被破解。网上有很多关于加密的算法的Demo案列,我发现这些Demo在Window平台运行正常,然后再MAC下就一直报错,现在选择网上常见的AES加密算法如下:

一·AES加密

 1 /**
 2      * AES加密字符串
 3      * 
 4      * @param content
 5      *            需要被加密的字符串
 6      * @param password
 7      *            加密需要的密码
 8      * @return 密文
 9      */
10     public static byte[] encrypt(String content, String password) {
11         try {
12             KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
13 
14             kgen.init(128, new SecureRandom(password.getBytes()));// 利用用户密码作为随机数初始化出
15                                                                     // 128位的key生产者
16             //加密没关系,SecureRandom是生成安全随机数序列,password.getBytes()是种子,只要种子相同,序列就一样,所以解密只要有password就行
17 
18             SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
19 
20             byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥,如果此密钥不支持编码,则返回
21                                                             // null。
22 
23             SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
24 
25             Cipher cipher = Cipher.getInstance("AES");// 创建密码器
26 
27             byte[] byteContent = content.getBytes("utf-8");
28 
29             cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化为加密模式的密码器
30 
31             byte[] result = cipher.doFinal(byteContent);// 加密
32 
33             return result;
34 
35         } catch (NoSuchPaddingException e) {
36             e.printStackTrace();
37         } catch (NoSuchAlgorithmException e) {
38             e.printStackTrace();
39         } catch (UnsupportedEncodingException e) {
40             e.printStackTrace();
41         } catch (InvalidKeyException e) {
42             e.printStackTrace();
43         } catch (IllegalBlockSizeException e) {
44             e.printStackTrace();
45         } catch (BadPaddingException e) {
46             e.printStackTrace();
47         }
48         return null;
49     }

二.AES解密

 1  /**
 2      * 解密AES加密过的字符串
 3      * 
 4      * @param content
 5      *            AES加密过过的内容
 6      * @param password
 7      *            加密时的密码
 8      * @return 明文
 9      */
10     public static byte[] decrypt(byte[] content, String password) {
11         try {
12             KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
13             kgen.init(128, new SecureRandom(password.getBytes()));
14             SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
15             byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥
16             SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
17             Cipher cipher = Cipher.getInstance("AES");// 创建密码器
18             cipher.init(Cipher.DECRYPT_MODE, key);// 初始化为解密模式的密码器
19             byte[] result = cipher.doFinal(content);  
20             return result; // 明文   
21             
22         } catch (NoSuchAlgorithmException e) {
23             e.printStackTrace();
24         } catch (NoSuchPaddingException e) {
25             e.printStackTrace();
26         } catch (InvalidKeyException e) {
27             e.printStackTrace();
28         } catch (IllegalBlockSizeException e) {
29             e.printStackTrace();
30         } catch (BadPaddingException e) {
31             e.printStackTrace();
32         }
33         return null;
34     }

三.测试

 1  public static void main(String[] args) {
 2         String content = "对面的楼上的男生,你们有女朋友吗?";
 3         String password = "123456789";
 4         System.out.println("加密之前:" + content);
 5 
 6         // 加密
 7         byte[] encrypt = AesTest.encrypt(content, password);
 8         System.out.println("加密后的内容:" + new String(encrypt));
 9         
10         // 解密
11         byte[] decrypt = AesTest.decrypt(encrypt, password);
12         System.out.println("解密后的内容:" + new String(decrypt));        
13     }

以上代码在Window平台上运行正常,但是在MAC下运行加密正常,解密一直以下报 Given final block not properly padded的错!!!

网上查了很多资料,最后分析了下错误原因:

SecureRandom 实现完全随操作系统本身的内部状态,除非调用方在调用 getInstance 方法之后又调用了 setSeed 方法;该实现在 windows 上每次生成的 key 都相同,但是在 MAC 或部分 linux 系统上则不同。两次加密,解密产生的密钥都不相同,所以解密就报错。为了规避这个错误,采用了另一种AES加密的方法,而且需要添加2个依赖jar包。两个依赖的maven坐标是:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.4</version>
</dependency>
<dependency>
    <groupId>org.apache.directory.studio</groupId>
    <artifactId>org.apache.commons.codec</artifactId>
    <version>1.8</version>
</dependency>

下面是改进后的代码:

  1 package com.corearchi.utils;
  2 
  3 import javax.crypto.Cipher;
  4 import javax.crypto.KeyGenerator;
  5 import javax.crypto.spec.SecretKeySpec;
  6 import org.apache.commons.codec.binary.Base64;
  7 import org.apache.commons.lang3.StringUtils;
  8 
  9 import sun.misc.BASE64Decoder;
 10 
 11 /**
 12  * AES算法进行加密
 13  *
 14  * @author CodeGeek
 15  * @create 2018-01-23 上午11:00
 16  **/
 17 public class EncryptUtils {
 18 
 19     /**
 20      * 密钥
 21      */
 22     private static final String KEY = "1234567887654321";// AES加密要求key必须要128个比特位(这里需要长度为16,否则会报错)
 23 
 24     /**
 25      * 算法
 26      */
 27     private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";
 28 
 29     public static void main(String[] args) throws Exception {
 30         String content = "url:findNames.action";
 31         System.out.println("加密前:" + content);
 32 
 33         System.out.println("加密密钥和解密密钥:" + KEY);
 34 
 35         String encrypt = aesEncrypt(content, KEY);
 36         System.out.println("加密后:" + encrypt);
 37 
 38         String decrypt = aesDecrypt(encrypt, KEY);
 39 
 40         System.out.println("解密后:" + decrypt);
 41     }
 42 
 43     /**
 44      * base 64 encode
 45      * @param bytes 待编码的byte[]
 46      * @return 编码后的base 64 code
 47      */
 48       private static String base64Encode(byte[] bytes){
 49         return Base64.encodeBase64String(bytes);
 50     }
 51 
 52     /**
 53      * base 64 decode
 54      * @param base64Code 待解码的base 64 code
 55      * @return 解码后的byte[]
 56      * @throws Exception 抛出异常
 57      */
 58     private static byte[] base64Decode(String base64Code) throws Exception{
 59         return StringUtils.isEmpty(base64Code) ? null : new BASE64Decoder().decodeBuffer(base64Code);
 60     }
 61 
 62 
 63     /**
 64      * AES加密
 65      * @param content 待加密的内容
 66      * @param encryptKey 加密密钥
 67      * @return 加密后的byte[]
 68      */
 69     private static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
 70         KeyGenerator kgen = KeyGenerator.getInstance("AES");
 71         kgen.init(128);
 72         Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
 73         cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
 74 
 75         return cipher.doFinal(content.getBytes("utf-8"));
 76     }
 77 
 78 
 79     /**
 80      * AES加密为base 64 code
 81      *
 82      * @param content 待加密的内容
 83      * @param encryptKey 加密密钥
 84      * @return 加密后的base 64 code
 85      */
 86     private static String aesEncrypt(String content, String encryptKey) throws Exception {
 87         return base64Encode(aesEncryptToBytes(content, encryptKey));
 88     }
 89 
 90     /**
 91      * AES解密
 92      *
 93      * @param encryptBytes 待解密的byte[]
 94      * @param decryptKey 解密密钥
 95      * @return 解密后的String
 96      */
 97     private static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
 98         KeyGenerator kgen = KeyGenerator.getInstance("AES");
 99         kgen.init(128);
100 
101         Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
102         cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
103         byte[] decryptBytes = cipher.doFinal(encryptBytes);
104 
105         return new String(decryptBytes);
106     }
107 
108 
109     /**
110      * 将base 64 code AES解密
111      *
112      * @param encryptStr 待解密的base 64 code
113      * @param decryptKey 解密密钥
114      * @return 解密后的string
115      */
116     private static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
117         return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
118     }
119 
120 }

这个时候在MAC下就可以正常运行了,在Window以及Linux上都可以正常运行。

 

posted @ 2018-01-23 15:38  codegeekgao  阅读(44320)  评论(0编辑  收藏  举报