不论前途如何,不管发生什么事情,我们都不失去希望,希望是一种美德。——《雨果传》
1.加密算法
- 在密码学中,加密算法分为单向加密和双向加密。
- 单向加密包括
MD5
、SHA
等摘要算法,它们是不可逆的。 - 双向加密包括对称加密和非对称加密。双向加密是可逆的,存在密文的密钥。
- 对称加密是指加密和解密使用相同的密钥,包括
AES
加密、DES
加密等。 - 非对称加密是指加密和解密使用不同的密钥,包括
RSA
加密等。
2.AES介绍
AES: 高级加密标准(Advanced Encryption Standard)是美国联邦政府采用的一种区块加密标准,是目前最流行的一种
对称加密算法
。
- 是用来替代DES的新一代分组加密算法。
- AES支持三种长度的密钥:128位、192位、256位。
3.AES的加密过程(AES处理单位:字节)
AES
的加解密过程和DES
一样,都是通过分组加密、分组解密。所谓分组加密,就是将待加解密的内容按照128
位进行分组,将密钥按照128
位、192
位、256
位进行分组,分别将分组后的明文与相应分组后的密钥进行加解密。
加密: 明文与密钥分组后,对每组:明文组与密钥组处理 -> 轮密钥加 -> 10轮加密 -> 密文组 解密: 对每组:密文组 -> 轮密钥加 -> 10轮解密 -> 明文组
明文分组: 每组长度相等,都是128位(16字节); 密钥分组: 有128位、192位、256位,推荐加密轮数分别为 10、12、14
密钥组处理: 以密钥分组每组128位为例(则推荐加密轮数为10,前9次执行操作一样,第十次有所不同) 类似地,128位密钥也是用字节为单位的矩阵表示,通过密钥编排函数,形成具有44个元素的序列W[0],W[1], … ,W[43](每个元素4个字节);其中,W[0],W[1],W[2],W[3]为原始密钥,其余40个元素分为10组,每组4个元素(4*4=16字节),分别用于10轮加密。
AES加密算法涉及4种操作: 字节替代(SubBytes)
、行移位(ShiftRows)
、列混淆(MixColumns)
和轮密钥加(AddRoundKey
)。下图给出了AES加解密的流程:
- AddRoundKey (轮密钥加)— 矩阵中的每一个字节都与该次轮密钥(round key)做XOR运算;每个子密钥由密钥生成方案产生。
- SubBytes(字节替代) — 通过非线性的替换函数,用查找表的方式把每个字节替换成对应的字节。
- ShiftRows(行移位) — 将矩阵中的每个横列进行循环式移位。
- MixColumns (列混淆)— 为了充分混合矩阵中各个直行的操作。这个步骤使用线性转换来混合每列的四个字节。
4.代码实现
1.生成密钥
public static String genAesSecret(){
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
//密钥长度,单位:字节,AES支持128、192、256字节长度的密钥,上面文章已介绍
keyGenerator.init(128);
SecretKey sk = keyGenerator.generateKey();
byte[] b = sk.getEncoded();
return Base64.encodeBase64String(b);
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException("没有此算法");
}
}
2.AES加密
public static String aesEncrypt(String content) throws Exception {
//指定加密算法
Cipher cipher = Cipher.getInstance("AES");
//创建加密规则:指定key和加密类型
SecretKeySpec secretKeySpec = new SecretKeySpec(SECRET.getBytes(), "AES");
//指定加密模式为加密,指定加密规则
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
//调用加密方法
byte[] result = cipher.doFinal(content.getBytes());
//用Base64编码
return new String(java.util.Base64.getEncoder().encode(result));
}
3.AES解密
public static String aesDecrypt(String content) throws Exception {
//Base64解码
byte[] result = java.util.Base64.getDecoder().decode(content);
//指定加密算法
Cipher cipher = Cipher.getInstance("AES");
//创建加密规则:指定key和加密类型
SecretKeySpec secretKeySpec = new SecretKeySpec(SECRET.getBytes(), "AES");
//指定加密模式为解密,指定加密规则
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
return new String(cipher.doFinal(result));
}
注意:SECRET.getBytes()
我这里是一个常量密钥,通过密钥生成后写成常量SECRET
。
4.前端解密
安装依赖
npm install crypto-js --save-dev
// 引入
import CryptoJS from 'crypto-js'
// 密钥
const AES_KEY = 'P@S5W0rDK3yBACHU' // 后端提供
// 解密
export function decrypt (word) {
var key = CryptoJS.enc.Utf8.parse(AES_KEY)
var decrypt = CryptoJS.AES.decrypt(word, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
})
return CryptoJS.enc.Utf8.stringify(decrypt).toString()
}