一、前言
1、Redeme
- 如果对AES加密解密了解的话,可以跳过目录二,直接看目录三目录四实例操作;
- 本博文主要是对js里面CryptoJS进行逆向,并用python进行还原实现,只用于js逆向交流学习
二、对称加密解密AES
1、对称加密与非对称加密
对称加密
:加密和解密时使用同一个密钥,加密速度非常快,适合经常发送数据的场合;缺点是密钥的传输比较麻烦;
非对称加密
:加密和解密时使用不同密钥,是用数学上的难解问题构造的,通常加密解密的速度比较慢,适合偶尔发送数据的场合,优点是密钥传输方便;常见的非对称加密算法为RSA、ECC和EIGamal;
2、AES对称加密介绍
- AES(Advanced Encryption Standard),是美国联邦政府采用的一种高级加密标准,这个标准用来替代原先的DES,也是最常见的对称加密算法;
- AES只有一个密钥key,其加密与解密需要双方确定好key,且密钥key 长度必须为16(AES-128)、24(AES-192)、或32(AES-256)Bytes 长度,分别对应了不同的算法;
- 密钥越长,安全性越高,但加解密花费时间也越长,默认的是16字节(AES-128),其安全性完全够用;
- AES只是个基本算法,实现AES有几种模式,主要有ECB、CBC、CFB、OFB、CTR:
3、实现AES的4种模式
ECB模式(电子密码本模式:Electronic codebook)
:ECB是最简单的块密码加密模式,加密前根据加密块大小(如AES为128位)分成若干块,之后将每块使用相同的密钥单独加密,解密同理CBC模式(密码分组链接:Cipher-block chaining)
:CBC模式对于每个待加密的密码块在加密前会先与前一个密码块的密文异或然后再用加密器加密。第一个明文块与一个叫初始化向量的数据块异或CFB模式(密文反馈:Cipher feedback)
:与ECB和CBC模式只能够加密块数据不同,CFB能够将块密文(Block Cipher)转换为流密文(Stream Cipher)OFB模式(输出反馈:Output feedback)
:OFB是先用块加密器生成密钥流(Keystream),然后再将密钥流与明文流异或得到密文流,解密是先用块加密器生成密钥流,再将密钥流与密文流异或得到明文,由于异或操作的对称性所以加密和解密的流程是完全一样的
三、网站案例分析
1、准备工作
- 网址源:由于只是用于学习记录,网址源就不提供了
- chrome浏览器开发者工具分析
2、分析js流程步骤
3、本地运行前端抠出来的CryptoJS脚本
- 前端定义的n其实就是CryptoJS我并没有直接复制,而是通过本地的node直接导入CryptoJS库,此时只需要将关键代码扣出来即可;
- 本地需安装node环境,然后再安装crypto-js库:
npm install crypto-js
重要参数
:key是密钥;iv是密钥偏移量;未指定模式默认CBC模式;padding是用来填充数据的;var CryptoJS = require("crypto-js");
var encrypt_req = function(e, l) {
return e = CryptoJS.enc.Utf8.parse(e),
l = CryptoJS.enc.Utf8.parse(l),
CryptoJS.AES.encrypt(l, e, {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: e
}).toString()
}
var decrypt_req = function(e, l) {
e = CryptoJS.enc.Utf8.parse(e);
var a = CryptoJS.AES.decrypt(l, e, {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: e
});
return CryptoJS.enc.Utf8.stringify(a).toString()
}
console.log(encrypt_req("8c18266c4e8fa5de", '{"Type":0,"page":3,"expire":1596461032894}'));
console.log(decrypt_req("8c18266c4e8fa5de", '7zHGSW218ARpzbHHsA90NuWHufnCLJo94vGad3zzkANQ3sFIWhHY6pDLzelv9XUO'));
四、通过Python还原CryptoJS
1、AES_CBC模式参数
key
:加密的时候用秘钥,解密的时候需要同样的秘钥才能解出来,必须是16位字节或者24位字节或者32位字节字符串
:加密或解密的参数,字节长度需要是16位的倍数模式
:aes 加密常用的有 ECB 和 CBC 模式等iv
:偏移量 ,这个参数在 ECB 模式下不需要,在 CBC 模式下需要。
2、Python模拟上面的CryptoJS脚本
- python调用js三种方式:要么还原js;要么通过execjs脚本执行,要么通过node布服务执行;
- python安装Cryptojs的库:
pip install pycryptodome
from Crypto.Cipher import AES
import base64
from Crypto.Util.Padding import pad
import json
def aes_cbc_encrypt_text(decrypt_text: str, key: str, iv: str) -> str:
"""
加密AES_CBC的明文
:param decrypt_text: 明文
:param key: 密钥
:param iv: 密钥偏移量
:return: 密文
"""
aes2 = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
encrypt_text = aes2.encrypt(pad(decrypt_text.encode('utf-8'), AES.block_size, style='pkcs7'))
encrypt_text = str(base64.encodebytes(encrypt_text), encoding='utf-8').replace("\n", "")
return encrypt_text
def aes_cbc_decrypt_js_text(encrypt_text: str, key: str, iv: str) -> str:
"""
解密AES_CBC的密文
:param encrypt_text: 密文
:param key: 密钥
:param iv: 密钥偏移量
:return:解密后的数据
example_url_learn_js_base64: aHR0cDovL2NyZWRpdC5jdXN0b21zLmdvdi5jbi8=
"""
decode_encrypt_text = base64.b64decode(encrypt_text)
aes2 = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
decrypt_text = aes2.decrypt(decode_encrypt_text).decode('utf8')
decrypt_text = decrypt_text.replace(b'\x00'.decode(), "").replace("", "")
return decrypt_text
"""由于只是用于学习,原网站的key和iv我已保密, 以下脚本并不能直接运行"""
decrypt_str = '{"Type":0,"page":3,"expire":1596461032894}'
key_str = "55****"
iv_str = "55****"
encrypt_str = aes_cbc_encrypt_text(decrypt_str, key_str, iv_str)
print(encrypt_str)
encrypt_str = "待解密字符串, 需自己替换,为保证原网站安全,暂不放"
key_str = "0a1******"
iv_str = "0a1******"
decrypt_str = aes_cbc_decrypt_js_text(encrypt_str, key_str, iv_str)
print(json.loads(decrypt_str)['list'])