最近peazip这款压缩软件似乎有点热度,原因是除了传统密码加密之外,还能够添加使用文件作为密钥,能有效防止分享的资源被在线解压从而被和谐。我想,使用这个软件的文件密钥加密功能,可能会成为未来分享文件的一种趋势。而我最近开发的f-keydle,一款专门解多层压缩包的软件,我觉得势必也要支持解压由peazip这种加密方式创建而来的压缩包,这就是我研究如何将peazip的文件密钥加密模式转换为明文密码的原因。
其实我从好几个月之前就开始研究这个了,当时甚至已经从官网翻到了有关文件密钥转文字密钥的方法,链接和截图如下:
https://peazip.github.io/extract-encrypted-files.html
我之前没发现规律前的理解是,先把文件的sha256得到,然后把显示出来的结果(显示出的字符串)编码为base64放在前面作为文件那部分对应的密码,然后如果有额外添加的密码的话,把密码拼接在后面,这样就得到了一整段密码。然而,经过好几次尝试,均以密码不正确告终,我甚至猜测了密码前面有什么类似“filekey=”之类的前缀,或者sha256显示的大小写,或者说因为base64三个一组编码的特性,可能sha256最后会补上几个空格、0、下划线来凑成3的倍数后再编码为base64等等这些情况,不过这些尝试也宣告失败了。
我想自己暂时没有能力搞定这件事了,这件事于是被搁置了几个月,直到f-keydle的2.1版本更新,我在帖子里写出了这个想支持peazip的想法,帖子发出后出乎意料的得到了站里大佬@风之暇想 的回复,说是看的机器翻译说是先把文件转换成base64,然后再取sha256的值,看到后我就准备再尝试一下,用了个很小的文件作为密钥加密压缩包,然后使用在线工具进行转换,同样地,也似乎在意料中地失败了。
不过,这次站里大佬的回复给了我一点信心,我的好运气似乎也就这样来了。收到回复后差不多一两天,突破口就来了,我无意中点开了peazip的“控制台”选项卡,然后看到了一堆7z的命令,于是想到了之前看过的7z的命令行里,“-p”的后面是接密码的,于是眼光落在了那个区域,如下图被鼠标选中变蓝的区域:
于是把那部分密码复制了去解码,结果得到了一堆乱码,只有几个可见的字符:
emmm,不管怎么说先把之前-p后面的密码复制下来再说吧,先反过来把文件的sha256编码成base64试试,放在一起对比看看有什么规律:
乍一看似乎没有什么规律,还一短一长,但是光标放在一行的末尾,看到列数的时候,就发现了一个重要信息:
记事本光标放到一行文字开头,显示的是第1列,也就是说第一行peazip生成的密码有44个字符,而第二行从文件sha256显示的结果编码而来的有88个字符,正好是个两倍的关系。一个文件的sha256不管怎么说,显示出的结果的位数都是固定的,编码出的base64位数也该是一样的,怎么到了peazip这里就被砍半了呢?莫非peazip是两位一组?想到这里,回头看了看文件的sha256值:220f5398866623e40ce4bcc0f51f3744005cb56a8dd288c9c015b42e20a623e7 (上面的截图里也有),发现两位一组,似乎可以像winhex显示的那样,解读为单个字节对应的十六进制码。回到刚才解码显示出的一行乱码中,开头的英文双引号“ " ”对应的编码是U+0022,对应着sha256显示结果的第一组“22”;乱码里倒数第二个可见字符“ # ”对应的编码是U+0023,也对上了sha256显示结果的倒数第二组“23”,原来是这么转换文件sha256到base64的。至于额外添加的密码,后面我试着加了额外的密码,发现密码都是拼接在文件的base64后面的。
没想到规律就这么找到了,困扰我这么几个月的问题就在机缘巧合下就这么解决了,那叫一个开心啊,记得我当时激动地用力拍起了手。或许过去几个月我也看过那个“控制台”的窗口,或许也曾经想要试过将“-p”后面的密码找出些门道(我忘记有没有这么做过了),但是这一次的运气实在是太好了。说起来,我可能还要感谢@风之暇想 大佬带来的好运呢,哈哈。
规律找到后,接下来就是着手写软件了,也就是现在所分享的这个,下面是软件核心部分,转换文件到最终密码的代码:
[Python] 纯文本查看 复制代码 #计算sha256,推算出结果的进程函数
def calc_process(file_path:str) -> str:
#获取文件的sha256校验值(字符串)
h = hashlib.sha256()
f = open(file_path, 'rb')
while b := f.read(8192):
h.update(b)
f.close()
sha256_chars = h.hexdigest()
#把sha256校验值字符串看成十六进制的字节串(每两个字符为一个字节,就类似winhex显示的那样)进行转换
hex_bytes = bytes.fromhex(sha256_chars)
#把转换后的bytes编码成base64的bytes
base64_bytes = base64.b64encode(hex_bytes)
#解码为字符串
base64_string = base64_bytes.decode(encoding="utf-8")
return base64_string
如果有额外的密码,直接拼接在文件所对应的密码后面就行了,就不作展示了。
说是v1.0,其实软件在我手里已经迭代了好几个版本了,从最初的命令行窗口,到GUI窗口,制作每一次拖放后能自动清除上一次输入的文件路径的拖放窗口,以及后来为了解决处理大文件时界面卡死,在额外的线程或者进程里处理的功能,增加文件数据记忆和选择性删除文件记忆的功能等等,可谓是有点“费尽心思”,现在想到能提升的地方就是加个文件处理的进度条了,不过考虑到进度条实现起来很复杂,而且作为密钥的文件大多都是小文件,不需要等待很长时间,即使是2G大小的文件在我这也就是十几秒的功夫就处理完了,所以就没有加进度条。我想,对于我这个接触PyQt5不到一周的人来说,应该算是做得比较好了。
|