如何用Python Crypto.Cipher解密CryptoJS加密的AES响应?
解决CryptoJS AES解密转Python的问题
先看看你提供的JavaScript解密代码,我帮你拆解几个关键细节,再对比你的Python代码,就能找到解密失败的原因了:
JavaScript代码的核心逻辑
这段JS代码用的是AES-CBC模式,默认使用PKCS7填充,具体步骤是:
- 密钥
keyBase64是Base64解码后的字节数组 - IV
iv1是Base64解码后的16字节全零数组(因为AAAAAAAAAAAAAAAAAAAAAA==解码后是16个0x00) - 解密时直接传入Base64格式的加密字符串
result,CryptoJS会自动处理Base64解码 - 解密后的结果转成UTF-8字符串
你的Python代码的问题
对比JS代码,你的Python代码有几个致命错误:
- 加密模式错误:JS用的是CBC,但你写的是
AES.MODE_ECB,ECB不需要IV,这完全不匹配 - 参数顺序错误:
AES.new的参数顺序在CBC模式下是(key, mode, iv),你把IV放在了ECB模式的参数位置,这会导致密钥解析错误 - 缺失填充处理:CryptoJS默认用PKCS7填充,但Python的
pycryptodome库默认不自动处理填充,需要手动指定 - 解密后未转UTF-8:你直接返回了解密后的字节,没有转成字符串,而且没处理填充残留
正确的Python解密代码
先确保你安装了pycryptodome库(不是老的pycrypto),然后用下面的代码:
from Crypto.Cipher import AES from Crypto.Util.Padding import unpad import base64 def decrypt(encrypted_data, key_b64, iv_b64): # 解码Base64格式的密钥和IV key = base64.b64decode(key_b64) iv = base64.b64decode(iv_b64) # 初始化AES-CBC解密器,指定PKCS7填充(和CryptoJS默认一致) cipher = AES.new(key, AES.MODE_CBC, iv) # 解码加密数据的Base64,然后解密,再去掉PKCS7填充 decrypted_bytes = cipher.decrypt(base64.b64decode(encrypted_data)) plaintext = unpad(decrypted_bytes, AES.block_size).decode('utf-8') return plaintext def main(): # JS里的密钥和IV key_base64 = "ITU2NjNhI0tOc2FmZExOTQ==" iv_base64 = "AAAAAAAAAAAAAAAAAAAAAA==" # 你的加密消息 encrypted_message = 'F\/VDFb\/tLplCXIgvPGlpppHawetuV1a5DtWOtmO1ZkS\/87wBEfaIV4VvxPeEyouCopt\/4G+3GDd\/kWnm6jjiBudpiOZnCmqOgQN6E\/K4P4oeGfeYrM51936xLc6CGjFl2McgbQ7YhldDobeuv3OCjYFd3Am3G2pzG6z7F44VP4e2p4ZVU3ysgXLVdqHnl8lVPzXX4AAH54yI1wjsoywDckbH9SXea4VvMryJ5bZsVs5XXG9GPlOJuwIkay46ubpZ5SZxM586C2bPVxi42RCF2a\/GsdagaMpQ83x\/PXN\/t3GBeKoxHN1WPbLskHvOirJeme7CIRmFRdswJkHbCFiUF9KChKuO06hdnZJECG76Y+xeB44R5254O\/E8R7K9uaCKRFFLBg7UoFwtlNKETiBBrrrT8l\/V4nY6u5P22uWy1Ioms2yj\/aJSP0HoHeR9vnbrmNQDSDRbOtBly4QfPaq1A5Vn2as+5CjnGmqE3CnsONO9a1LDdt\/kg5N89\/1KXEiq4ytlcSczi1DN+cKpNKxERd2nFb5jWGHgb0CFpo5ZUF1tj0HdGGfZW16lQpHbhVo+zhVdZZUHght81AkL5D35BN0Dn0SKF3Xt7FB56HTri3f25kxSycswY\/xNpiYdW7BTY2D8te6neGCn7zFF1kWcsDQJaaIa3lwKcs0HxMMYQ+Gm8oA3UtPXoRWE4QmEmZr2YslnWbq5Uemu+m9WdZ9Yks4zYcHtdixCa2Sjfgbyz+SfgGPKePaN6U1raEBge1BPwf71S2IL9PFfrhHAw2VNdNNOae1pi1Vgplui9SWU\/4PsdAyYQlLOBKY7OFyG26QFLoEDIo0UP8xMlHel6IgIK2oKDIvqQFDQpl2nJE0d832OzrKgD1+xuyPQRfaaw7xlEGrFpJ7unQ6vDs64PTG\/Kyh75Q\/LBgTf7cqA4PgprSsa4V8+rm9Ozx9D\/33mAo0N5Tlm9YHnfvx60nTsGqCBjiNHU48jRkMRVqP1TnrH0Po3EVXO8RAXOV6iHus1JdxNNTbJykZkPK6WepiURLoVv8s0fFG1ok9Z0ofhgjRH10jcJf2pIA6xUuXFDIu0BNbPoYlcsHJiLlHSZ+nskafbs2uHrIfhoJ6HMGnn4WBTAJIhXTwGqPqjx8uh1aiinMta84T\/hf69VOqGcClxPR0PuS0Ak1iVxofRRdOthpVS7RIMosAc5mM8VFxyzkwm0B1YhJUCXLKgO\/nHl+Olji1wH4ZokIyNl6uGx89pFZk4+c9q72epuMr2jbn3E+nDMGead8hpN7vWZSBsuPxuSgWygTUfc3H2fpdyQMn75qNEozS+u2CivIHc6T3MzsWnibHTjFiFPLzyOED1ISVqVJ9CfaHujLaJ8VW3EAykqSJgFRmsj3eyIAl5ZzUW2BYk4rej1gvEIDgkUwso4zm3hxWAwgp7ozeYKCE5EaweCW5B31MxV+2WV6z0auYAzubcAdF300AgueiVwY5+syfweh2OkEJaEn2C\/qUlJCPyXepgklqjpxQ9b7jyoqlCf8ZmD6zcjTK8zH9t4eG0J4aah2bY9Rm5bBWhqQ0LCoudvkCJ\/LvA+zTjBUlL474CLOkrKGK9yfxZYNyRbwObmXy49jUMjk\/03Y8cZizDDNMhnjqTt8+Ww2q9ohKNQmKYtbWVMSRm6EcundxVseGkp0kvxaIB7HA0PedR\/+MEi7VTGNnJeYDGGTTOQQigIM5B4DVj1M0IKvWM7nFH+TPze2zz5iRnfsVTU9aKyOvgQSabOxfIzLXLN7qA18TwENoOr75FN4Untbh7fL92sYCBhoJ5bszZ3GhB2NpL4xANpZM3g43fgiGqj8I4FDoxfUSijPwo2pYHk+32Hs2R0vLrFOM6uUThf84D1vxdVGhwszy\/LFFBAYWchw470h\/kuI7ndX2V3Fi6s8mjijFytBKh1Cq4U7F3CnIcEJN4b51Ivpza\/Yir+eKC6nZSrQR4AuezaQ\/UCn8n7okkApI09v6jGZvzcrVbx5Ifkd9WQ\/8ZSPKOFwRlVYISAlJaEKRYokpVVrpq5Rmpi7VezIhr5z6qDQV\/1ILUpTgChkEIj1ZqzVIIj\/Rads3WREgWjucgRlZNEXLjUex0+tyg3GZvdr8HxvfxzAum3rVQBcGyJUJtXPMDE8xuErtrdn\/xHU+QNkiJykVZrUB\/WmWKU72pIXJ2zjcwnUbb8NrYyVd529H8kxi\/CVF7iQQnsF3V7ArB1Cv3VV+fayiufothy\/amPgem4DK5WNlVbt+KfnQKuMNyfz3Rrvnu\/3kdq6JDHPdncpNuqGeWpNKphuyC809jI\/lNbQI+HRNv7J3p\/J74MNXd4JqsSuBaF9OEIOjcvh4rgILHQ1W6j9qwN4SeuL6ylegK2pBZ7A7uua31WXDqmQAY5SeRXQlplf30HGD3Lew4qXJmo1f4vo33azubPDBIl\/kk7a2UgXMfKWNhueFqsBPWsCQFMCRDDD\/XPho+2uU7c2X9DL1B2fK+8cxkYXSE1h9sZ+Palc2r1ujqxCiiHdCsWwviL0autdk2eFEkyb\/Mox+cY01GgWpHLQE\/PN\/cY\/3WFlKuaG9aajPC598NNfUNHqt8rfvmSdTu3eiLrUJdBB0Fi6EbtquUNEvB2+IxU9fsF0mtrWzZ6hlk8kF+mBNE1t+49Aq1xS56uTu0+TZAZNuQBBGGAR7OJ4m\/PYAv8HTDERO9nX7GJQq2nsUw5ZT4ssIMh5JEyKcdosf\/2bC1gaOr\/ZjH+gT2CHQocwkXk\/CZSYrD8XsaO6UNxJsNYAN7q5kMZrbRg1K81quyov1SekpENASiOYRUwtg11ZJ589yXrMD7q6KY66uW5kw1\/rOewOiCPVAJSahWg6vPxB\/T3d5Nb2CX9nvpdqArlH\/Ny9iKzJtMA2xhkG9pn7Z5NVPWHsnn1qvDTvWzhCaC1+Kzvx+IinJYcpqBIC3DLOJguVrrAs9bxx4QfNnY4MYPn3GPRKUxkcABa8sEOr8uDFB1XWYG8LwVbYtxjAKZNyYW08Ynd+wkbDGUANh4fb3JR7uSUWs99IUUJkH8jG0iGxsnw1YV2POdi+fqyc5eVPfjjIz+mXcvlG05AfvYRg6vHmC0geo24G\/xjLiFgwKV3QGrR6ijMVsy3A5P0VC+IysUj7LcJjtUjd7FQbi6ep4iYwdrsNrrkzIiweDS83RKyU2GuVe1X\/4LwKL0uMLwyzjOcXM6el169zOvgmqageXExcNY+9kEXZMg6HTBSSfz8rZbCh9Dv1KFX0Q7cJcHS9A4aNdFowCyCi7oz7utTY7GtOyLSMPcjsv6fjtMV98JbY+pu7DpsOM8bWCJIKmp4W9Hl2HVCR0440Eygddml\/eg\/a1HkKv7biWSMcKxtdyuXx5ka1MOQRlDsqJC5QQsBiGtFnfMZMra5RZ3xta6wVB0A6s6y\/MTzXcHTM\/GjCZmnRcxDGc0T80bllAMFzssmlS6gZwSlsRbI2ODvwcw63DAr2wbkp2OCGjUdOW08++4Qw9Zjuv6jRCTQGSqrvgMVYFpW+arrj4ts9tMemRrr7m9h7OFzXwo\/leIZf10PGdlyskCiYrazxL\/tmAQBl2yE+0JYJ\/8BSCsqW59cSlGSxe1o54mk1QkzzLf0U3FVZw+FwyL3DL5uwRkRdIrV+4fUr9FerPcy3mi5iNj2wGB1xRwC+FRmndqttqJB7KI+YtETaMYgEo77a1j8LrkNcREn2um37ZbzC5uCVP7N9yxRKuyGX1xUbrguxfhqT1COApm8K2hjRhGaEGhbbiB6M\/SrllvLs3Imq246nrSbG50HEKVIaVtRcgtpcmmYvNBoJPLzvOMxkMxCV3VWixeGh0WIcMvYEXsyEvtjhAZFYQUHYS8u8PXAxBTPRT0jKjz\/6QGfCsTxB+zVeJyTpzS6CRtg+WMXFWZOo5sJHkzzei1TCifptwiS2fVGwua86djV15YSVwHaIm8vGpo+UXmQsir6RGTD8b0JPmcwO1wv79cZ3Apa3WQCC+eHmXDGb3uakyrmFD\/mQSGGZpBsSeKtqgZgUgWr3V2KLtcnK6XmDHkrrTVu3p+uRMF' # 注意:你的加密消息里有转义的斜杠,需要先处理一下,把\/替换成/ encrypted_message = encrypted_message.replace('\\/', '/') try: plaintext = decrypt(encrypted_message, key_base64, iv_base64) print("解密结果:") print(plaintext) except Exception as e: print(f"解密失败:{str(e)}") if __name__ == "__main__": main()
关键注意事项
- 填充方式匹配:CryptoJS的AES默认使用PKCS7填充,所以Python里必须用
unpad函数处理,否则解密后的字符串会有多余的填充字节 - IV和模式匹配:CBC模式必须指定IV,而且IV长度必须是16字节(AES块大小),这里JS里的IV是16个0,完全符合要求
- Base64处理:加密消息里的
\/是转义后的斜杠,需要先替换成/才能正确解码Base64 - 库的选择:一定要用
pycryptodome,老的pycrypto已经停止维护,而且API细节有差异
内容的提问来源于stack exchange,提问作者Kiran
相关产品推荐
相关产品推荐

