一.前言
AES(Advanced Encryption Standard),高级加密标准,是美国政府用于替换DES的一种加密算法标准,Java SDK中包含了部分AES的实现,但javadoc对于算法的描述非常少,本文将解释Java AES实现的使用和原理。
二.示例代码
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
|
importjavax.crypto.Cipher;
importjavax.crypto.spec.SecretKeySpec;
public
classAesECB{
public
static
byte[]Encrypt(
byte[]text,
byte[]key)
throwsException{
Cipher cipher=Cipher.getInstance(
"AES/ECB/PKCS5Padding");
// default, same as "AES"
// Cipher cipher = Cipher.getInstance("AES"); // same as above
cipher.init(Cipher.ENCRYPT_MODE,aesKey);
returncipher.doFinal(text);
}
public
static
byte[]Decrypt(
byte[]text,
byte[]key)
throwsException{
SecretKeySpec aesKey=
newSecretKeySpec(key,
"AES");
Cipher cipher=Cipher.getInstance(
"AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE,
aesKey);
returncipher.doFinal(text);
}
public
static
Stringbytes2hex(
byte[]bytes){
StringBuilder sb=
newStringBuilder();
for(
inti=
0;i<bytes.length;i++){
Stringtemp=(
Integer.toHexString(bytes[i]&
0XFF));
if(temp.length()==
1){
temp=
"0"+temp;
}
sb.append(temp);
sb.append(
" ");
}
returnsb.toString().toUpperCase();
}
public
static
voidmain(
String[]args){
try{
Stringkey=args[
0];
Stringtext=args[
1];
System.out.printf(
"text : %s\n",bytes2hex(text.getBytes()));
byte[]enc=AesECB.Encrypt(text.getBytes(),key.getBytes());
System.out.printf(
"encrypt: %s\n",bytes2hex(enc));
byte[]dec=
AesECB.Decrypt(enc,key.getBytes());
System.out.printf(
"decrypt: %s\n",bytes2hex(dec));
}
catch(Exceptione){
e.printStackTrace();
}
}
}
|
三.代码分析
JDK AES加密主要是几个步骤:
1.key变换
将传入的明文key做变换,AES的key固定为128bit,但变换后的key为加密位数的一倍,128bit的加密变换后key为256bit。注意加密和解密的key变换不一样。
2.加密解密
选择加密的模式和补齐填充方法生成加密实例,加密得到密文。
四.密码块工作模式
块密码工作模式(Block cipher mode of operation),是对于按块处理密码的加密方式的一种扩充,不仅仅适用于AES,包括DES, RSA等加密方法同样适用。
名称 | 英文 | 全名 | 方法 | 优点 | 缺点 |
ECB | Electronic codebook | 电子密码本 | 每块独立加密 | 1.分块可以并行处理 | 1.同样的原文得到相同的密文,容易被攻击 |
CBC | Cipher-block chaining | 密码分组链接 | 每块加密依赖于前一块的密文 | 1.同样的原文得到不同的密文 | 1.加密需要串行处理 |
PCBC | Propagating cipher-block chaining | 填充密码块链接 | CBC的扩种,较少使用 | 1.同样的原文得到不同的密文 | 1.加密需要串行处理 |
CFB | Cipher feedback | 密文反馈 |
|
|
|
OFB | Output feedback | 输出反馈模式 | 加密后密文与原文异或XOR |
| 1.能够对密文进行校验 |
CTR | Counter mode | 计数器模式 | 增加一个序列函数对所有密文快做XOR |
|
|
五.填充
填充(Padding),是对需要按块处理的数据,当数据长度不符合块处理需求时,按照一定方法填充满块长的一种规则。
名称 | 方法 | 示例 |
Zero padding | 最常见的方式,全填充0x00 | AA AA AA AA 00 00 00 00 |
ANSI X.923 | Zero的改进,最后一个字节为填充字节个数 | AA AA AA AA 00 00 00 04 |
ISO 10126 | 随机填充 | AA AA AA AA 81 A6 23 04 |
PKCS7 | ANSI X.923的变体 | AA AA AA AA AA AA AA 01 |
ISO/IEC 7816-4 | 以0x80开始作为填充开始标记,后续全填充0x00 | AA AA AA AA AA AA AA 80 |
六.JDK AES实现
1.实现支持
AES理论上支持128,192,256三种长度的密钥,几乎全部密码块工作模式和填充方法,但JDK 7中只实现如下四种AES加密算法:
(1)AES/CBC/NoPadding (128)
(2)AES/CBC/PKCS5Padding (128)
(3)AES/ECB/NoPadding (128)
(4)AES/ECB/PKCS5Padding (128)
2.使用须知
(1)缺省模式和填充为"AES/ECB/PKCS5Padding",Cipher.getInstance("AES")与Cipher.getInstance("AES/ECB/PKCS5Padding")等效。
(2)JDK的PKCS5Padding实际是上述的PKCS7的实现。
(3)由于AES是按照16Byte为块进行处理,对于NoPadding而言,如果需要加密的原文长度不是16Byte的倍数,将无法处理抛出异常,其实是由用户自己选择Padding的算法。密文则必然是16Byte的倍数,否则密文肯定异常。
(4)如果加密为PKCS5Padding,解密可以选择NoPadding,也能解密成功,内容为原文加上PKCS5Padding之后的结果。
(5)如果原文最后一个字符为>=0x00&&<=0x10的内容,PKCS5Padding的解密将会出现异常,要么是符合PKCS5Padding,最后的内容被删除,要么不符合,则解密失败抛出异常。对此有两种思路,一是原文通过Base64编码为可见字符,二是原文自带长度使用NoPadding解密。
七.参考
(1)AES(Wiki)
(2)Block cipher mode of operation(Wiki)
(3)块密码的工作模式(Wiki)
(4)Padding(Wiki)
(5)PKCS(Wiki)
(6)JAVA 7 Cipher