走~走走~走走走走​🚶‍♂️🚶‍♂️🚶‍♂️

综合课程设计:令人感叹


课设过程没有记录时间线,因此该博客少了点条理性。
第一次写这种稍微大一点的项目,过程还是值得记录下的。

开始

综合课程设计刚开始选题的时候,定位到负责我们这一块的申杰老师项目列表,所有项目几乎都和CV,机器学习相关,唯独一个文件加密传输十分显眼。5难度,刚好上学期上过密码学。不觉得很酷吗?很符合我对分数的想象。

于是我自信满满的选了,持续一个月的噩梦也开始了。

第一步自然是选择库我怎么会先想着造轮子。题目要求C++,那图形化软件很容易想到Qt;而密码库的选择倒是一波三折,原本想用成熟的OpenSSL的,但学习成本极大,于是翻知乎翻到现在用的CryptoPP库,有wiki有示例代码,想要的加密算法一应俱全,还是C++原生的,太好了,就它了!

然而之后大部分的bug(或者说,全部恼人的bug)都来源这个加密库。这部分暂且不提。

CryptoPP库没有现成的lib,换句话说需要自己编译。打开它的github下载源码,发现这玩意使用VS编译的(不用CMAKE?),源码里甚至有专门提供给VS2005的用户的sln文件.

好,那我就用VS2022给你编译了,然后喜闻乐见的报错了。翻网上资料发现要用VS2017,那就装!(电脑被VS狂暴鸿儒四五次才装好,C++下的SDK确实难绷)

编译好了(已经过去三四天了),配环境部分最恼火的来了:我该怎么让QtCryptoPP适配呢?
装了Qt七八回,Qt老版本的VS只支持VS2015套件,而新版本的VS2017套件不知道怎么回事检测不到本地的VS2017 SDK。折腾了三四天才挑出来符合的Qt版本,之后又花了一天在Qt的项目配置文件.pro边查边写,终于搞好了VS2017 编译的CryptoPP在windows下如何和VS2017 SDK套件的Qt以及qmake适配。

这就是装环境,听devops说

网络通信部分(QT)

这部分其实没啥好说,各种抄,抄着抄着就把自己软件的框架搭好了,然后在这基础上改了。
后面翻了下,我在原来的代码上改了挺多的,看上去确实和原来代码差别很大。socket从两个到三个又到两个,还稍微学了下TCP的粘滞,以及Qt神奇的信号和槽机制。

若把TCP作为一种抽象流,那么我们是无法分辨其中数据意义的。若要分辨,必须事先知道文件/消息的长度,然后再根据长度进行截断。
需要指出的是,暴露密文的长度并不会影响安全性,因此可以将密文的长度直接暴露在不安全信道下。

Qt的信号与槽是可以反复绑定的。反复绑定对于某些情况是不要紧的,但如果你需要信号的参数,这就有大问题。我在一个函数里写了connect进行信号和槽的绑定,而该函数多次调用导致一个信号和多个槽(但其实是一个)进行了绑定。于是槽函数便收到了多个信号,而这些信号都是来源于同一个动作函数的。

密码学部分(CryptoPP)

具体细节放报告里了不想写,这里挑几个CryptoPP的神奇bug罢。

中文

这个其实还好,CryptoPP不支持中文路径和中文名的文件加密。但还是可以吐槽:不是只对文件内部数据进行加密签名吗?名字按二进制存取不行吗?

RNG

不是电竞那个RNG,hz打来我就投降。

RNG(Random number generator),在密码学中是十分重要的一个原语,用于生成伪随机数,然而CryptoPPRNG行为十分特异:RNG定义后必须立即使用,不能放在其他地方(比如我原先放在一个统一管理的CryptoManager class里头)备用。否则CryptoPP自己推荐的“对加载的密钥必须进行验证(Valinate,该操作接受一个RNG和一个验证级别作为参数)”便会Runtime-error.

DSA

DSA是十分经典的数字签名方案,本来想在课设里实现一下的。但CryptoPP库的DSA内部出现了问题:我在同一份代码里对文件生成签名,之后立刻验证,直接RE。后面~~经过输出debug(ACM习惯了属于是)~~定位到CryptoPP库内部出现问题,没啥办法,删了罢。

RSA

RSA作为公钥加密方案,同时也支持数字签名。但运行过程中,CryptoPP库又出现了和DSA一样的错误。到这里我还是没发现为什么数字签名会产生错误,后面选择ED25519作为数字签名方案的时候才偶然发现,又是你,RNG

CryptoPP库的RNG支持极其不完善,而示例代码中,数字签名基本都需要使用RNG作为参数来进行验证。而WIKI中的ED25519示例代码十分特殊的把对应的RNG换成了NullRNG,这十分形象的名字,使得ED25519能够顺利进行签名。于是ED25519成为了课设里唯一的数字签名方案。

看到这里的你其实也明白了,理论上DSA,RSA这两个弃用的数字签名改改RNG就能恢复使用,但我懒了,不改了😇

ED25519

ED25519是椭圆曲线数字签名方案,其公钥密钥长度为64/32 bytes,在其他语言中可以自由选择这两个。

CryptoPP与众不同:头文件写明default情况下,ED25519应该生成32bytes的密钥,但它实际上生成了56bytes的密钥,前面多出来的24bytes是不变值。

若按照示例代码所写进行编程,那么密钥中将会包含24bytes的确定值,以及8bytes的随机值,而这显然会影响到ED25519的安全性。
而被DSA,RSA,以及接下来的GCM摧残许久的我放弃了修改(虽然修改确实会比较容易),多一事不如少一事,何况这ED25519能跑。能跑就行,不奢望太多了。

反正老师也看不懂

GCM

GCM是在对称密钥加密里头的操作模式,它提供了AE安全性,因此满足了CCA安全。。。。
以上部分换成人能听懂的,就是:GCM能够提供比采取普通操作模式更强的安全性,而这部分安全性的来源,很大程度上来源于它独立生成的GMAC 认证标签,这是其他操作模式所没有的。

这么好的安全性自然要拿来用了。照着wiki代码敲一遍,RE…RE?

翻了StackOverflow,发现示例代码是错的,代码把Tag长度和IV长度搞反了。呃呃💧。
最离谱的是:CryptoPP wiki专门写了:初始的IV向量可以是任意长度;但实际过程中,IV必须为12字节。


另外还有诸如指针没有new变量导致程序出现奇怪bug,被yaossg(orz)指出后心态炸裂等nt行为,暂且不表。

summary

CryptoPP库极其难用,于是只能挑几个毛病最少的使用。但最本质的问题并不在此,而是:为什么要用C++开发?

C++没有内置的密码库,所以我只能挑不靠谱的第三方库作为代替,而其他语言,比如JS,C#,JAVA,这些都有十分成熟且现成的密码库,并且图形化软件编写更比C++容易的多。而申请改换语言只要和老师说一句就行了。

当我发现这个问题的时候,我已经把代码写完了。

也许综设整个过程就是个笑话。哈哈。


Author: ZzzRemake
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source ZzzRemake !
Comment
  TOC