JS逆向入门:AES加解密及其Python脚本实现与解析

admin 2024年9月2日08:11:38评论60 views字数 6031阅读20分6秒阅读模式

最近在学习Js逆向时发现AES涉及的知识点比较多,编写对应的Py脚本时涉及的细节也比较多,就导致了会出现各种各样的小bug,所以心血来潮写一篇文章进行一个系统的总结(学艺不精,如有错误,欢迎各位师傅指正)

1、AES简介

JS逆向入门:AES加解密及其Python脚本实现与解析

AES是最为常见的对称加密算法(对称加密就是加密与解密使用的秘钥是一个),大致的加密流程如下

JS逆向入门:AES加解密及其Python脚本实现与解析

含义介绍

明文P等待加密的数据

秘钥K:用来加密明文的密码,在对称加密算法中,加密与解密的密钥是相同的。密钥为接收方与发送方协商产生,但不可以直接在网络上传输,否则会导致密钥泄漏,例如我们在进行Js逆向时,得到了该秘钥就可以尝试解密网站中的加密数据

AES加密函数:设 AES 加密函数为 E,则 C = E(K, P),其中 P 为明文,K 为密钥,C 为密文。也就是说,把明文 P 和密钥 K 作为加密函数的参数输入,则加密函数 E 会输出密文 C

密文 C经过 AES 加密后的数据

AES 解密函数设 AES 解密函数为 D,则 P = D(K, C),其中 C 为密文,K 为密钥,P 为明文。也就是说,把密文 C 和密钥 K 作为解密函数的参数输入,则解密函数会输出明文 P

实现 AES 有几种模式,主要有 ECB、CBC、CFB 和 OFB 这几种。本章主要介绍最常用的 ECB CBC 模式。

由于我们主要是研究Js逆向中的AES加密,只需要知晓其基本概念和用法即可,详细的加密逻辑暂时不用深究

2、加密模式_ECB

JS逆向入门:AES加解密及其Python脚本实现与解析

ECB是AES几种加密模式中最简单的加密模式,简单来说就是将明文切分为若干个组分别加密,实际上有很明显的弱点,就是相同的明文会得到同样的密文。因为每个分组加密方式和密钥都相同,若分组明文相同,加密后密文也相同

这里给出我自己写的利用Python3实现AES_ECB模式的加解密完整demo,每一步都会在注释中进行详细的解释,首先是AES_ECB加密代码,如下

def encrypt(key, text):    # 确保密钥长度是16    key = key[:16]  # 截断16位    # 因为AES加密算法处理的是字节数据,所以需要将密钥转化为bytes类型    text_bytes = text.encode('utf-8')    # 由于AES加密要求输入数据的长度必须是块大小的整数倍(AES的块大小是16字节)    # 使用pad函数来填充数据,以确保其长度是16的倍数    padded_text = pad(text_bytes, AES.block_size)    # 初始化AES加密器(使用ECB模式)    aes = AES.new(key, AES.MODE_ECB)    # 加密    encrypt_aes = aes.encrypt(padded_text)    # 注意:加密后的数据是字节串,可能包含无法直接以文本形式存储或传输的字符    # 形如b'x036x19xe1x12x15xa7x9bHx16!'    # 加密后的字节串编码为Base64格式的字节串    encrypted_text = base64.b64encode(encrypt_aes)    # 然后.decode('utf-8')将字节串转换为字符串    # 形如b'AzYZxk2RHr7uq6cN8SVA/hOmMGx+Nfc54RIVp5tIFiE='    encrypted_text = encrypted_text.decode('utf-8')    # 形如AzYZxk2RHr7uq6cN8SVA/hOmMGx+Nfc54RIVp5tIFiE=    return encrypted_text

AES_ECB模式只需要秘钥key即可对明文进行加密,所以这里传入key(必须是16位)和要加密的明文text,并且aes的加解密函数,形如

encrypt_aes = aes.encrypt(padded_text)

处理的都是字节串,也就是padded_text必须是个字节串,这里是加密函数,解密函数也是一样,所以在调用该数据进行加解密前,可以通过

# 将text字符串转为字节串text_bytes = text.encode('utf-8')# 相反的,下面这样就是将字节串转为字符串text = text_bytes.decode('utf-8')

字节串和字符串看下面两个就已经可以区分了

# 字符串text = 'AzYZxk2RHr7uq6cN8SVA/hOmMGx+Nfc54RIVp5tIFiE='# 字节串# aes加解密函数,处理的就是字节串text = b'AzYZxk2RHr7uq6cN8SVA/hOmMGx+Nfc54RIVp5tIFiE='

