加密算法库之mbedtls
WangGaojie Lv4

一直对各种加密算法库都非常感兴趣,之前用wolfssllib做过一些关于RSA的非对称加密的测试。最近又在做https相关的内容,由于wolfssllib的版权问题,不方便于商业开发使用,所以准备换到mbedtls进行https相关的开发。

mbedtls的移植和使用都比较简单,唯一走的弯路就是在实现底层calloc函数时出了一点意外,最开始没注意到申请的内存需要清零,因为我用的是malloc来申请内存,内存默认没有清零,导致mbedtls在进行大数运算时经常卡死或者出错,这个问题折腾了好久。

用mbedtls作为https的tls层,配置基本可以照搬官方的默认配置模板,然后做一些针对特定平台的适配,主要是内存、时间、随机数生成器这方面的适配。

考虑到在单片机环境不方便更新CA证书,我选择不校验服务器证书。这或许会导致中间人攻击,但是在专用通讯网络中,我认为没有这方面的风险。

关于https的细节不是我今天想说的,我今天想对比一下wolfssl和mbedtls的RSA算法差异。虽然目前主流的服务器的tls都基本上是椭圆曲线加密,但是RSA作为一种非常经典的非对称加密算法,仍然值得学习。

这里先对比一下wolfssl和mbedtls的RSA算法在ARM单片机(STM32H7@480MHz)上执行的效果,以生成一个2048位的密钥对来进行测试。

lib wolfssl mbedtls mbedtls
(without MBEDTLS_HAVE_ASM)
执行时间(秒) 25.7 2.17 15.8
堆内存使用(kb) 17.2 14.2 14.2

显然在单片机上mbedtls的性能要好得多,我认为其中最关键的应该是mbedtls针对特定处理器架构所做的优化,这些优化在大整数计算性能方面有非常大的提升。

通过对运行时heap区的数据进行分析,wolfssl性能偏低的原因主要是在进行大整数计算时频繁的内存分配导致的。wolfssl在生成2048长度密钥时,内存分配次数达到了20万次以上,而mbedtls生成相同的密钥数据时内存分配只有几千次。

wolfssl也不是完全没有优点,通过对编译后的二进制文件进行分析,mbedtls相关函数所使用的栈空间要更多一些,总调用栈深度达到了3kb字节,而wolfssl的栈调用深度在1kb以内。

了解RSA算法的开发者应该都知道,RSA密钥生成中最关键的算法就是大质数生成算法,这应该是决定两者性能关键的算法。

通过分析代码来看,两者的实现都基本上差不多。首先利用随机数生成器生成一个2047位的随机数,然后判断这个树是不是质数,如果不是质数则重新生成一个,直到生成了一个可以用的质数。

根据素数定理来看,在这种长度级别的整数附近,素数的密度在千分之一左右。所以这是一个需要反复试错的算法,这是无法避免的。

所以为了提升效率,素数的判定上就必须要尽可能的优化。mbedtls构造了1000以内的质因数用来快速验算待判定的树是否存在一些小的因数,然后再使用Miller-Rabin算法进行素性测试。wolfssl在操作上类似,不过它的素因数表要稍微大一些,最大的素数是1619。此外,在验算两个大质数的距离时,两个库也存在区别,mbedtls先生成两个大质数P和Q,再计算它们的距离,如果距离太近的化就重新生成P和Q。而wolfssl在校验第二个质数Q的素性前先进行了距离计算,这样效率应该快一些,且当距离不满足要求时只需要重新生成Q即可。看起来在这些细节方面wolfssl的策略要更好一些,不过它的代码看起来也要复杂许多。

在移植这两个算法库之余,还学习椭圆曲线加密相关的内容。RSA密钥生成过程中由于需要不断试错来寻找大质数,所以在嵌入式系统中看起来它的性能就不是很稳定。而椭圆曲线加密在这方面就要好得多,椭圆曲线的密钥生成不依赖大质数生成,无论是计算量还是稳定性都要好得多。椭圆曲线依靠椭圆曲线上的离散对数问题的复杂性来保证安全,而RSA依靠大数分解难题来保证安全性,在安全性上面椭圆曲线也应该要更好。