请教一个 Python 中 Crypto 实现 JS 中 CryptoJS AES 加密解密的一个问题

2022-08-11 17:50:58 +08:00
 persona5

以这个在线工具为例: https://tool.oschina.net/encrypt

选择 AES ,明文输入 test content ,得到密文 U2FsdGVkX18rKzwlZ/7CleXiil1NCTu46Q9LkW7eh3s=

JS 中可以正常解密:

CryptoJS.AES.decrypt("U2FsdGVkX18rKzwlZ/7CleXiil1NCTu46Q9LkW7eh3s=", "12345").toString(CryptoJS.enc.Utf8)

'test content'

如下 py 实现可以做到互相加密解密,但是无法解密通过上面在线工具中获得的密文。

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad

key = '12345'
   
def encrypt(raw):
    raw = pad(raw.encode(), 16)
    cipher = AES.new(key.encode('utf-8'), AES.MODE_ECB)
    return base64.b64encode(cipher.encrypt(raw))

def decrypt(enc):
    enc = base64.b64decode(enc)
    cipher = AES.new(key.encode('utf-8'), AES.MODE_ECB)
    return unpad(cipher.decrypt(enc), 16)

上面在线工具没有让填写偏移量的地方,我就当作 ECB 模式,填充用 Pkcs7 来理解了,是我理解错了吗?

希望可以用 py 实现可以解密上面在线工具生成的密文。

1686 次点击
所在节点    程序员
12 条回复
yyf1234
2022-08-11 17:54:19 +08:00
nopadding 吧?
Wincer
2022-08-11 18:25:44 +08:00
CroptoJS 默认用的应该是 cbc mode ,以及 PKCS7Padding
ThirdFlame
2022-08-11 18:55:19 +08:00
Salted base64 解码可见。 不是标准的加密
yagamil
2022-08-11 19:44:28 +08:00
key 要 16 的倍数,你补全方法看看是不是不对。
py 代码无法在 ubunut 删运行
getcharch
2022-08-11 20:03:13 +08:00
https://github.com/brix/crypto-js/issues/293

CryptoJS 不会检测 key 长度,其它语言都需要标准的 key 长度
getcharch
2022-08-11 20:07:55 +08:00
非标准的 key 长度,可以使用 pyexecjs 库调用 CryptoJS 实现解密
kkocdko
2022-08-11 20:24:13 +08:00
CroptoJS 由于 JS 本身的 weakness ,库作者偷懒,**某些半吊子前端瞎 JB 写**等原因,可以作出很多奇怪的非标准操作,例如 5 楼提到的 key 长度,之前还碰到过有强行把加密后的数据当成 utf8 传进去的,我当时看到负数码点的 utf8 差点吓死,但它也跑得好好地。
最好的方案还是 6 楼所说的那样,找个轻量的 JS 运行环境跑一下 CryptoJS 。如果要避免,就只能手动修改本语言的加密库以放宽限制。但这通常非常麻烦。
kof21411
2022-08-12 08:16:47 +08:00
js 用的是 cbc 模式你 python 用的是 ecb
lusi1990
2022-08-12 08:25:05 +08:00
同样遇到过 key 长度不是 8 的倍数
persona5
2022-08-12 08:42:23 +08:00
@Wincer
@kof21411 默认是 CBC 模式的话,vi 不是必传吗,请问那应该传什么?


@getcharch
@kkocdko
@lusi1990 所以 CroptoJS 中不要求 key 的长度吗,我还以为会自己补。那么除了 pyexecjs 调用 CroptoJS ,就只能自己修改加密库了吗?
Slurp
2022-08-12 11:56:26 +08:00
我也被这玩意困扰过……一堆参数隐式传,文档又不写,还要自己看源码。前端方便了,后端对接 sb 了一样。
Wincer
2022-08-12 13:04:35 +08:00
@persona5 #10 iv 你随便挑个 16 字节传就行,但是要保证 python 加密时和 js 解密时传递的 iv 一致即可,方便起见我是拿 key 填充到 16 位当 iv ,看个例子吧,key 和 iv 的取值需要根据你具体场景微调一下
python 加密:
```python
key = b"aaaaaaaaaaa12345"
data = b"test content"
cipher = AES.new(key, AES.MODE_CBC, iv=key)
ct_bytes = cipher.encrypt(pad(data, AES.block_size))
>>> print(b64encode(ct_bytes).decode('utf-8'))
'D9OA8v/qIWeNUsuojKMWJg=='
```
js 解密:
```javascript
let key=CryptoJS.enc.Utf8.parse('aaaaaaaaaaa12345');
let encryptedBase64Str = 'D9OA8v/qIWeNUsuojKMWJg=='
let decrypt = CryptoJS.AES.decrypt(encryptedBase64Str, key, {iv: key, mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7})
decrypt.toString(CryptoJS.enc.Utf8)
```

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/872241

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX