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 &lt; buf.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
        String hex </span>= Integer.toHexString(buf[i] &amp; 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() &lt; 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 &lt; 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>

}
}