一文了解Linux Kernel中密码学算法的设计与应用
基本概念,如下请自行学习和理解:
- 对称密码
- 非对称密码
- 数字摘要
- 随机数
Linux Kernel系统中实现了很多算法,这些算法被统一归纳为:对称密码算法、数字摘要算法、随机数算法、认证加密算法、非对称密码算法等,并在Kernel层提供了统一操作的接口,供kernel其他模块调用。部分算法又被封装到了网络层,开放暴露给Userspace。其具体的结构/接口模型如下所示:
Userspace通过netlink接口方式( PF_ALG)调用到底层算法的实现
在Userspace,需指定socket接口 PF_ALG,需指定算法名称(如skcipher)、需指定具体调用的"算法实现"(如aes-cbc),这样命令传输到Kernel层,就能根据这些信息跳转到响应的算法实现层。注意akcipher算法没有暴露给网络层,也就没有开放给Userspace了,所以在User程序中,是无法调用Kernel层的非对称密码算法的。
如下是一个Userspace程序调用kernel底层算法的示例:
(1)建立一个socket会话的流程:
(2)相关代码
Kernel程序对底层算法的调用采用函数直接调用的方式。流程为:kernel程序--->算法中间层--->算法实现层. 算法中间层 就是暴露给kernel其它模块的API函数。
如下是一个kernel中调用底层算法的一个示例(因skcipher为例):
增加一个"算法的实现" 只需要:
- 定义一个该算法的结构体变量并初始化,其实就是实现其中的成员函数
- 将该算法实现注册到系统中。
结构体的定义并初始化:
成员函数的实现,例如:
将该算法实现注册到系统中:
小小总结一下, 如果您要增加一个算法实现,那么您就是需要实现定义如下结构体,并调用 crypto_register_xxx()注册到kernel系统中:
- skcipher_alg
- akcipher_alg
- ahash_alg
- rng_alg
- aead_alg
思考:
- 对称密码底层是怎样实现的?纯软?硬件?Neon指令?CE指令?
- 非对称密码底层是怎样实现的?
- Hash、rng、aead 又都是怎样实现的?
实现算法的方式:
(1)在armv8/armv9的芯片中,有ARM-CE指令可以进行aes/hash/md5计算,
(2)在armv8/armv9的芯片中,也有ARM-NEON指令也可以进行aes/hash/md5计算
(3)arm的security IP中,有cryptocell之类的加密芯片
(4)另外SOC厂商也可能集成自己设计的crypto engine加解密芯片
(5)除此之外,还有C语言、汇编程序等编程语言实现的纯软实现
毫无疑问,在效率这块肯定是:(3)(4) > (1) > (2) > (5). 另外从"实现算法的方式" 来看,如果是rng、aead、rsa之类的算法,那么就不能用ARM-CE这种方式,只有编程语言实现、Neon指令实现、crypto engine(含arm security IP)这几种方式了。
kernel怎么玩的?:
针对 crypto engine(含arm security IP) 这种,先当SOC硬件不支持,跳过此场景。
针对rng、aead、rsa,那么kernel有一套纯软的实现 (似乎没有看到arm neon指令的实现)
针对aes、hash,有arm-ce的实现、arm neon指令的实现、纯软的实现,三者三选一(通过宏开关,只能选1)
crypto engine的实现:如果自定义了crypto engine的实现,那么要看你具体的设计,是设计成“取代原有算法实现”,还是设计成“新增算法实现”。如果是前者,那么对于aes/hash,则变成了四选一的了(crypto engine实现、arm-ce的实现、arm neon指令的实现、纯软)。如果是后者,这和原有实现不冲突。
有关aes/hash底层实现三选一的开关:
(1) 开启下面两个宏,使用ARM Neon指令的实现 CONFIG_CRYPTO_AES_ARM64_CE_BLK CONFIG_CRYPTO_AES_ARM64_NEON_BLK
(2) 在(1) 的基础之上,再开启如下宏,使用ARM CE指令的实现 USE_V8_CRYPTO_EXTENSIONS
(3) 以上三个宏都不开启的情况下,使用默认的纯软实现
(以ARM Security IP的cryptocell 712为例)
在Linux Kernel中开启 CONFIG_CRYPTO_DEV_CCREE宏控即可起用该实现, 代码路径如下:
以为aes-cbc为例,其实现的名字 和 Kernel中默认是算法实现的名字是一致的,即使这种实现方式是取代原有算法实现
在网络层、算法中间层、算法实现层有着丰富的结构体类型?那么怎么去阅读代码?怎弄清各个层面之间的逻辑呢?事实上我们只要理清这些结构体之间的关系,将其抽象成模型,就会变得更加容易理解了。
如下是以Userspace调用底层的对称密码函数为例总结的一张数据结构图:
sock通信进入网络层后(algifskcipher.c),构建skcipherrequest结构体,通过该结构体,就能寻址到底层的算法实现,继而完成算法实现的调用。这些总结一下就是:
- skcipher_request //网络层构建的结构体
- cryptoskcipher // kernel中间层构建的结构体,如果是kernel层调用底层算法,那么就从构建cryptocipher结构体开始。
- skcipher_alg //算法实现层的结构体,描述着具体的算法实现,有实现厂商自己添加。
上述复杂的结构体流程,进一步抽象,就变成如下这个样子:
既然如此,那么我们还可以举一反三一下: