JAVA与NodeJS实现AES加密

内容要点

本文实现java与nodejs的AES加密方式如下,并可实现java加密,nodejs解密或者nodejs加密,java解密

  • aes-128-ecb
  • aes-256-ecb
  • aes-128-cbc
  • aes-256-cbc

java实现AES

注意

Java本身限制密钥的长度最多128位,而AES256需要的密钥长度是256位,因此需要到Java官网上下载一个Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files。在Java SE的下载页面下面的Additional Resources那里会有下载链接。下载后打开压缩包,里面有两个jar文件:
local_policy.jarUS_export_policy.jar
把这两个jar文件解压到JRE目录下的lib/security文件夹,覆盖原来的文件。这样Java就不再限制密钥的长度了,否则编译会报错:

java.security.InvalidKeyException: Illegal key size

import org.apache.commons.lang.StringUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.spec.AlgorithmParameterSpec;

public class EncodeUtil {

    public static void main(String[] args) throws Exception {
        //key是16进制,需要转换为bytes,转换后bytes长度为16,即aes128,如果bytes长度是32则是aes256
        //也就是说keybytes.length须满足16的整数倍
        String key128 = "c4b84456c1379bec99c4d1b7e9f13173";
        String key256 = "c4b84456c1379bec99c4d1b7e9f13173c4b84456c1379bec99c4d1b7e9f13173";
        //iv.length须满足16的整数倍
        byte[] iv = "abcdefgh12345678".getBytes("UTF-8");
        String content_str = "helloworld 你好";
        byte[] contentbytes = content_str.getBytes("utf-8");

        //ecb128 bytes
        byte[] encryptbytes = EncodeUtil.aesEncryptToECB(contentbytes,key128);
        byte[] decryptbytes = EncodeUtil.aesDecryptToECB(encryptbytes,key128);
        System.out.println(new String(decryptbytes,"utf-8"));

        //ecb256 bytes
        encryptbytes = EncodeUtil.aesEncryptToECB(contentbytes,key256);
        decryptbytes = EncodeUtil.aesDecryptToECB(encryptbytes,key256);
        System.out.println(new String(decryptbytes,"utf-8"));

        //ecb128 String
        String encryptString = EncodeUtil.aesEncryptToECB(content_str,key128);
        String decryptString = EncodeUtil.aesDecryptToECB(encryptString,key128);
        System.out.println(decryptString);

        //ecb256 String
        encryptString = EncodeUtil.aesEncryptToECB(content_str,key256);
        decryptString = EncodeUtil.aesDecryptToECB(encryptString,key256);
        System.out.println(decryptString);

        //cbc128 bytes
        encryptbytes = EncodeUtil.aesEncryptToCBC(contentbytes,key128,iv);
        decryptbytes = EncodeUtil.aesDecryptToCBC(encryptbytes,key128,iv);
        System.out.println(new String(decryptbytes,"utf-8"));

        //cbc256 bytes
        encryptbytes = EncodeUtil.aesEncryptToCBC(contentbytes,key256,iv);
        decryptbytes = EncodeUtil.aesDecryptToCBC(encryptbytes,key256,iv);
        System.out.println(new String(decryptbytes,"utf-8"));

        //cbc128 String
        encryptString = EncodeUtil.aesEncryptToCBC(content_str,key128,iv);
        decryptString = EncodeUtil.aesDecryptToCBC(encryptString,key128,iv);
        System.out.println(decryptString);

        //cbc256 String
        encryptString = EncodeUtil.aesEncryptToCBC(content_str,key256,iv);
        decryptString = EncodeUtil.aesDecryptToCBC(encryptString,key256,iv);
        System.out.println(decryptString);

    }

    /**
     * base 64 encode
     *
     * @param bytes 待编码的byte[]
     * @return 编码后的base 64 code
     */
    public static String base64Encode(byte[] bytes) {
        return new BASE64Encoder().encode(bytes);
    }

    /**
     * base 64 decode
     *
     * @param base64Code 待解码的base 64 code
     * @return 解码后的byte[]
     * @throws Exception
     */
    public static byte[] base64Decode(String base64Code) throws Exception {
        return StringUtils.isEmpty(base64Code) ? null : new BASE64Decoder().decodeBuffer(base64Code);
    }

     /**
     * 验证密钥长度是否有效
     *
     * @param key 密钥bytes
     * @throws Exception
     */
    public static void checkkey(byte[] key) throws Exception {

        if(key.length != 16 && key.length != 32) {
            throw new Exception("密钥长度错误,key byte[]必须是16或者32位");
        }
    }

    /**
     * AES加密 aes-128/256-ecb
     *
     * @param content    待加密的内容
     * @param encryptKey 加密密钥
     * @return 加密后的byte[]
     * @throws Exception
     */
    public static byte[] aesEncryptToECB(byte[] content, String encryptKey) throws Exception {
        byte[] key = org.apache.commons.codec.binary.Hex.decodeHex(encryptKey.toCharArray());
        checkkey(key);
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"));
        return cipher.doFinal(content);
    }



    /**
     * AES加密 aes-128/256-ecb
     *
     * @param content    待加密的内容
     * @param encryptKey 加密密钥
     * @return 加密后的base64字符串
     * @throws Exception
     */
    public static String aesEncryptToECB(String content, String encryptKey) throws Exception {
        byte[] key = org.apache.commons.codec.binary.Hex.decodeHex(encryptKey.toCharArray());
        checkkey(key);
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"));
        return base64Encode(cipher.doFinal(content.getBytes("utf-8")));
    }


    /**
     * AES解密 aes-128/256-ecb
     *
     * @param content 待解密的byte[]
     * @param decryptKey   解密密钥
     * @return 解密后的byte[]
     * @throws Exception
     */
    public static byte[] aesDecryptToECB(byte[] content, String decryptKey) throws Exception {
        byte[] key = org.apache.commons.codec.binary.Hex.decodeHex(decryptKey.toCharArray());
        checkkey(key);
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"));
        byte[] decryptBytes = cipher.doFinal(content);
        return decryptBytes;
    }



    /**
     * AES解密 aes-128/256-ecb
     *
     * @param content 待解密的byte[]
     * @param decryptKey   解密密钥
     * @return 解密后的String
     * @throws Exception
     */
    public static String aesDecryptToECB(String content, String decryptKey) throws Exception {
        byte[] key = org.apache.commons.codec.binary.Hex.decodeHex(decryptKey.toCharArray());
        checkkey(key);
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"));
        byte[] decryptBytes = cipher.doFinal(base64Decode(content));
        return new String(decryptBytes,"utf-8");
    }


    /**
     * AES加密 aes-128/256-cbc
     *
     * @param content 待解密的byte[]
     * @param encryptKey   加密密钥
     * @param iv 偏移
     * @return 解密后的byte[]
     * @throws Exception
     */
    public static byte[] aesEncryptToCBC(byte[] content, String encryptKey,byte[] iv) throws Exception {
        byte[] key = org.apache.commons.codec.binary.Hex.decodeHex(encryptKey.toCharArray());
        checkkey(key);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        //算法参数
        AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"),paramSpec);
        return cipher.doFinal(content);
    }

    /**
     * AES解密 aes-128/256-cbc
     *
     * @param content 待解密的byte[]
     * @param decryptKey   解密密钥
     * @param iv 偏移
     * @return 解密后的byte[]
     * @throws Exception
     */
    public static byte[] aesDecryptToCBC(byte[] content, String decryptKey,byte[] iv) throws Exception {
        byte[] key = org.apache.commons.codec.binary.Hex.decodeHex(decryptKey.toCharArray());
        checkkey(key);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        //算法参数
        AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"),paramSpec);
        return cipher.doFinal(content);
    }

    /**
     * AES加密 aes-128/256-cbc
     *
     * @param content 待解密的byte[]
     * @param encryptKey   加密密钥
     * @param iv 偏移
     * @return 解密后的byte[]
     * @throws Exception
     */
    public static String aesEncryptToCBC(String content, String encryptKey,byte[] iv) throws Exception {
        byte[] key = org.apache.commons.codec.binary.Hex.decodeHex(encryptKey.toCharArray());
        checkkey(key);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        //算法参数
        AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"),paramSpec);
        return base64Encode(cipher.doFinal(content.getBytes("utf-8")));
    }

    /**
     * AES解密 aes-128/256-cbc
     *
     * @param content 待解密的byte[]
     * @param decryptKey   解密密钥
     * @param iv 偏移
     * @return 解密后的byte[]
     * @throws Exception
     */
    public static String aesDecryptToCBC(String content, String decryptKey,byte[] iv) throws Exception {
        byte[] key = org.apache.commons.codec.binary.Hex.decodeHex(decryptKey.toCharArray());
        checkkey(key);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        //算法参数
        AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"),paramSpec);
        byte[] decryptBytes = cipher.doFinal(base64Decode(content));
        return new String(decryptBytes,"utf-8");
    }
}

nodejs

说明

以下nodejs代码来源于 aes-cross项目

/**
 * "AES/cbc/pkcs5Padding" encription and decription.
 * setAutoPadding(true) is actually pkcs5Padding,.
 */
'use strict';

var crypto = require('crypto');

var CBC = 'cbc';
var ECB = 'ecb';
var NULL_IV = new Buffer([]);

