-
-
[原创][原创]M30A1_FW110B02固件解密,AES、EVP-ByTokey(SHA-256)
-
发表于: 2025-12-14 21:40 219
-
1、信息收集

编辑
我们拿到M30A1的110版本先binwalk看一下,里面只有一个0x41的OpenSSL 加密,salted,并且盐也给我们了。

6dfK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
能确定是加密态,熵值接近1。

10eK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
这里发现了Salt
2、加盐算法
我们在了解是OpenSSL加密那就先去了解一下他的加密逻辑。
DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 65 0x41 OpenSSL encryption, salted, salt: 0xE5C9BB84466AF3C5
f11K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">
这里有三个参数,65是一个10进制的数,标识加密部分在文件中的起始位置
0x41是16进制表示,与65相同
下面的是加密的描述
OpenSSL encryption, salted, salt:0xE5C9BB84466AF3C5 OpenSSL encryption:表示文件这一部分用了OpenSSL工具加密 salted:表示加密过程中使用的盐值。 salt:提供了盐的具体值,即0xE5C9BB84466AF3C5 这个盐是生成密钥的一部分。
487K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">
3、核心引擎AES-128 Encryption

e21K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
我们能找到1.02版本是AES-128加密,而且在更新的版本更新公告中也没发现其他的安全升级。
AES
AES-128是对称加密的,意味着加密解密都是同样的一把钥匙(Key),我们需要扣出这个Key
这里的128含义是密钥(Key)长度为128位,也就是16字节(128 ÷ 8),换算成Hex字符串是32个字符。
CBC
AES不会把整个文件一口气加密,把文件切成一块一块的,每块16字节处理,但是问题在于如果只是每块独立加密,ECB模式,那么文件里相同的 的内容,加密后还是相同的密文,能看得出来特征。
如果解决就引用了CBC模式,他是连锁反应,第二块加密依赖于第一块结果,第三块,依赖第二块加密结果,以此类推,但是第一块加密需要依赖的就是IV,也就是初始化向量这样一个概念来作为加密引擎。
填充
AES的块大小固定是16字节,如果文件大小不是16的倍数会用到OpenSSL的默认填充方式,他会在文件末尾补上几个字节,凑齐16的倍数,解密把他们丢掉。
加密逻辑
OpenSSL是一个工具库,他在加密有两种方案
(1)、基于密码加密
输入端:我们只需要一个密码(Password)和一个Salt(盐)
过程:
1、OpenSSL使用KDF(密钥派生函数,如MD5或PBKDF2)混合密码和Salt
2、算出一个Key/IV
3、用算出来的Key/IV去跑AES
文件特征:文件头通常有Salted__字样,后面跟着8字节的盐
(2)、基于原始密钥(Raw Key/iv)
输入端:直接给AES引擎塞入Key(16字节)和IV(16字节)
过程:跳过派生,直接加密
文件特征:
Key:通常硬编码在解密程序(如u-boot或解密脚本),文件找不到
IV:通常放在文件头部的某个固定位置,比如前16字节,或偏移0x20处,因此解密必须用到。
总结
我们回归D-Link固件想要破解,就必须填上三个空
1、Key
一个16字节的Hex串,一般藏在路由器上个版本系统文件里,或者写死在解密程序的二进制代码里,但对于D-Link这个是通用。
2、IV(初始化向量)
16字节,他一定在固件文件里,因为解密程序运行时第一件事就是读取文件头的IV
3、算法
加密方式,我们能确定是AES-128-CBC
4、追踪IV、Key、确定密文长度、文件头分析。
那我们这一套非常之明确了,这就是第一种玩法嘛,非常明显的Salt__后的8字节,我们提取出来,然后还有一个点就是确定密文长度。我们一步一步来,先来最简单的确定密文长度。
一、头部元数据校验(确定加密长度)
由于在1.20版本中的一些发现,这个未加密的文件头中会有加密长度,我们寻找一下。

fadK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
非常明显的一点就是0x50之前都是明文,以0x50作为一个分界线,我们可以在这个文件头中找到这个加密长度,或者从0x50开始往后截取成一个新的文件。我们先看一下整个文件大小。

af6K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
我们先查询到整个文件的长度,这个作用是比对长度,以此为标准,因为明文占用的空间非常的小,大部分都是加密的,因此我们找那串16进制的符合。

bd3K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
我们写了一个脚本。我们先把猜测的加密部分提取出来,比对一下大小。

353K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
这里应该是截的有些偏差,不过大概能判断出这两个位置是加密长度,因为去除头部明文差不多是这个长度。
我们应该从0x51开始截取,我们再截一次。
dd if=M30A1_FW110B02.bin bs=1 skip=80 of=payload_80.bin
66bK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">

b97K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
好像区别不大。
但我们在提起盐的部分发现从0x41(salt+加密长度)开始截取的长度刚好就是38871424,那么我们找的文件长度是没问题的,剔除salt就是整个加密长度。
二、提取Salt
我们一开始使用的binwalk很明显的发现了0X41开始就是Salt__,然后后面8字节是salt值。
我们先把这个salt提取出来。
ENCSIZE=$(hexdump -s 0x18 -n 4 -e '1/4 "%u\n"' M30A1_FW110B02.bin) echo "ENCSIZE=$ENCSIZE" ENCSIZE=38871424 dd if=M30A1_FW110B02.bin of=raw_enc.bin bs=1 skip=$((0x41)) count=$ENCSIZE
8ccK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">
我们先提取盐和加密数据这一段,从0x41开始。

0f0K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
这次就是对的,也符合我们一开始用binwalk找到的salt: 0xE5C9BB84466AF3C5。
//从第 73 字节 (0x49) 开始,切 8 个字节,存为 salt.bin dd if=salt+ciphertext.bin bs=1 skip=8 count=8 of=salt.bin //查看提取出来的 Salt (HEX 格式) xxd -p salt.bin
b9cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">

1f7K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
确定这是我们的salt,接下来寻找IV。
dd if=salt+ciphertext.bin bs=1 skip=16 of=ciphertext.bin
a38K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">
三、寻找IV
首先我们理清一下逻辑,我们再看一遍这两种方法,一种是基于密码加密、一种是基于原始密钥,我们有Key,Salt那就可以尝试基于原始密钥的方式了,去寻找IV尝试解密,我们直接给AES塞入Key和IV直接加密,由此我们大概率能猜到IV。

b2dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
为什么说IV我们可以找到,我们可以确认算法是AES-128,这是在升级公告中所提到的,IV长度需求是16字节,我们紧盯着0x41之前的数据。

cafK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
Salt之前的数据,前32字节(0x00-0x1F)元数据区,这里存放着魔术头、固件大小、校验和版本号等,元数据结束后紧接着通常是加密参数,我们最重要的就是IV,然后0x41又是Salt,这是OpenSSL的标准头,其实我们要找的IV必须存在0x20-0x40这一段空窗期,不然我们没办法在解密前拿到他,是这样的。
接下来我们分析这一段吧,把他了解透彻。
MH01就是固件的签名,魔术头,01应该代表版本号v1,然后0x10这一行也有一个MH01再次确认一遍,0x18是我们大概是加密数据的长度。然后再往后走就发现了两行奇怪的数据,我们看一下。

7edK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
这两行看到了奇怪的数据,那我们根据之前的想法也大概率能想到是IV,这32的ASCII字符表示16字节的HEX IV。
为什么这32字节是16位的IV呢,因为AES算法在底层运算时是需要16字节的二进制数据的,我们开始截取。
(1)、提取
我们提取就要从0x20开始,也就是32字节开始,切32字节,把IV保存成一个文件
(2)、确认IV
如果这段数据是IV的字符串表示,他应该只包含0-9和a-f(或A-F)字符,他不会出现乱码,我们可以试试cat和hendump验证验证。

c4fK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
我们大概率可以确认是IV

256K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
接下来验证一下字符个数,也就是长度。

62dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
5、尝试解密
既然我们知道他是用OpenSSL加密的,我们尝试用OpenSSL解密,我们调用OpenSSL的enc,尝试一下。
aes-128-cbc:指定算法,告诉这个OpenSSL是AES加密,128位的,CBC模式。
-D:Decrypt(解密)不加这个是默认加密
-K:Key(密钥)通用钥是
-iv(小写):切出来的IV
-in:输入文件(纯密文)
-out:输出文件(解开后的固件)
openssl aes-128-cbc -d -K xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -iv $(cat IV.txt) -in clean_ciphertext.bin -out decrypted_b451.bin
d86K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">
这里尝试了很多次,好像都不太行

f2cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
有一些突破,但是不知道是不是这样。

