java AES使用

java提供AES算法支持。支持的密钥长度为:128, 192, 或256位。由于美国进出口限制,默认的jre只支持128位,也就是16个字节的密钥。

支持的工作模式:

  • NONE
  • CBC
  • CCM
  • CFB, CFBx
  • CTR
  • CTS
  • ECB
  • GCM
  • OFB, OFBx
  • PCBC

支持的填充方式:

  • NoPadding
  • ISO10126Padding
  • OAEPPadding
  • PKCS1Padding
  • PKCS5Padding
  • SSL3Padding

当使用Cipher.getInstance("AES")时,默认获取的是AES/ECB/PKCS5Padding对应的实例。实际使用中这里一定要注意一下,建议实际应用中一定要显示指定工作模式和填充方式。若不显示指定,在跨语言、跨类库或跨系统调用时,容易踩坑。

java aes示例

java 版本 : 1.8。

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
package com.cloudin.commons.security;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
* Created by YFHan on 2017/4/4 0004.
*/
public class AESHelper {

/**
* 算法名称
*/
public static final String ALGORITHM_NAME ="AES";

/**
* java aes 算法默认工作模式
*/
public static final String DEFAULT_MODE = "ECB";

/**
* java aes 算法默认填充方式
*/
public static final String DEFAULT_PADDING = "PKCS5Padding";

/**
* java aes 算法默认的密码实例
*/
public static final String DEFAULT_CHIPHER_INSTANCE = "AES/ECB/PKCS5Padding";

/**
* 对指定内容使用指定秘钥进行AES(128)加密,并返回加密后的字节数组
*
* @param content 待加密的内容
* @param password 加密秘钥
* @return
*/
public static byte[] encrypt(byte[] content, byte[] password) {
Cipher cp = null;
try {
SecretKeySpec skeySpec = new SecretKeySpec(password, ALGORITHM_NAME);
cp = Cipher.getInstance(DEFAULT_CHIPHER_INSTANCE); // 算法/模式/填充
cp.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
return cp.doFinal(content);

} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return null;
}

/**
* 对指定内容使用指定秘钥进行AES(128)解密,并返回解密后的字节数组
*
* @param content 待解密的内容
* @param password 解密秘钥
* @return
*/
public static byte[] decrypt(byte[] content, byte[] password) {
try {
SecretKeySpec skeySpec = new SecretKeySpec(password, ALGORITHM_NAME);
Cipher cp = Cipher.getInstance(DEFAULT_CHIPHER_INSTANCE); // 算法/模式/填充
cp.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));

return cp.doFinal(content);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return null;
}
}

常见问题

java aes密钥长度限制

由于美国进出口限制,jre自带的aes算法限制了密钥长度为16字节。这时需要使用JCE无限制权限策略的jar包覆盖jvm自带的jar包。

下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html

java 和 js互相加解密问题

java和js互相加解密时,如果不指定工作模式和填充方式,会失败。在js中,一般使用crypto-js库来加解密。但是该类库默认的工作模式是CBC,默认填充方式PKCS7,与java的默认方式不一致。

很多同学在使用AES算法时,不显示指定工作模式和填充方式,在这里就会屡屡出错。问题就出在java和js(crypto-js)默认的工作模式和填充方式不一致。这里只要将两者的工作模式和填充指定一样即可。

推荐一种方式: js采用AES/CBC/ZeroPadding方式加密。由于java没有提供ZeroPadding填充方式,可以使用AES/CBC/NoPadding方式解密,解密后从后往前依次剔除0x00的字节,遇到非0x00的字节时停止。剩下的字节就是解密后的结果。不过,这种方式需要注意,原始文本转byte数组后,最后一个字节不能是0x00。如果是java加密,js解密,将过程反过来即可。

参考

AES java