linux的密码管理
在linux内核中,密码相关的头文件在 include crypto下,相关概念大致有加密 块加密 异步块加密 哈希 分组加密模式等等。
加密算法
算法:
AEAD算法:一种带有认证功能的加密方式。拆分为认证和加密两部分。常见的有GCM和CCM,
对称加密算法: 使用同一个密钥进行加密和解密。这意味着加密方和解密方必须事先共享同一个密钥,并且保证这个密钥的安全。
AES:AES-128 AES-256等,后个字段对应密钥长度。密钥越长,安全性能越高,加密时间越长。
DES,3DES等。
非对称加密算法: 使用一对密钥,一个公开密钥(公钥)用于加密,一个私有密钥(私钥)用于解密。公钥可以公开分享,而私钥必须保持私密。
模式:
实现不同的算法有几种模式:
主要有ECB CBC CFB OFB 和 CTR等这几种。
不同模式的区分如下:
ECB模式: ECB是最简单的块密码加密模式,加密前根据加密块大小(如AES为128位)分成若干块,之后将每块使用相同的密钥单独加密,解密同理。
CBC模式: CBC模式对于每个待加密的密码块在加密前会先与前一个密码块的密文异或然后再用加密器加密。第一个明文块与一个叫初始化向量的数据块异或。
CFB模式: 与ECB和CBC模式只能够加密块数据不同,CFB能够将块密文(Block Cipher)转换为流密文(Stream Cipher)。
OFB模式: OFB是先用块加密器生成密钥流(Keystream),然后再将密钥流与明文流异或得到密文流,解密是先用块加密器生成密钥流,再将密钥流与密文流异或得到明文,由于异或操作的对称性所以加密和解密的流程是完全一样的。
CTR模式: CTR模式是一种通过将逐次累加的计数器进行加密生成密钥流的流密码。
加密算法在内核中的形式
以aes加密算法为例。
所有的加密算法名都是xxx_alg的方式。关键成员有算法名 驱动名 算法类型 同步,异步,分组大小,上下文。加解密函数等等。
在alg结构中,块加密和普通分组加密的区别就是.cra的设置。普通分组加密指定的是cipher.同步块加密指定的是blkcipher. 异步块加密指定的是ablkcipher。
ctx:上下文。指的是算法执行过程中所要贯穿始终的数据结构。由每个算法自己定义。set_key encrypt decrypt这几个函数都可以从参数获得算法上下文的指针。算法上下文所占的内存空间由密码管理器来分配。注册alg的时候指定ctx大小和对其即可。ctx对齐对于一些硬件加密等。ctx的首地址可能需要在内存中4字节或者16字节对齐。
Device Mapper
device mapper是linux 2.6内核中支持的逻辑卷管理的通用设备映射机制。为实现用于才能出资源管理的块设备驱动提供了一个高度模块化的内核架构。
在内核中它通过一个一个模块化的target driver实现对IO请求的过滤或者重定向。包括软raid,软加密,多路径,镜像,快照等等。device mapper用户空间相关部分主要负责配置具体的策略和控制逻辑。比如逻辑设备和哪些物理设备映射。怎么建立这些映射关系等等。而具体的过滤和重定向IO请求的工作由内核相关代码完成。整个device mapper机制由两部分组成 内核空间的device mapper驱动,用户空间的device mapper库以及他提供的dmsetup工具。
内核部分
device mapper的内核相关代码在driver/md目录中。device mapper在内核中作为一个块设备驱动被注册的,包含三个重要的对象概念,mapped device,映射表,target device。
mapped device是一个逻辑抽象,是内核向外提供的逻辑设备。通过映射表描述的映射关系和target device建立映射。从mapped device 到一个 target device的映射表由一个多元组表示,该多元组由表示mappdevice逻辑的起始地址,范围,和表示在target device所在的物理设备的地址偏移量以及target类型等变量组成。以磁盘扇区为单位,512字节大小。
target device表示的是mapped device所映射的物理空间段。device mapper中这三个对象和target driver一起构成了可迭代的设备树 。
用户空间部分
Device mapper在用户空间包括device mapper库和dmsetup工具,device mapper库就是对ioctl 用户空间创建删除devicemapper逻辑设备所需必要操作的封装。dmsetup工具是一个应用层直接操作device mapper设备的命令行工具。大致包含,发现每个mapper device相关的target device,根据配置信息创建映射表,将用户空间构建好的映射表传入内核,让内核构建mapper device对应的dm table结构。
LUKS介绍
LUKS (linux unified key setup),linux统一密钥设置。是一种高性能安全的磁盘加密方法。基于cryptsetup。使用dm-crypt作为磁盘加密后端。
定义了如何安全存储加密密钥和加密元数据。支持多重密码。最多8个key slot。不需要重加密就能够更换密码。配合dm-crypt使用。实际加密使用的是内核支持的加密算法,LUKS只负责配置,封装和密钥管理。
LUKS结构
任何文件系统都可以加密,包括交换分区,加密卷的开头有一个未加密的头部。允许存储多达8个lusk1或者32个lusk2加密密钥,以及诸如密码类型和密钥大小之类的加密参数。
dm crypt
dm crypt,内核提供的磁盘加密功能。即device mapper crypto。lucks通过dmcrypt模块使用内核设备映射器子系统。负责处理设备的加密和解密。
cryptsetup
命令行的前端,通过它来操作 dm crypt。创建和访问加密设备。
linux加密框架
分成User Space layer 和 kernel Space layer。
kernel space.
在kernel space密码学算法上。主要分成软件以及硬件运算。
软件运算。主要由CPU进行密码学算法运算,不需要额外硬件,但很费CPU性能。linux kernel 原始码位于crypto subsystem下。
硬件加速。由硬件辅助进行密码学运算,不需要耗费cpu性能,但需要额外硬件。
SoC Component–许多ARM SoC厂商都会将硬件加解密元件放入SoC中,Linux Kernel原始码多位于drivers/crypto底下.且设计必须遵照Linux crypto framework,不能私下修改。
Crypto API User space interface
主要的功能是提供界面。让user space可存取kernel space.目前主流为cryptodev以及af_alg
crypt dev
不在linux kernel中自带。开源模块。需要单独移植,并挂载kernel module。
ioctl
openssl支持cryptodev。通过操作cryptdev节点来操作加密
af_alg
netlink
openssl从1.1开始支持af_alg。
User Space密码学库
常见的有openssl,wolfssl。
openssl提供af alg以及cryptdev的engine,可以透过engine来存取crypto api。
PART ONE Crypyo Subsystem of Kernel
介绍由应用层所发出的crypto(cryptography)request,透过system call将request传送到Linux kernel端,并经由crypto subsystem将request转发给硬件算法引擎(hardware crypto engine)的流程。
概述
Crypto subsystem是Linux系统中负责处理crypto request的子系统,除了包含流程控制机制之外,另一个重要特色就是提供算法实作的抽象层,让各家厂商能够依据需求去客制化实作方式。
其中一个常见例子就是厂商在硬件构架中加入用以加速特定算法运算效率的硬件算法引擎,并且透过crypto subsystem将驱动硬件算法引擎的流程整合进Linux系统中,供其他kernel module或是应用层使用。
cryptodev engine
在Linux系统中,想要实现应用层与硬件装置的沟通,第一个想到的就是透过character/block device driver,让应用程序开启表示此硬件装置的抽象层,并且藉由读写行为与硬件装置进行互动。
而Cryptodev-linux就是负责此角色,它提供中间层的服务,接收由应用层传送过来的crypto request,再呼叫Linux kernel crypto Subsystem的crypto API将request转发给特定的硬件算法引擎。
Cryptodev-linux为misc device类型的kernel module,预设路径是/dev/crypto,使用ioctl file operation cryptodev_ioctl来接受应用端所传递过来的数据。
应用端则是使用cryptdev.h定义好的struct crypt_op或是struct crypt_auth_op来组成指定crypto request,并呼叫ioctl system call将request送给Cryptodev-linux。
simple of cryptdev linux ioctl
另外,Cryptodev-linux也提供session机制,每个crypto request对应到一个session,而session管理当前crypto request的状态。
例如,目前session在initialized的状态,则表示此crypto request可执行encrypt,透过此方式来确保crypto request会在正确的流程下运作。
linux kernel crypto subsystem
首先 crypto subsystem有两个重要元素,transformation object(tfm),被称作cipher handle,transformation implementation,是transformation object底层的实作内容,又被称为crypto algo。就是crypto engine算法实作。
之所以要区分成object和implementation,最主要的原因是有可能多个object会使用同一个implementation。
举例来说,A和B使用者都要使用hmac-sha256算法,因此会新建立A和B两个transformation object并包含A和B各自拥有的key值,但这两个object有可能会使用同一个transformation implementation来呼叫同一个crypto engine进行算法运算。
当有crypto request进来,会先根据request中指定的算法名称,从已注册的crypto algorithm list中取出适合的crypto algorithm,并新建立transformation object。
之后,transformation object会再被组成crypto subsystem所用的cipher request。cipher request有可能共享同一个transformation object,举例来说,hmac-sha256的transformation object包含了transformation implementation和一个key值,而这个transformation object可以使用在多个cipher request的messsage上进行hash算法。当cipher request完成相关设值之后,接着实际调用transformation object的transformation implementation执行算法运算。
此时会出现一个问题,就是当短时间有多个request进来时,我们该如何依序地处理request?
这点crypto subsystem也设计了方便的struct crypto_engine,crypto engine提供了queue管理机制,让多个request能够顺序地转发给对应的crypto engine。
要新增transformation implementation到crypto subsystem,最重要的就是注册transformation implementation到crypto algorithm list中。
使用crypto_register_skciphers即可完成注册。
另外,cra_priority代表各算法的优先程度,优先级高的会先被采用。
asynchronous & synchronous
在crypto subsystem中,crypto API分成asynchronous(异步)和synchronous(同步)两种机制。
最早版本的crypto API其实只有synchronous crypto API,但随着要处理的数据量增加,运算和数据传输时间也可能大幅拉长,此时synchronous crypto API有可能让处理流程陷入较长时间的等待,因此后来引入了asynchronous crypto API,供使用者依据自己的使用场景来选择适合的机制。
而asynchronous与synchronous crypto API在命名设计上有所区别,asynchronous会在前缀多加一个a字,反之synchronous则是s字,以hash为例:
synchronous api
只要顺序的呼叫对应流程的API,并且针对返回的结果进行error handling即可。
在API的呼叫流程中,crypto_shash_update可以被多次呼叫,让使用者放入多组需要进行加密的message。当完成一组message后,可能有些中间状态是需要被保存起来的。这些状态就会存在state handler中。在使用者呼叫api前,会需要自己分配一块足够大小的内存,让crypto engine能够存放这些状态。在transformation implementation中会设定好crypto engine需所需的状态存储空间大小,使用者只需要呼叫特定API即可。
除了命名之外,由于两种机制的处理流程不同,因此所需的参数也会有所不同。
async request
包含一个callback function crypto completion,当运算完成后,会透过此callback来通知使用者继续处理完成的流程。由于asynchronous非同步机制,因此crypto engine在处理request时,行为和流程也和synchronous同步机制有蛮大的差异,其中常见的实作方式加入request queue来管理多个request,当使用者呼叫update API发送request时,则会将request加入到queue中,并直接回传处理中(-EINPROGRESS)的状态信息。
如果使用者使用asynchronous hash API,但是实际上对应的transformation implementation却是synchronous型态,crypto subsystem会主动进行相关的数据转换,因此也是可以正常运作的。
一般常见的方式是 crypto queue搭配worker,额外开一个kernel thread来与crypto engine进行沟通,让crypto request按照FIFO的顺序处理。
建立一个全局的crypto request list,将进来的request依序排到list中,建立一个worker(kernel thread)和对应的work queue来与hardware crypto engine进行沟通,worker的任务除了从crypto request list中取出request处理h之后,也可能会包含crypto engine的初始化和资源释放等工作。注册interrupt handler,当status interrupt举起时,呼叫user自定义的completion callback function来完成最后的流程。
crypto/engine.h中有提供接口可以直接调用。