0bcK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
偶然回头以看发现我们已经成功破解了,我们回顾一下解密这一部分。但是写到这里我整个人还是有点疑惑,疑惑在于不论我是否解密成功他都会报错
6、解密回顾
一、提取加密字段、IV
echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx > IV.txt 写入IV
fddK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">
精确提取从Salted__头部开始的完整加密数据块
dd if=M30A1_FW110B02.bin of=raw_enc.bin bs=1 skip=65
9e8K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">
但是有时候拆分数据时候会发生错误,建议用dd来截取。
我们可以把签名这一段忽略

376K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
这里面我们把0x41开始截取,这样我们能得到一个带盐+密文的字段,然后后续我们再提盐。

8cbK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
提取到这样我们整个文件就工整很多了,然后我们提取后8位的Salt,然后再把整个Salt部分去除掉就变成了完整的加密部分。
二、核心解密
下一步我们就用OpenSSL解密,我们一开始手上是掌握了Key的,然后使用命令。
openssl aes-128-cbc -d -pass pass:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -in raw_enc.bin -out try_pass_mode.bin
7c6K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">
三、密码学模式推断与试错
首先确定了密文的起始字节为Salted__,证实用了OpenSSL的EVP框架,Key派生是必须的。
然后基于D-Link更新公告和IV长度,锁定算法为AES-128-CBC
四、KDF(密钥派生成功)
改变Key的角色,激活OpenSSL的自动派生机制
运行-pass模式,将Key是为Password,结果就是OpenSSL自动读取文件中的Salt,并使用Password+Salt派生出Key/IV,然后我们成功实现了,熵值降到0.69,证明Key是Password,而bad decrypt是虚假报错,数据主体已解密。
五、EVP_BytesTokey派生逻辑实现
#!/bin/bash
# --- 1. 定义常量 ---
PASSWORD="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# 假设 salt 已经从 raw_enc.bin 中提取并保存在这个文件里
SALT_FILE="extracted_salt.bin"
# --- 2. KDF 第一轮:生成 D1 ---
echo "--- KDF 1/2: 生成 D1 (SHA256(Password + Salt)) ---"
# 拼接 Password 和 Salt,并计算 SHA256 摘要
{ printf "%s" "$PASSWORD"; cat "$SALT_FILE"; } | openssl dgst -sha256 -binary > D1.bin
echo "D1.bin 创建完成 (32 bytes)"
# --- 3. KDF 第二轮:生成 D2 ---
echo -e "\n--- KDF 2/2: 生成 D2 (SHA256(D1 + Password + Salt)) ---"
# 拼接 D1.bin、Password 和 Salt,并计算 SHA256 摘要
{ cat D1.bin; printf "%s" "$PASSWORD"; cat "$SALT_FILE"; } | openssl dgst -sha256 -binary > D2.bin
echo "D2.bin 创建完成 (32 bytes)"
# --- 4. 拼接并提取 Key/IV ---
echo -e "\n--- 提取 Key 和 IV ---"
# 将 D1 和 D2 拼接成完整的 64 字节密钥材料
cat D1.bin D2.bin > KM.bin
# 提取 Key (前 16 字节用于 AES-128)
dd if=KM.bin of=derived_key.bin bs=1 count=16 status=none
# 提取 IV (从 16 字节开始,提取 16 字节)
dd if=KM.bin of=derived_iv.bin bs=1 skip=16 count=16 status=none
# --- 5. 打印结果 (十六进制) ---
echo -e "\n派生出的 Key 和 IV (十六进制):"
KEY_HEX=$(xxd -p derived_key.bin | tr -d '\n')
IV_HEX=$(xxd -p derived_iv.bin | tr -d '\n')
echo "KEY (-K): $KEY_HEX"
echo "IV (-iv): $IV_HEX"
# --- 6. 最终解密命令示例 ---
# 使用派生出的 Key 和 IV,对纯密文文件 (cipher.bin) 进行解密
# openssl aes-128-cbc -d -K $KEY_HEX -iv $IV_HEX -in cipher.bin -out manual_code_decrypt.bin7a6K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">
六、解密实质
一开始的Key我们原以为是用于解密也就是-K模式,然后呗KDF流程处理了,但是这个Key是作为KDF的输入,也就是-Pass模式,他被OpenSSL读取,然后与Salt混合,派生出了真的AES Key和IV。
也就是说我们提供的Hex串作为Pasword,必须进入KDF与Salt混合,才能产生出真的Key和IV
七、手动解密流程
如果我们想脱离OpenSSL的-pass模式,我们需要以下三个步骤。
(1)、定义常量
PASSWORD="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" SALT_FILE="extracted_salt.bin"
6cfK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">
我们需要把Key当作Password,然后把Salt单独放一个文件中。
(2)、运行KDF逻辑,生成Key
这里使用SHA-256两轮KDF逻辑,只提取key
D1 = SHA256({Password}+{Salt})
//生成D1(SHA256(Password + Salt))
{ printf "%s" "$PASSWORD"; cat "$SALT_FILE"; } | openssl dgst -sha256 -binary > D1.binac1K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">
D2 = (SHA256(D1 + Password + Salt))
//生成 D2 (SHA256(D1 + Password + Salt)) { cat D1.bin; printf"%s""$PASSWORD"; cat "$SALT_FILE"; } | openssl dgst -sha256 -binary > D2.bin88cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">
拼接并提取Key(前16字节)
cat D1.bin D2.bin > KM.bin dd if=KM.bin of=derived_key.bin bs=1 count=16 status=none
17aK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">
# 将 Key 转换为十六进制字符串 KEY_HEX=$(xxd -p derived_key.bin | tr -d '\n') echo"Derived Key: $KEY_HEX"
afcK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">
(3)、混合解密(Code Mode)
现在用我们派生出的Key和Header中的IV对纯密文解密。
openssl aes-128-cbc -d \ -K "$KEY_HEX" \ -iv "$IV_HEX" \ -in cipher.bin \ -out hybrid_decrypt.bin
927K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">
我们可以得到派生的Key和IV。
openssl aes-128-cbc -d -K xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -iv xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -in cipher.bin -out manual_decrypt_success.bin
bbbK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">
然后再执行即可。

