为了数据安全,不直接明文暴露,我们会对数据进行加密,前面我们学习了使用哈希算法完成对数据的加密,但哈希算法的加密处理是单向的、不可逆。但在很多场景中我们不仅需要对数据加密,还需要能够把加密后的内容还原为明文。这时我们要用到加密算法来完成加密和解密的操作,加密算法同样是基于秘钥来实现的。
常用的加密算法不仅有AES算法还有DES算法、IDEA算法
算法 |
密钥长度 |
工作模式 |
填充模式 |
DES |
56/64 |
ECB/CBC/PCBC/CTR/... |
NoPadding/PKCS5Padding/... |
AES |
128/192/256 |
ECB/CBC/PCBC/CTR/... |
NoPadding/PKCS5Padding/PKCS7Padding/... |
IDEA |
128 |
ECB |
PKCS5Padding/PKCS7Padding/... |
其中DES算法的秘钥长度过于短,很容易在段时间内被暴力穷举破解,不安全。
AES是常用的对称加密算法之一,所谓对称加密,就是加密和解密操作使用同一把秘钥完成。
AES算法中又分为两种工作模式:ECB和CBC,下面我们依次介绍:
它需要一个固定长度的密钥,会将固定的明文会生成固定的密文。
为了更清楚的了解AES算法加密步骤,我们把加密和解密的过程封装为不同的方法
加密(解密)步骤如下:
1、 创建密码对象Cipher,需要依次传入算法/工作模式/填充模式
2、根据key的字节内容【严格规范】,"恢复"为秘钥对象(SecretKey)
3、初始化秘钥:设置当前初始化模式【ENCRYPT_MODE(加密)|DECRYPT_MODE(解密)】、秘钥对象
4、调用Cipher对象的doFinal()对原始内容(字节),进行【加密|解密】
下面在我们的测试类中完成加密和解密的一个例子:
创建一个128位(16字节)的秘钥数组,通过AES算法+ECB模式对原文“天生我材必有用飞流直下三千尺”进行操作
运行结果:
AES算法中对秘钥的长度有严格的要求,有三种不同的秘钥长度规模支持ASE算法,分别是128(16字节)位、192(24字节)位、256(32字节)位。
在ECB模式下,同一个秘钥产生的密文是固定的
同一个秘钥产生的加密后的内容是固定不变的,这和我们前面哈希算法中加密后的结果是类似的,但哈希算法并不基于秘钥,它是通过"加盐"的方式把随机“盐值”与要加密的数据一同加密,使得每次加密后的结果都是不同的,需要保存“盐值”。那么在AES算法中为了提高安全性,还提供了另一种模式:CBC,那它是如何实现的呢?
它需要一个随机数作为Iv参数,这样对于同一份明文,每次生成的密文都不同
同样我们将加密和解密封装为两个方法
CBC模式下的大体加密步骤与ECB模式一致,由于其中涉及了动态的Iv参数,所以在初始化秘钥之前需要获取到Iv参数
1、 创建密码对象Cipher,需要依次传入算法/工作模式/填充模式
2、根据key的字节内容【严格规范】,"恢复"为秘钥对象(SecretKey)
3、创建IV参数:
3.1)通过SecureRandom类的静态方法getInstanceStrong()获取随机数生成器SecureRandom
3.2)设置SecureRandom对象的种子长度,返回随机成的种子数组
3.3)将种子数组通过IvParameterSpec类包装为Iv参数
3、初始化秘钥:设置当前初始化模式【ENCRYPT_MODE(加密)】、秘钥对象、Iv参数
4、调用Cipher对象的doFinal()对原始内容(字节),进行【加密】并临时存储加密后返回的数组
5、将随机生产的种子数组和加密后返回的数组进行合并后返回
这里数组的合并我们单独封装在一个join()中,代码如下:
通过调用2次System类的静态方法arraycopy()实现,返回合并后的数组
以上是加密的操作,下面是解密操作:
1、 把input分割成IV和密文分别存储
2、 创建密码对象Cipher,需要依次传入算法/工作模式/填充模式
3、根据key的字节内容【严格规范】,"恢复"为秘钥对象(SecretKey)
4、将存储IV参数的数组包装为IvParameterSpec对象
5、初始化秘钥:设置当前初始化模式【DECRYPT_MODE(解密)】、秘钥对象、Iv参数
6、调用Cipher对象的doFinal()对密文内容(字节)进行解密并返回
同样在测试类中完成加密解密操作:
采用256位(32字节)的秘钥加进行AES算法+CBC模式对“巴斯光年,你好”操作
CBC模式中同一内容在相同的秘钥下会产生不同的加密结果
在运用CBC模式进行加密/解密操作,需要将产生随机种子(Iv参数)数组与密文数组合并保存
在解密时传入合并的数组,对其进行分隔就能够获取到Iv参数并对其再封装IvParameterSpec类型对象完成解密操作。
小结: