1.对称加密之AES
高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。高级加密标准已然成为对称密钥加密中最流行的算法之一。加密与解密时用同一个密钥的加密方式叫做对称加密,用不用密钥则是非对称加密。
AES支持三种长度的密钥:128位、192位、256位。
在进行AES加密前有一步很重要的步骤——填充,由于AES加密并不是一次性将明文加密成密文的,而是把明文拆分成一个个独立的明文块,且每个明文块都是128位
假设:有一段明文长度是200位,按每128位拆分的话,第二个明文块只有72位,不足128位,就需要对明文进行填充。
填充的方式有很多,这里我就只讲我用的填充方式——PKCS7Padding,当明文块少于16个字节,则在明文块末尾补足相应数量的字符,并且每个字节都等于缺少的字符数
比如:
1,2,3,4,5,6,7,8,9
这里有9个字节,不足16个字节,差7个字节,所以就补7个7变位
1,2,3,4,5,6,7,8,9,7,7,7,7,7,7,7
2.模式
AES加密有5种模式CBC、ECB、CTR、CFB、OFB,经常使用的是CBC模式,这里就以CBC模式进行讲解。
CBC需要添加密钥key和初始向量iv两个参数
3.Vue前端
代码如下:
import CryptoJS from 'crypto-js';
// 这是密钥,非常重要,可以是后台获取,或者是前后台约定好,注意保护
const key = CryptoJS.enc.Utf8.parse('xxxxxxxxxxxxxxxx');
const iv = CryptoJS.enc.Utf8.parse('xxxxxxxxxxxxxxxx');
/**
* 解密
* @param {String} word 解密内容
* @returns
*/
function decrypt(word) {
let base64 = CryptoJS.enc.Base64.parse(word);
let src = CryptoJS.enc.Base64.stringify(base64);
let decrypt = CryptoJS.AES.decrypt(src, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
});
let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
return decryptedStr.toString();
}
/**
* 加密
* @param {String} word 加密内容
* @returns
*/
function encrypt(word) {
let srcs = CryptoJS.enc.Utf8.parse(word);
var encrypted = CryptoJS.AES.encrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
});
return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}
function decrypt2json(word, size) {
let s = decrypt(word)
return (JSON.parse(s.substring(0, size)))
}
export default { decrypt, encrypt, decrypt2json };
4.python后端
代码如下:
from Crypto.Cipher import AES
import base64
key = 'xxxxxxxxxxxxxxxx'.encode('utf-8')
iv = 'xxxxxxxxxxxxxxxx'.encode('utf-8')
# 明文使用PKCS7填充
def pkcs7padding(text):
bs = 16
length = len(text)
bytes_length = len(text.encode('utf-8'))
padding_size = length if (bytes_length == length) else bytes_length
padding = bs - padding_size % bs
padding_text = chr(padding) * padding
return text + padding_text
# AES加密
def aes_encrypt(content):
cipher = AES.new(key, AES.MODE_CBC, iv)
# 处理明文
content_padding = pkcs7padding(content)
# 加密
encrypt_bytes = cipher.encrypt(content_padding.encode('utf-8'))
# 重新编码
result = str(base64.b64encode(encrypt_bytes), encoding='utf-8')
return result
# AES解密
def aes_decrypt(content, size: int):
cipher = AES.new(key, AES.MODE_CBC, iv)
content = base64.b64decode(content)
text = cipher.decrypt(content).decode('utf-8')
return text[:size]
if __name__ == '__main__':
m = '{"code":200,"data":{"apts":[]},"message":"内蒙古呼和浩特市新城区","success":true}'
l = len(m)
e = aes_encrypt(m)
d = aes_decrypt(e, l)
print("加密:", e)
print("解密:", d)
print(aes_decrypt('pOtVxMJ8HQPgQiwOcuAwlb3WxM8aguRtpoBJILNUhptXb8tC6kWaWxkLZ78YpfUro1ezbMlsPJBJySkBf5XwnA==', 35))
5.前端使用
请求:
// 对 data 进行加密
let txt = JSON.stringify(data)
let enc = aes.encrypt(txt)
let dat = {value: enc, size: txt.length}
响应处理
let r = aes.decrypt2json(response.data.value, response.data.size)
console.log(r.desc)
6.后端使用
请求处理
@router.post(path='/login')
async def login(request: Request, value: str = Body(..., embed=True), size: int = Body(..., embed=True)):
plaintext = aes_decrypt(value, size)
print(plaintext)
......
响应
@router.post(path='/login')
async def login(request: Request, value: str = Body(..., embed=True), size: int = Body(..., embed=True)):
res = {'res': None, 'desc': '内蒙古呼和浩特市'}
......
return {'value': aes_encrypt(json.dumps(res)), 'size': len(json.dumps(res))}