一.前言html
AES(Advanced Encryption Standard),高级加密标准,是美国政府用于替换DES的一种加密算法标准,Java SDK中包含了部分AES的实现,但javadoc对于算法的描述很是少,本文将解释Java AES实现的使用和原理。java
二.示例代码算法
import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; public class AesECB { public static byte[] Encrypt(byte[] text, byte[] key) throws Exception { SecretKeySpec aesKey = new SecretKeySpec(key, "AES"); 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); return cipher.doFinal(text); } public static byte[] Decrypt(byte[] text, byte[] key) throws Exception { SecretKeySpec aesKey = new SecretKeySpec(key, "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, aesKey); return cipher.doFinal(text); } public static String bytes2hex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String temp = (Integer.toHexString(bytes[i] & 0XFF)); if (temp.length() == 1) { temp = "0" + temp; } sb.append(temp); sb.append(" "); } return sb.toString().toUpperCase(); } public static void main(String[] args) { try { String key = args[0]; String text = 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 (Exception e) { e.printStackTrace(); } } }
三.代码分析api
JDK AES加密主要是几个步骤:oracle
1.key变换app
将传入的明文key作变换,AES的key固定为128bit,但变换后的key为加密位数的一倍,128bit的加密变换后key为256bit。注意加密和解密的key变换不同。ide
2.加密解密函数
选择加密的模式和补齐填充方法生成加密实例,加密获得密文。ui
四.密码块工做模式编码
块密码工做模式(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