内容要点
本文实现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.jar
和US_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