注意调用加密函数得到的结果是个字节串,不利用阅读传输和存储,所通过是将接加密后得到的字节串进行base64编码后再转为字符串,从而得到最终的密文

然后是AES_ECB的解密代码,由于AES是对称加密,所以解密简单来说就是倒走一遍加密流程,代码如下
def decrypt(key, text):    # 初始化加密器    aes = AES.new(key[:16], AES.MODE_ECB)    # 注意:无论什么格式的数据,base64解码后得到的一定是字节串!!!    # 如果是加密,则编码后的数据类型和编码前相同    # 所以这里对字符串进行base64解码,得到字节串,中间不需要主动进行字符串转字节串的操作    # 解密之后形如b'x036x19xe1x12x15xa7x9bHx16!'的字节串    base64_decrypted = base64.b64decode(text)    # 调用AES解密函数解密字节串    # 解密之后形如b'Hello, AES Encryption!nnnnnnnnnn'的字节串    decrypted_padded = aes.decrypt(base64_decrypted)    # 去除填充部分,然后将字节串改为字符串    decrypted_text = unpad(decrypted_padded, AES.block_size).decode('utf-8')    # 最后得到完整明文    return decrypted_text

这个代码也很容易理解,但有两个需要注意的地方,一个是传入的密文text是字符串,但是此处不需要先转化为字节串再base64解码。而是直接进行base64解码,原因是任何类型的数据,在进行base64解码之后,得到的结果都是字节串,可以看下面一个小demo

import base64# 假设这是一个Base64编码的字符串encoded_str = "SGVsbG8gV29ybGQ="# 解码Base64字符串decoded_bytes = base64.b64decode(encoded_str)# 打印解码后的字节串,可以看到得到的结果从字符串变为了字节串print(decoded_bytes)  # 输出: b'Hello World'# 只有将字节串结果进行utf-8编码,才能得到字符串decoded_str = decoded_bytes.decode('utf-8')print(decoded_str)  # 输出: Hello World

所以此处在调用aes解码函数前,不需要手动进行字符串转字节串,然后再去对字节串进行base64解码(因为base64解码的结果会强制转换五位字节串)

第二个需要注意的地方就是去除填充部分,这个部分需要跟加密函数中的填充代码进行比对,从而理解填充这个操作

最后给出一个完整的AES_ECB模式的加解密以及示例demo

import base64from Crypto.Cipher import AESfrom Crypto.Util.Padding import pad, unpad# 加密函数def encrypt(key, text):    # 确保密钥长度是16    key = key[:16]  # 截断16位    # 因为AES加密算法处理的是字节数据,所以需要将密钥转化为bytes类型    text_bytes = text.encode('utf-8')    # 由于AES加密要求输入数据的长度必须是块大小的整数倍(AES的块大小是16字节)    # 使用pad函数来填充数据,以确保其长度是16的倍数    padded_text = pad(text_bytes, AES.block_size)    # 初始化AES加密器(使用ECB模式)    aes = AES.new(key, AES.MODE_ECB)    # 加密    encrypt_aes = aes.encrypt(padded_text)    # 注意:加密后的数据是字节串,可能包含无法直接以文本形式存储或传输的字符    # 形如b'x036x19xe1x12x15xa7x9bHx16!'    # 加密后的字节串编码为Base64格式的字节串    encrypted_text = base64.b64encode(encrypt_aes)    # 然后.decode('utf-8')将字节串转换为字符串    # 形如b'AzYZxk2RHr7uq6cN8SVA/hOmMGx+Nfc54RIVp5tIFiE='    encrypted_text = encrypted_text.decode('utf-8')    # 形如AzYZxk2RHr7uq6cN8SVA/hOmMGx+Nfc54RIVp5tIFiE=    return encrypted_textdef decrypt(key, text):    # 初始化加密器    aes = AES.new(key[:16], AES.MODE_ECB)    # 注意:无论什么格式的数据,base64解码后得到的一定是字节串!!!    # 如果是加密,则编码后的数据类型和编码前相同    # 所以这里对字符串进行base64解码,得到字节串,中间不需要主动进行字符串转字节串的操作    # 解密之后形如b'x036x19xe1x12x15xa7x9bHx16!'的字节串    base64_decrypted = base64.b64decode(text)    # 调用AES解密函数解密字节串    # 解密之后形如b'Hello, AES Encryption!nnnnnnnnnn'的字节串    decrypted_padded = aes.decrypt(base64_decrypted)    # 去除填充部分,然后将字节串改为字符串    decrypted_text = unpad(decrypted_padded, AES.block_size).decode('utf-8')    # 最后得到完整明文    return decrypted_text# 示例使用key = b'thisisakey123456'text = 'Hello, AES Encryption!'encrypted = encrypt(key, text)print("Encrypted:", encrypted)decrypted = decrypt(key, encrypted)print("Decrypted:", decrypted)

