如何用python实现js的AES加密和解密

2023年 7月 11日 66.3k 0

什么是AES加密

AES加密(Advanced Encryption Standard)是一种对称加密算法,它只使用一个密钥进行加密和解密。该算法可用于多种模式,包括ECB、CBC、CFB、OFB和CTR等,其中最常用的是CBC模式。

为什么要用Python实现js的AES加密解密

举个例子,我们因为学习交流或其他原因,需要获取某个网站的某个api的数据,当我们查看数据内容时,发现是这样的格式

如何用python实现js的AES加密和解密

prompt: "U2FsdGVkX18ysXWhT/IUHhE7TatRnKt7oMBu4hD0cz8="

这样的数据显然是经过加密的,发送到服务端后再进行解密。

我们找到加密代码所在的位置

如何用python实现js的AES加密和解密

const Uu = ju
  , o2 = "__CRYPTO_SECRET__I>EO)$__M*&.fsee";
function Oh(e) {
    const t = JSON.stringify(e);
    return Uu.AES.encrypt(t, o2).toString()
}

可以看到数据是进行了AES加密。想要实现同样的加密/解密,第一种方法是使用python运行js代码,这种方法需要编译js代码,执行起来繁琐、易出错;第二种就是直接使用python实现,推荐这种方法。

AES加密库

能够使用aes算法的python库有cryptopycryptopycryptodomexpycryptodome等,但是因为各种原因,很多库已经不再维护了,目前推荐使用且一直在维护的库为pycryptodome,且其调用方法都是相同的。

pip install pycryptodome -i https://pypi.tuna.tsinghua.edu.cn/simple

加密解密方法

import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad


def aes_encrypt(data, key, iv):
    cipher = AES.new(key.encode(), AES.MODE_CBC, iv.encode())
    res = base64.b64encode(
        cipher.encrypt(pad(data.encode(), AES.block_size, style="pkcs7"))
    )
    return res


def aes_decrypt(data, key, iv):
    cipher = AES.new(key.encode(), AES.MODE_CBC, iv.encode())
    res = cipher.decrypt(base64.b64decode(data))
    return res


if __name__ == "__main__":
    data = "data"
    print("要加密的字符串:", data)
    key = "0123456789abcdef"
    iv = "0123456789abcdef"
    en = aes_encrypt(data, key, iv)
    print("加密后的字符串:", en)
    de = aes_decrypt(en, key, iv)
    print("解密后的字符串:", de)

上述代码的输出结果为

要加密的字符串:data
加密后的字符串:b'hAoMQT3Kbn3MWHgyFHlQUw=='
解密后的字符串:b'datax0cx0cx0cx0cx0cx0cx0cx0cx0cx0cx0cx0c'

python加密和js加密的异同

当你想调用python的aes加密方法,去实现和js相同的加密内容是,你就会发现这样一些问题

  • python需要用到iv,js怎么没传iv参数呢?
  • python中的key和iv的长度必须为16、24或32,js中怎么什么长度都可以呢?
  • 加密后的密文怎么不一样呢?
  • python加密后的密文长度怎么和js的不一样长呢?
  • 我们进行一一解答:

  • AES默认使用CBC加密,CBC加密是要用到iv的,js不需要必传iv参数的原因是,当不传此参数是,js会自动生成。
  • 当key和iv的长度不是指定长度时,需要进行补齐,python需要手动补齐,js进行了自动补齐。
  • 每次加密后的密文时不一样的,这是因为js在加密时会添加随机salt,但是解密后的密文是相同的。
  • js在加密时会添加Salted__和随机salt,使得加密长度比用python加密长。
  • 用python实现js的AES加密

    根据以上种种,直接用python的encrypt方法是得不到js的密文的。但是幸运的是有这样一个库,实现了很多语言的AES通用加密——aes-everything。

    AES Everywhere - Cross Language Encryption Library (Bash, C#, Dart, GoLang, Java, JavaScript, PHP, Python, Ruby, Swift)

    pip install aes-everything -i https://pypi.tuna.tsinghua.edu.cn/simple
    

    方法如下

    加密方法

    from AesEverywhere import aes256
    data = "data"
    key = "012345678"
    encrypted = aes256.encrypt(data, key)
    

    解密方法

    from AesEverywhere import aes256
    data = "U2FsdGVkX1+I0zYbay/n9fgynjYWwpC9fPRBQR1z0j8="
    key = "012345678"
    encrypted = aes256.encrypt(data, key)
    

    ECB加密解密方法

    aes-everything没有提供ECB模式的加解密方法,我们将上述模式(CBC模式)的代码稍微进行魔改即可,如下

    def aes256_ecb_encrypt(raw, passphrase):
        salt = aes256.Random.new().read(8)
        key, iv = aes256.__derive_key_and_iv(passphrase, salt)
        cipher = aes256.AES.new(key, aes256.AES.MODE_ECB)
        return base64.b64encode(
            b"Salted__" + salt + cipher.encrypt(aes256.__pkcs7_padding(raw))
        )
    def aes256_ecb_decrypt(enc, passphrase):
        ct = base64.b64decode(enc)
        salted = ct[:8]
        if salted != b"Salted__":
            return ""
        salt = ct[8:16]
        key, iv = aes256.__derive_key_and_iv(passphrase, salt)
        cipher = aes256.AES.new(key, aes256.AES.MODE_ECB)
        return aes256.__pkcs7_trimming(cipher.decrypt(ct[16:]))
    

    总结

    在本篇文章中,我们介绍了如何用python实现js的AES加密解密的方法,目前网上的其他教程都没有正确说明,本文解答了疑惑,给出正确代码,建议有需要的同学收藏本文。

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论