今天花了一天的时间总是把AES加密这块做完了。总结下以备不时之需:网上版本太多了,还是自己写一些:

/***
 * 关于加解密JAVA一般使用的JCE,关于C++可以实现AES加解密的开源项目就多的数不胜数的。
 理论上上算法一样,对称密钥一样就能够互相识别了。
 相信很多人开始想法都同我一样,起初我JAVA用JCE,C++使用openssl。
 结果发现加密出的密文完全不相同。
 出现问题就要解决
 了解了一下JCE:
 JCE中AES支持五中模式:CBC,CFB,ECB,OFB,PCBC;支持三种填充:NoPadding,PKCS5Padding,ISO10126Padding。
 不支持SSL3Padding。不支持“NONE”模式。
 好原来有模式和填充一说。
 在OPENSSL中直接有一个CBC加解密函数。填充没找到,试过后发现C++加密出的内容比JAVA的要长出一截,前面的内容是完全一样的。
 这应该就出现在填充上。
 本来以为找到问题关键就应该很容易解决的。结果发现OPENSSL的填充是固定实现的,而我所需要解密的java端代码不能改动。
 一条路走不通咱就换条路。最后发现有一个开源项目Botan什么都有而且同JCE十分相似并且满足我要求垮平台,好就是它了。
 附:
 算法/模式/填充 16字节加密后数据长度 不满16字节加密后长度
 AES/CBC/NoPadding 16 不支持
 AES/CBC/PKCS5Padding 32 16
 AES/CBC/ISO10126Padding 32 16
 AES/CFB/NoPadding 16 原始数据长度
 AES/CFB/PKCS5Padding 32 16
 AES/CFB/ISO10126Padding 32 16
 AES/ECB/NoPadding 16 不支持
 AES/ECB/PKCS5Padding 32 16
 AES/ECB/ISO10126Padding 32 16
 AES/OFB/NoPadding 16 原始数据长度
 AES/OFB/PKCS5Padding 32 16
 AES/OFB/ISO10126Padding 32 16
 AES/PCBC/NoPadding 16 不支持
 AES/PCBC/PKCS5Padding 32 16
 AES/PCBC/ISO10126Padding 32 16
 可以看到,在原始数据长度为16的整数倍时,
 假如原始数据长度等于16*n,
 则使用NoPadding时加密后数据长度等于16*n
 ,其它情况下加密数据长度等于16*(n+1)。
 在不足16的整数倍的情况下,假如原始数据长度等于16*n+m[其中m小于16]
 ,除了NoPadding填充之外的任何方式,加密数据长度都等于16*(n+1)
 ;NoPadding填充情况下,CBC、ECB和PCBC三种模式是不支持的,CFB、OFB两种模式下则加密数据长度等于原始数据长度。
 */
package com.example.ex_crypto;
import java.io.UnsupportedEncodingException;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
/**
 * AES加密解密类
 *
 * @author xuxiong
 */
public class AESHelper {
    /** 算法/模式/填充 **/
    private static final String CipherMode = "AES/ECB/NoPadding";
    /**
     * 创建密钥
     *
     * @param password
     *            例如:"0123456701234567" 128位 16*8 所有密钥长度不能超过16字符中文占两个。192 24;
     *            256 32
     * @return SecretKeySpec 实例
     */
    private static SecretKeySpec createKey(String password) {
        byte[] data = null;
        if (password == null) {
            password = "";
        }
        StringBuffer sb = new StringBuffer(16);
        sb.append(password);
        while (sb.length() < 16) {
            sb.append("0");
        }
        if (sb.length() > 16) {
            sb.setLength(16);
        }
        try {
            data = sb.toString().getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return new SecretKeySpec(data, "AES");
    }
    /**
     * 加密字节数据
     *
     * @param content
     *            需要加密的字节数组
     * @param password
     *            密钥 128 <16个字节 192 <24,256 <32个字节
     * @return 加密完后的字节数组
     */
    public static byte[] encrypt(byte[] content, String password) {
        try {
            SecretKeySpec key = createKey(password);
            Cipher cipher = Cipher.getInstance(CipherMode);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] result = cipher.doFinal(content);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 加密(结果为16进制字符串)
     *
     * @param content
     *            要加密的字符串
     * @param password
     *            密钥
     * @return 加密后的16进制字符串
     */
    public static String encrypt(String content, String password) {
        byte[] data = null;
        try {
            data = content.getBytes("UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        data = encrypt(data, password);
        String result = byte2hex(data);
        return result;
    }
    /** 解密字节数组 **/
    public static byte[] decrypt(byte[] content, String password) {
        try {
            SecretKeySpec key = createKey(password);
            Cipher cipher = Cipher.getInstance(CipherMode);
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] result = cipher.doFinal(content);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /** 解密16进制的字符串为字符串 **/
    public static String decrypt(String content, String password) {
        byte[] data = null;
        try {
            data = hex2byte(content);
        } catch (Exception e) {
            e.printStackTrace();
        }
        data = decrypt(data, password);
        if (data == null)
            return null;
        String result = null;
        try {
            result = new String(data, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 字节数组转成16进制字符串
     *
     * @param b
     * @return 16进制字符串
     */
    public static String byte2hex(byte[] b) { // 一个字节的数,
        StringBuffer sb = new StringBuffer(b.length * 2);
        String tmp = "";
        for (int n = 0; n < b.length; n++) {
            // 整数转成十六进制表示
            tmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
            if (tmp.length() == 1) {
                sb.append("0");
            }
            sb.append(tmp);
        }
        return sb.toString().toUpperCase(); // 转成大写
    }
    /**
     * 将hex字符串转换成字节数组 *
     *
     * @param 16进制的字符串
     * @return 字节数组
     */
    private static byte[] hex2byte(String inputString) {
        if (inputString == null || inputString.length() < 2) {
            return new byte[0];
        }
        inputString = inputString.toLowerCase();
        int l = inputString.length() / 2;
        byte[] result = new byte[l];
        for (int i = 0; i < l; ++i) {
            String tmp = inputString.substring(2 * i, 2 * i + 2);
            result[i] = (byte) (Integer.parseInt(tmp, 16) & 0xFF);
        }
        return result;
    }
}

注意:创建密钥时要注意你用的是那种128,还是192还是256位 他们对应的密钥长度分别是16/24/32一个中文字符占用2个字节,今天就没有注意到这个,输出来的字符与实际的不一致,后来才发现。

最后调用方法就OK了。

//需要加密的字符  密钥
String encrypt = AESHelper.encrypt("0123456701234567", "0123456701234567");
// 加密完后的字符 密钥
String decrypt = AESHelper.decrypt(encrypt, "0123456701234567");

这样就可以了

153951224.png

153954694.png

好了这就样了。