目前Linux内核已经较好的支持了SM3和SM4算法,这得益于无线局域网标准的广泛使用。但SM2算法和国密证书迟迟没有得到支持,也就无法基于国密来建立全栈可信和内核中的完整性验证,因此在内核中支持这一套体系也变得迫切起来。整个规划是:在内核中支持SM2算法和国密证书,在内部业务率先应用起来后,最终推进到社区。整个流程下来,诸多不顺,权且记录下来。
第一回,有了规划,接下来就是考虑如何实施。但凡密码学算法,都会先考虑是否可以从openssl做移植。幸运的是,openssl对SM2/3/4支持得非常好,椭圆曲线算法的实现久经考验,非常成熟,而且最新版本也完整支持了国密证书。不幸的是,openssl的各个模块之间藕合度很高,要实现SM2和国密证书,需要移植openssl架构和基础设施代码,包括BIGNUM、ECC、X509等。这个工作量无疑是巨大的,即便实现了,这种方式也很难被社区接受,再三考虑权衡后,果断放弃了这条"捷径"。
第二回,发现了一个令人惊喜的事实:内核中已经有了一个椭圆算法的基础实现(crypto/ecc.c),何不尝试基于这个算法来做呢?于是参照SM2规范开始coding,但结果有点遗憾,这个椭圆算法在SM2上居然失效了,连最基本的点乘结果都是错的!纳尼?剧本不应该是这样的。于是发邮件咨询该算法的一个资深开发者,很快就得到了下面的回复(感叹天下还是好心人多):
Shamir's trick algo is probably generic, but it's ecc_point_double_jacobianthatiscurve specific.Algorithms are chosen that are fit curves I (andprevious coders) used.You need to check their properties carefullyifyou going to use them.Some variants of used algos, that may fit other curves, areinreferencedpapers (incomments).总结原因:这个算法是经过高度优化的算法,是精确适配过NIST和ECRDSA椭圆曲线参数的,并不一定适合国内的SM2曲线参数,看来这条路是走不通了......
......哭泣中,别理我。
......擦干眼泪,看成败,人生豪迈,不过是从头再来......
第三回,经过反复探索,发现内核中RSA算法是基于一个mpi(高精度整数)库实现的,这个库来源于libgcrypt(这是知名隐私保护软件GnuPG的底层算法实现)。内核中已经实现了一个早期版本的mpi,当时就是为了实现RSA引入的。现在的libgcrypt已经有了完整的椭圆曲线基础算法,于是抱着试试看的心态基于libgcrypt测试SM2算法曲线,苍天保佑,这次的惊喜没有变成惊吓,实验结果与SM2规范一致。
第四回,libgcrypt中的ECC算法是个通用的算法,实现藕合度低。于是有了一个想法,可以尝试先在libgcrypt中实现SM2,小试牛刀之后再把这一套东西全部移植到内核,进一步推进到社区,看起来这也是能被社区接受的方式。有了计划后,索性摆个安逸的造型,庄严肃穆地将双手放在键盘上,让思维随着手指自然流淌,接下来的开发调试就比较顺利了,很快便有了公钥算法的四件套:加密,解密,签名,验签。一鼓作气把这些实现提交到了libgcrypt社区,经过两轮的review再修改之后,最终SM2算法作为ECC的一个子算法被社区接受,这里要感谢libgcrypt的maintainer之一的NIIBE Yutaka,耐心友好,对中国传统文化也很了解。整体过程比较顺利,表过不提。附上相关commit:
http://git.gnupg.org/cgi-bin/gitweb.cgi?p=libgcrypt.git;a=search;s=Tianjia+Zhang;st=author
第五回,趁热打铁,由于内核中的 lib/mpi 库是一个较老的版本并且是为RSA服务的,相对于libgcrypt中的mpi,是一个阉割的版本,需要移植缺失的函数以及ECC算法,这没什么技术难度,却也是一个精细活,工作量也不小。在实践中,把实现SM2的过程中所缺失的东西都移植过来,很快便有了相应的SM2算法和国密证书的实现。再经过几轮打磨,并做了充分的测试后,就有了最初的这组patch:http://lkml.org/lkml/2020/2/16/43
第六回,中国古语曰过,一鼓作气,再而衰,三而竭,事情的进展再次遇到阻碍。Linux内核比不得专用的密码学库,对于这么一个不怎么知名的算法,社区并没有表现出什么兴趣,甚至鲜有人问津,最终以没有实际应用场景而被拒绝。事情当然不能就这么结束,考虑到代码量大,maintainer review意愿低,果断裁剪掉了SM2的加解密和签名,只保留了支持国密证书必要的验签功能,后来陆陆续续又做了一些小修小补,同时给IMA的upstream做了国密算法的增强以便将国密功能在IMA场景的应用作为实际案例。同时,随着跟相关开发者和maintainer不断的软(si)磨(chan)硬(lan)泡(da),不断地发送新的patch,最后甚至都摸透了maintainer习惯性的回复时间和patch的合入规律,持续地缓慢推进SM2进入社区的步伐。这期间没有波澜壮阔的故事,也没有狗血的剧情,balabalabala......,省略while (1) {...}循环。第七回,年过中秋月过半, 历时半年多时间,SM2早已不是那个最熟悉的娃,不知不觉patch也更新到了v7版本。中秋月圆之夜向来都是有大事要发生的。是夜,一个盖世英雄,头顶锅盖,腰缠海带,脚踩七彩祥云飞过来了,SM2终于等到了它的至尊宝。言归正传,这个版本的patch最终被社区接受,目前已经merge到了Linux主线的5.10-rc1:
http://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?qt=author&q=Tianjia+Zhang
,如不出意外会在5.10内核版本中正式release。
后来有幸在某个机缘巧合之下,在libgcrypt中实现了SM4。作为国密开发过程的一个附属产物,目前libgcrypt已经全面支持了国密算法SM2/3/4,这些实现都会在下一个版本1.9.0正式release。其中SM3由相关同事在2017年开发。http://sourceforge.net/p/linux-ima/ima-evm-utils/ci/ceecb28d3b5267c7d32c6e9401923c94f5786cfb/log/?path=
当下SM2还有一些问题需要注意: