hanqunfeng's blog

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
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("密钥长度错误,必须是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项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/**
* "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);

参考资料

热评文章