V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
persona5
V2EX  ›  程序员

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

  •  
  •   persona5 · 2022-08-11 17:50:58 +08:00 · 1961 次点击
    这是一个创建于 836 天前的主题,其中的信息可能已经有所发展或是发生改变。

    以这个在线工具为例: 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 实现可以解密上面在线工具生成的密文。

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

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


    @getcharch
    @kkocdko
    @lusi1990 所以 CroptoJS 中不要求 key 的长度吗,我还以为会自己补。那么除了 pyexecjs 调用 CroptoJS ,就只能自己修改加密库了吗?
    Slurp
        11
    Slurp  
       2022-08-12 11:56:26 +08:00
    我也被这玩意困扰过……一堆参数隐式传,文档又不写,还要自己看源码。前端方便了,后端对接 sb 了一样。
    Wincer
        12
    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)
    ```
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2504 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 15:46 · PVG 23:46 · LAX 07:46 · JFK 10:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.