使用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上都可以正常运行。
作者:撩琼不止
出处:https://www.cnblogs.com/codegeekgao/
github:https://github.com/codegeekgao
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。