运行之后结果如下

JS逆向入门:AES加解密及其Python脚本实现与解析

成功实现了对明文的加密和解密,感兴趣的师傅可以复制代码自己下去试试,结合代码的注释,很快就能理解了

3、加密模式_CBC

JS逆向入门:AES加解密及其Python脚本实现与解析

AES_CBC加密模式算是AES几个模式中使用的最多的,因为它的安全性比ECB模式高了很多,在这种方法中,每个密文块都依赖于它前面的所有密文块。同时,为了保证每条消息的唯一性,在第一个块中需要使用初始化向量iv

AES_CBC模式的加解密,在代码中相比于AES_ECB模式多了一个iv(初始化向量)需要处理,所以这里直接给出AES_CBC的完整加解密Demo,如下

import base64from Crypto.Cipher import AESfrom Crypto.Util.Padding import pad, unpadfrom Crypto.Random import get_random_bytes# 加密函数def encrypt(key, iv, text):    key = key[:16]    # 转换明文字符串为为字节串    text_bytes = text.encode('utf-8')    # 填充    padded_text = pad(text_bytes, AES.block_size)    # 初始化AES加密器(使用CBC模式,需要传入iv)    aes = AES.new(key, AES.MODE_CBC, iv)    # 加密    encrypt_aes = aes.encrypt(padded_text)    # 加密后的字节串编码为Base64格式的字节串    encrypted_text = base64.b64encode(encrypt_aes)    # 转换为字符串    encrypted_text = encrypted_text.decode('utf-8')    return encrypted_text# 解密函数def decrypt(key, iv, text):    # 解码Base64    base64_decrypted = base64.b64decode(text)    # 初始化AES解密器(使用CBC模式)    aes = AES.new(key[:16], AES.MODE_CBC, iv)    # 解密    decrypted_padded = aes.decrypt(base64_decrypted)    # 去除填充部分    decrypted_text = unpad(decrypted_padded, AES.block_size).decode('utf-8')    return decrypted_text# 秘钥key = b'thisisakey123456'# 初始化向量长度必须与块大小相同(AES为16字节)# 初始化向量iv = b'1234567812345678'text = 'Hello, AES Encryption with CBC Mode!'# 加密encrypted = encrypt(key, iv, text)print("Encrypted:", encrypted)# 解密时需要使用相同的IVdecrypted = decrypt(key, iv, encrypted)print("Decrypted:", decrypted)

大致流程与AES_ECB相同,只不过在初始化加密器和解密器时,带上了一个初始化向量iv,这个iv也必须与AES块大小相同,即16字节,运行效果如下(如果key和iv固定,那相同明文得到的密文也固定)

JS逆向入门:AES加解密及其Python脚本实现与解析

在实际逆向中,通常寻找目标的key与iv来对站点的加密数据进行解密,如下

JS逆向入门:AES加解密及其Python脚本实现与解析

4、总结

JS逆向入门:AES加解密及其Python脚本实现与解析

除了这两种常见的模式之外,AES还有CFB,OFB等模式,但这两种是Js逆向中最常见的,所以这两种是必须要理解的,其他模式等遇到的时候再去了解就行,今天的文章就到这里啦,有任何的意见和建议也欢迎各位师傅交流!!

5、杂谈

JS逆向入门:AES加解密及其Python脚本实现与解析

另外我本人的课程在9月底也会加入Js逆向的内容哦,通过基础代码讲解,实战Js逆向案例分析,提供Js逆向练习站点,让你快速上手Js逆向!

JS逆向入门:AES加解密及其Python脚本实现与解析

强力亲推:专属于大学生的SRC漏洞挖掘课程来啦!!

等9月底Js逆向课程开始之后可能会小幅度涨价,但老学员不受影响,所以欢迎有兴趣的师傅们咨询课程哦

原文始发于微信公众号(Daylight庆尘):JS逆向入门:AES加解密及其Python脚本实现与解析

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年9月2日08:11:38
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   JS逆向入门:AES加解密及其Python脚本实现与解析https://cn-sec.com/archives/3119221.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息