16bK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
这里我们想不依赖-pass模式,手动解密,把Key当作Password然后追踪一下全流程,这样来说说可以更清晰的其加密过程。
echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" | xxd -r -p > password_raw.bin
//准备好Key也就是Password
echo "E5C9BB84466AF3C5" | xxd -r -p > salt_raw.bin
//盐
{ cat password_raw.bin; cat salt_raw.bin; } | openssl dgst -sha256 -binary > D1.bin
//生成D1
echo -n "D1 (HEX): " && xxd -p D1.bin | tr -d '\n' && echo ""
//打印D1
D1:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
{ cat D1.bin; cat password_raw.bin; cat salt_raw.bin; } | openssl dgst -sha256 -binary > D2.bin
//生成D2
echo -n "D2 (HEX): " && xxd -p D2.bin | tr -d '\n' && echo ""
//打印D2
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
cat D1.bin D2.bin > KM.bin
//拼接完整密钥
dd if=KM.bin of=derived_key.bin bs=1 count=16 status=none
//提取Key前16字节
dd if=KM.bin of=derived_iv.bin bs=1 skip=16 count=16 status=none
//提取Key后16字节
echo -n "派生 Key: " && xxd -p derived_key.bin | tr -d '\n' && echo ""
# 10. 打印派生的 Key (D1)
# 11. 打印派生的 IV (D1)
echo -n "派生 IV: " && xxd -p derived_iv.bin | tr -d '\n' && echo ""cfeK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">

31dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑
成功
八、算法原理(IV和Key来源)
为什么是SHA-256哈希运算,因为每次运行SHA-256都能产出32字节的数据。
但是问题在于我们在文件头看到了数据只有IV没见到Key的身影,原因就在于如果只进行一轮的话确实刚好足够32字节,但这样Key和IV必须从这同一个32字节中分出来。
但是如果Key和IV都是同一轮生产出的话会很不安全,基本是打名牌,最安全的方式就是第一次产出32字节提供给Key,第二次产出提供给IV,这样总结64字节,也会很安全。因此厂商必须进行两次SHA-256运算,才能保证Key和IV都有足够的密钥数据,这是更安全的。

790K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0M7$3c8F1K9h3#2Y4i4K6u0W2j5$3&6Q4x3V1k6J5k6h3I4W2j5i4y4W2i4K6u0r3j5X3I4G2k6#2)9#2k6X3g2V1K9i4c8G2M7W2)9#2k6X3S2@1L8h3I4Q4x3V1k6J5k6h3I4W2j5i4y4W2x3W2)9J5k6e0c8Q4x3X3f1@1i4K6u0r3j5$3E0W2k6r3W2@1L8%4u0Q4x3V1k6H3L8s2g2Y4K9h3&6K6i4K6u0r3N6$3W2V1k6$3g2@1i4K6u0r3K9h3#2S2k6$3g2K6i4K6u0r3K9r3q4F1k6r3I4W2i4K6u0W2M7r3&6Y4i4K6t1&6i4K6y4n7">编辑