var IV = new Buffer([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
var cipherMode = ECB;
var keySize = 128;
var algorithm;
setAlgorithm();
var outputEncoding = 'base64';
var inputEncoding = 'utf8';

function setAlgorithm() {
    algorithm = 'aes-' + keySize + '-' + cipherMode;
}

function setCipherMode(mode) {
    if (mode !== CBC && mode !== ECB) {
        throw ('AES.setCipherMode error: ' + mode);
    }
    cipherMode = mode;
    setAlgorithm();
}

function setKeySize(size) {
    if (size !== 128 && size !== 256) {
        throw ('AES.setKeySize error: ' + size);
    }
    keySize = size;
    setAlgorithm();
    // console.log('setKeySize:%j',keySize);
}

/**
 * the key must match the keySize/8 , like:16 ,32
 * @param  {Buffer} key
 * @return {}
 */
function checkKey(key) {
    if (!key) {
        throw 'AES.checkKey error: key is null ';
    }
    if (key.length !== (keySize / 8)) {
        throw 'AES.checkKey error: key length is not ' + (keySize / 8) + ': ' + key.length;
    }
}

/**
 * buffer/bytes encription
 * @param  {Buffer} buff
 * @param  {Buffer} key  the length must be 16 or 32
 * @param  {Buffer} [newIv]   default is [0,0...0]
 * @return {encripted Buffer}
 */
function encBytes(buff, key, newIv) {
    checkKey(key);
    var iv = newIv || IV;
    if (cipherMode === ECB) iv = NULL_IV;
    var cipher = crypto.createCipheriv(algorithm, key, iv);
    cipher.setAutoPadding(true);
    var re = Buffer.concat([cipher.update(buff), cipher.final()]);
    // console.log('enc re:%s,len:%d', printBuf(re), re.length);
    return re;
}

/**
 * text encription
 * @param  {string} text
 * @param  {Buffer} key         the length must be 16 or 32
 * @param  {Buffer} [newIv]       default is [0,0...0]
 * @param  {string} [input_encoding]  ["utf8" -default,"ascii","base64","binary"...](https://nodejs.org/api/buffer.html#buffer_buffer)
 * @param  {string} [output_encoding] ["base64" -default,"hex"]
 * @return {string}                 encription result
 */
function encText(text, key, newIv, input_encoding, output_encoding) {
    checkKey(key);
    var iv = newIv || IV;
    if (cipherMode === ECB) iv = NULL_IV;
    var inEncoding = input_encoding || inputEncoding;
    var outEncoding = output_encoding || outputEncoding;
    var buff = new Buffer(text, inEncoding);
    var out = encBytes(buff, key, iv);
    var re = new Buffer(out).toString(outEncoding);
    return re;
}

/**
 * buffer/bytes decription
 * @param  {Buffer} buff
 * @param  {Buffer} key  the length must be 16 or 32
 * @param  {Buffer} [newIv] default is [0,0...0]
 * @return {encripted Buffer}
 */
function decBytes(buff, key, newIv) {
    checkKey(key);
    var iv = newIv || IV;
    if (cipherMode === ECB) iv = NULL_IV;
    var decipher = crypto.createDecipheriv(algorithm, key, iv);
    decipher.setAutoPadding(true);
    var out = Buffer.concat([decipher.update(buff), decipher.final()]);
    return out;
}

/**
 * text decription
 * @param  {string} text
 * @param  {Buffer} key         the length must be 16 or 32
 * @param  {Buffer} [newIv]       default is [0,0...0]
 * @param  {string} [input_encoding]  ["utf8" - default,"ascii","base64","binary"...](https://nodejs.org/api/buffer.html#buffer_buffer)
 * @param  {string} [output_encoding] ["base64"- default ,"hex"]
 * @return {string}                 decription result
 */
function decText(text, key, newIv, input_encoding, output_encoding) {
    checkKey(key);
    var iv = newIv || IV;
    if (cipherMode === ECB) iv = NULL_IV;
    var inEncoding = input_encoding || inputEncoding;
    var outEncoding = output_encoding || outputEncoding;
    var buff = new Buffer(text, outEncoding);
    var re = new Buffer(decBytes(buff, key, iv)).toString(inEncoding);
    return re;
}


exports.setCipherMode = setCipherMode;
exports.setKeySize = setKeySize;
exports.encText = encText;
exports.encBytes = encBytes;
exports.decText = decText;
exports.decBytes = decBytes;

// 以下为测试部分
// //key是16进制,需要转换为buffer,转换后buffer长度为16,即aes128,如果buffer长度是32则是aes256
// var key = new Buffer("c4b84456c1379bec99c4d1b7e9f13173", 'hex');
// var key256 = new Buffer("c4b84456c1379bec99c4d1b7e9f13173c4b84456c1379bec99c4d1b7e9f13173", 'hex');
// var str = "helloworld 你好";
// var buffer = new Buffer(str,"utf8");
//
// //aes-ecb-128 buffer
// var buffer_encrypt = encBytes(buffer,key);
// var crypto_buffer =decBytes(buffer_encrypt,key);
// var str = crypto_buffer.toString();
// console.log(str);
//
// //aes-ecb-128 string
// var text_encrypt = encText(str,key);
// var text_decrypt =decText(text_encrypt,key);
// console.log(text_decrypt);
//
// text_encrypt = encText(str,key,null,'utf8','base64');
// text_decrypt =decText(text_encrypt,key,null,'utf8','base64');
// console.log(text_decrypt);
//
// //aes-cbc-128 buffer
// setCipherMode(CBC);
// var iv = new Buffer("abcdefgh12345678","utf8");//字符串一定是16位
// buffer_encrypt = encBytes(buffer,key,iv);
// crypto_buffer =decBytes(buffer_encrypt,key,iv);
// str = crypto_buffer.toString();
// console.log(str);
//
// //aes-cbc-128 string
// text_encrypt = encText(str,key,iv);
// text_decrypt =decText(text_encrypt,key,iv);
// console.log(text_decrypt);
//
// text_encrypt = encText(str,key,iv,'utf8','base64');
// text_decrypt =decText(text_encrypt,key,iv,'utf8','base64');
// console.log(text_decrypt);
//
//
// //aes-ecb-256 buffer
// setKeySize(256);
// setCipherMode(ECB);
// buffer_encrypt = encBytes(buffer,key256);
// crypto_buffer =decBytes(buffer_encrypt,key256);
// str = crypto_buffer.toString();
// console.log("256=="+str);

参考资料

  • 用Java进行AES256-ECB-PKCS7Padding加密
  • aes-cross

你可能感兴趣的:(JAVA与NodeJS实现AES加密)