java实现AES加密(解决中文解密后乱码问题,解决传输字符串后解密报错的问题)
在对安全性要求比较高的报文做加密的时候,算法有很多种,我这里主要用到的就是 AES 加密算法。由于在国内使用,所以不可避免的要对中文进行加密和解密,而在这个过程中,发现,如果不做处理,很容易会出现中文乱码。
下面是常见的情况:
一、中文乱码
不对密码进行编码处理
byte[] decryptResult = decrypt(encryptResult, password); System.out.println("解密后:" + new String(decryptResult));
运行后
加密前:我是 shoneworn
解密后:鎴戞槸 shoneworn
二、对文字进行编码处理,但是在传输过程中草率的将 byte[] 转成 String, String code = new String(bytes); 由于 AES 加密算法要求密文是 16 位的倍数。所以,这么处理,在解密的时候,就会报各种错。比如下面的。
String code = new String(encryptResult); byte[] decryptResult = decrypt(code.getBytes(), password);
结果就.........
加密前:我是 shoneworn javax.crypto.BadPaddingException: Given final block not properly padded at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966) at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824) at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436) at javax.crypto.Cipher.doFinal(Cipher.java:2165) at com.ailin.test.AES.decrypt(AES.java:72) at com.ailin.test.AES.main(AES.java:173) Exception in thread "main" java.lang.NullPointerException at java.lang.String.<init>(Unknown Source) at com.ailin.test.AES.main(AES.java:174)
三、给功能正常的,能传中文的,不报错的 AES 加密加密算法源码
package com.ailin.test;import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;public class AES {
/**
* 加密
*
* @param content
* 需要加密的内容
* @param password
* 加密密码
* @return
*/
public static byte[] encrypt(String content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(password.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
byte[] result = cipher.doFinal(byteContent);
return result; // 加密
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * 解密 * * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> content * 待解密内容 * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> password * 解密密钥 * </span><span style="color: rgba(128, 128, 128, 1)">@return</span> <span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">byte</span>[] decrypt(<span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">[] content, String password) { </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> { KeyGenerator kgen </span>= KeyGenerator.getInstance("AES"<span style="color: rgba(0, 0, 0, 1)">); kgen.init(</span>128, <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SecureRandom(password.getBytes())); SecretKey secretKey </span>=<span style="color: rgba(0, 0, 0, 1)"> kgen.generateKey(); </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] enCodeFormat =<span style="color: rgba(0, 0, 0, 1)"> secretKey.getEncoded(); SecretKeySpec key </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> SecretKeySpec(enCodeFormat, "AES"<span style="color: rgba(0, 0, 0, 1)">); Cipher cipher </span>= Cipher.getInstance("AES");<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 创建密码器</span> cipher.init(Cipher.DECRYPT_MODE, key);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 初始化</span> <span style="color: rgba(0, 0, 255, 1)">byte</span>[] result =<span style="color: rgba(0, 0, 0, 1)"> cipher.doFinal(content); </span><span style="color: rgba(0, 0, 255, 1)">return</span> result; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 加密</span> } <span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (NoSuchAlgorithmException e) { e.printStackTrace(); } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (NoSuchPaddingException e) { e.printStackTrace(); } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (InvalidKeyException e) { e.printStackTrace(); } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IllegalBlockSizeException e) { e.printStackTrace(); } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (BadPaddingException e) { e.printStackTrace(); } </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; } </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * 将二进制转换成16进制 * * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> buf * </span><span style="color: rgba(128, 128, 128, 1)">@return</span> <span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> String parseByte2HexStr(<span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)"> buf[]) { StringBuffer sb </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> StringBuffer(); </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i < buf.length; i++<span style="color: rgba(0, 0, 0, 1)">) { String hex </span>= Integer.toHexString(buf[i] & 0xFF<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">if</span> (hex.length() == 1<span style="color: rgba(0, 0, 0, 1)">) { hex </span>= '0' +<span style="color: rgba(0, 0, 0, 1)"> hex; } sb.append(hex.toUpperCase()); } </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> sb.toString(); } </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * 将16进制转换为二进制 * * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> hexStr * </span><span style="color: rgba(128, 128, 128, 1)">@return</span> <span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">[] parseHexStr2Byte(String hexStr) { </span><span style="color: rgba(0, 0, 255, 1)">if</span> (hexStr.length() < 1<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] result = <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">byte</span>[hexStr.length() / 2<span style="color: rgba(0, 0, 0, 1)">]; </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i < hexStr.length() / 2; i++<span style="color: rgba(0, 0, 0, 1)">) { </span><span style="color: rgba(0, 0, 255, 1)">int</span> high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">int</span> low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16<span style="color: rgba(0, 0, 0, 1)">); result[i] </span>= (<span style="color: rgba(0, 0, 255, 1)">byte</span>) (high * 16 +<span style="color: rgba(0, 0, 0, 1)"> low); } </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result; } </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * 加密 * * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> content * 需要加密的内容 * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> password * 加密密码 * </span><span style="color: rgba(128, 128, 128, 1)">@return</span> <span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">[] encrypt2(String content, String password) { </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> { SecretKeySpec key </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> SecretKeySpec(password.getBytes(), "AES"<span style="color: rgba(0, 0, 0, 1)">); Cipher cipher </span>= Cipher.getInstance("AES/ECB/NoPadding"<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] byteContent = content.getBytes("utf-8"<span style="color: rgba(0, 0, 0, 1)">); cipher.init(Cipher.ENCRYPT_MODE, key);</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 初始化</span> <span style="color: rgba(0, 0, 255, 1)">byte</span>[] result =<span style="color: rgba(0, 0, 0, 1)"> cipher.doFinal(byteContent); </span><span style="color: rgba(0, 0, 255, 1)">return</span> result; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 加密</span> } <span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (NoSuchAlgorithmException e) { e.printStackTrace(); } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (NoSuchPaddingException e) { e.printStackTrace(); } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (InvalidKeyException e) { e.printStackTrace(); } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (UnsupportedEncodingException e) { e.printStackTrace(); } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IllegalBlockSizeException e) { e.printStackTrace(); } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (BadPaddingException e) { e.printStackTrace(); } </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> main(String[] args) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> UnsupportedEncodingException { String content </span>= "我是shoneworn"<span style="color: rgba(0, 0, 0, 1)">; String password </span>= "12345678"<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 加密</span> System.out.println("加密前:" +<span style="color: rgba(0, 0, 0, 1)"> content); </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] encode =<span style="color: rgba(0, 0, 0, 1)"> encrypt(content, password); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">传输过程,不转成16进制的字符串,就等着程序崩溃掉吧</span> String code =<span style="color: rgba(0, 0, 0, 1)"> parseByte2HexStr(encode); System.out.println(</span>"密文字符串:" +<span style="color: rgba(0, 0, 0, 1)"> code); </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] decode =<span style="color: rgba(0, 0, 0, 1)"> parseHexStr2Byte(code); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 解密</span> <span style="color: rgba(0, 0, 255, 1)">byte</span>[] decryptResult =<span style="color: rgba(0, 0, 0, 1)"> decrypt(decode, password); System.out.println(</span>"解密后:" + <span style="color: rgba(0, 0, 255, 1)">new</span> String(decryptResult, "UTF-8"<span style="color: rgba(0, 0, 0, 1)">)); //不转码会乱码 </span>
}
}