一.前言
AES(Advanced Encryption Standard),高级加密标准,是美国政府用于替换DES的一种加密算法标准,Java SDK中包含了部分AES的实现,但javadoc对于算法的描述非常少,本文将解释Java AES实现的使用和原理。
二.示例代码
三.代码分析
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解密。