作者: wzw,架构组成员,原文发表在 https://blog.csdn.net/u014430366/article/details/79710571, 经同意发布到此
最近博主有 AES 加密的使用需求,遇到了一些意想不到的问题,承接之前的博文 基于 Java 加密快速入门(Base64、MD5、AES) 进一步探讨探讨 AES 加密
我个人一直拿 在线加解密工具 这个网页做在线验证,然而这个网页是不是标准的 AES 加解密我也很慌。。。
参考文献
Warn:下文是按照已阅读这些参考文献的前提条件写的
这篇介绍 AES 的译文很有意思,下文有些词汇来源于这篇译文(这篇译文到后边部分我彻底看晕了)
维基百科好像没什么说的,英文版不被墙已经暗示了很多东西,可以脑补出很多信息
知乎:AES128和AES256主要区别和安全程度是多少?他们对于机器的消耗是怎样的?两者性能如何?实际开发如何选择?
至于到底如何选择,见仁见智了,考虑到硬件升级换代、量子计算发展,128渐渐退出舞台是大势所趋,只是时间问题
这个人看起来就像是大佬 (:з」∠)
工作模式
其实指代的加密实现逻辑,似乎有 ECB、CBC、CTR、OFB、CFB,而这里面又分流加密(如OFB、CFB等)和块加密(如ECB、CBC等),留下了没有技术的泪水,更进一步了解肯定得啃理论书籍了。
站在门外查到一点资讯: CBC 适合传输长度长的报文,是 SSL 和 IPSec 的标准。Intel 甚至在他们的芯片中量身定制了底层指令来让AES执行地更快。
填充模式
Java 默认支持的填充只有
NoPadding(其实是为了方便用户实现自定义填充逻辑)
PKCS5Padding
ISO10126Padding
填充的意义其实是因为 AES 的设计,执行加密时,需加密的对象被拆分成了很多“状态矩阵”,这个矩阵大小就是16字节。这个”状态矩阵”无法被填满时,就需要填充,以满足加密对象是16字节的倍数。填充模式则是规定,用什么、怎么样去填满”状态矩阵”。根据基本的”搜商”,搜索 AES 填充模式即可,细节博主我还没弄明白,但查到 PKCS 5这种填充模式 是 PKCS 7的子集,PKCS 5是PKCS 7 的一种特例。
Java 里想要支持非默认的填充模式、工作模式要怎么办呢?
一种是自己实现填充逻辑,这里不多提。另一种就是找别人写好的了,例如BouncyCastle这个包提供的
(下方实验环境是 8-126 的 JDK,老的 JDK 有可能需要更复杂的操作去扩展)
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding","BC"); /* 承接上一篇,后续操作没什么区别 这里大致意思是用 BouncyCastle 包来实现 AES 功能,至少这样就支持 PKCS 7 填充了,别人造的轮子还真是好用括弧笑*/
秘钥
AES 是对称加密,采用相同的密钥对信息进行加密、解密。wiki 上说
AES is a variant of Rijndael which has a fixed block size of 128 bits, and a key size of 128, 192, or 256 bits.
我个人感觉是秘钥长度 就是128、192、256 位三种,我尝试用 Java (BouncyCastle 包)实现 AES 给出非 128、192、256 位的秘钥抛出这个异常似乎也是一种佐证
org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$1: Key length not 128/192/256 bits. (至于其他方式实现方法256位以内秘钥不报错很可能是其他实现方式有自己的补齐"秘钥"逻辑)
那么问题来了,秘钥的长度到底决定了什么呢?
漫画里:The number of repetitions depends on the size of the key
秘钥用于 AES 算法指定”明文”转换时的”轮数”
而”轮数”决定了 AES 算法的安全性,”轮数”越多越安全,同样也会越增加性能开销。AES 发明者们在安全性和效率之前做出权衡,然后定下了3档。
秘钥长度(位) | 轮数 |
---|---|
128 | 10 |
192 | 12 |
256 | 14 |
PS:顺带提一嘴,JDK 似乎是有秘钥长度限制的,默认限制到 128 位秘钥,老版 JDK 可能需要下载 JCE 扩展包并覆盖。够新的 JDK 会自带扩展,不过默认配置还是限制到128位秘钥。
够新的大概是这样:
应在 java.security 文件中设置新的 crypto.policy 安全属性,才能解除 128 位秘钥限制。配置文件里需要加上一行
crypto.policy=unlimited