Linux Crypto(7):skcipher以及cbc(aes)组合算法
skcipher 是一种算法类型,为对称密钥加密。它使用相同的密钥(或一组关联的密钥)对数据进行加密和解密。skcipher API 设计用于处理任意长度的数据流(可能不是块大小的整数倍),通常通过链接模式(如 CBC, CTR, XTS, CFB, OFB)来实现。这与处理固定大小块的 cipher 类型不同。
1 skcipher说明
层级: skcipher 的概念和 API 主要在核心框架层定义 (crypto/skcipher.c, include/crypto/skcipher.h)。
使用: 用户空间(通过 AF_ALG)和内核其他子系统(如 IPsec, DM-Crypt, FScrypt)通过核心框架提供的 skcipher API (crypto_alloc_skcipher, crypto_skcipher_encrypt/decrypt) 发起请求。
实现: 具体的 skcipher 算法(如 cbc(aes), xts(serpent), ecb(arc4))在算法实现层提供(软件模块如 cbc.c, aes_generic.c;硬件驱动如 aesni-intel.ko)。
抽象硬件和软件实现: 核心框架通过 skcipher API 向使用者隐藏了底层算法是软件实现还是硬件加速的细节。使用者只需关心接口。
管理算法实例和请求: 提供分配算法实例 (crypto_alloc_skcipher)、设置密钥 (crypto_skcipher_setkey)、创建和提交加密/解密请求 (skcipher_request_alloc, crypto_skcipher_encrypt/decrypt) 的机制。
支持异步操作: API 设计为异步的,允许加密操作在后台执行(可能在软中断或工作队列中,或由硬件异步完成),操作完成后通过回调函数通知调用者。这对高性能场景(如网络数据包处理)至关重要。
2 skcipher数据结构
struct crypto_cipher通过 crypto_alloc_skcipher() 创建,表示带密钥的实例 。
struct crypto_skcipher; -- 不透明结构体,表示对称密钥加密实例的句柄。包含算法实现、密钥、上下文等状态信息。
struct skcipher_alg描述对称密钥加密算法的实现,需通过 crypto_register_skcipher() 注册到内核
struct skcipher_alg { int (*setkey)(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen); -- 设置密钥的回调函数 int (*encrypt)(struct skcipher_request *req); -- 执行加密操作的回调 int (*decrypt)(struct skcipher_request *req); -- 执行解密操作的回调 int (*init)(struct crypto_skcipher *tfm); -- 初始化算法实例 void (*exit)(struct crypto_skcipher *tfm); -- 清理算法实例 unsigned int ivsize; -- 初始化向量(IV)大小 unsigned int chunksize; -- 块处理粒度 unsigned int walksize; -- 分块处理时的步进大小 struct crypto_alg base; -- 嵌入的基础算法结构 };
struct skcipher_request封装单次加密/解密操作的请求,包含所有运行时参数。
struct skcipher_request { struct scatterlist *src; -- 输入数据的分散/聚集列表 struct scatterlist *dst; -- 输出数据的分散/聚集列表 unsigned int cryptlen; -- 待处理数据长度 void *iv; -- 初始化向量指针 void *__ctx[] CRYPTO_MINALIGN_ATTR; -- 底层实现的私有上下文存储区 };
3 skcipher API
struct crypto_skcipher *crypto_alloc_skcipher(const char *alg_name, u32 type, u32 mask); -- 分配算法实例。alg_name: 算法名(如"cbc(aes)"), type: 算法类型(CRYPTO_ALG_TYPE_SKCIPHER), mask: 位掩码 void crypto_free_skcipher(struct crypto_skcipher *tfm); -- 释放算法实例。tfm: 由 crypto_alloc_skcipher() 分配的实例 int crypto_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen); -- 设置密钥。tfm: 算法实例, key: 密钥指针, keylen: 密钥长度(字节)。返回0成功,负数错误码 int crypto_skcipher_encrypt(struct skcipher_request *req); -- 提交异步加密请求。req: 预配置的请求对象。返回0/-EINPROGRESS表示已提交,负数错误码 int crypto_skcipher_decrypt(struct skcipher_request *req); -- 提交异步解密请求。参数和返回同encrypt struct skcipher_request *skcipher_request_alloc(struct crypto_skcipher *tfm, gfp_t gfp); -- 分配请求对象。tfm: 关联的算法实例, gfp: 内存分配标志 void skcipher_request_free(struct skcipher_request *req); -- 释放请求对象。req: 由skcipher_request_alloc分配的请求 void skcipher_request_set_callback(struct skcipher_request *req, u32 flags, crypto_completion_t compl, void *data); -- 设置异步回调。req: 请求对象, flags: 标志位(如CRYPTO_TFM_REQ_MAY_BACKLOG), compl: 完成回调函数, data: 回调参数 void skcipher_request_set_crypt(struct skcipher_request *req, struct scatterlist *src, struct scatterlist *dst, unsigned int cryptlen, void *iv); -- 配置加密参数。req: 请求对象, src: 输入分散列表, dst: 输出分散列表, cryptlen: 数据长度, iv: 初始化向量
4 skcipher cbc(aes)组合加解密算法
aes_init注册了一个通用aes算法到核心框架。
aes_init
->crypto_register_alg--注册aes_alg到核心框架层。
aes通用算法结构体实现如下:
static struct crypto_alg aes_alg = { .cra_name = "aes", .cra_driver_name = "aes-generic", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct crypto_aes_ctx), .cra_module = THIS_MODULE, .cra_u = { .cipher = { .cia_min_keysize = AES_MIN_KEY_SIZE,--最小秘钥长度。 .cia_max_keysize = AES_MAX_KEY_SIZE,--最大密钥长度。 .cia_setkey = crypto_aes_set_key,--设置秘钥。 .cia_encrypt = crypto_aes_encrypt,--加密操作。 .cia_decrypt = crypto_aes_decrypt--解密操作。 } } };
crypto_cbc_module_init注册一个crypto_cbc_tmpl模版:
- aes_alg实现原始的 AES 块加密(ECB 模式)。
-
crypto_cbc_tmpl(CBC 模式)包裹 aes_alg(AES 块加密),形成完整的 cbc(aes) 算法。
- cbc(aes)是组合算法,通过模板组合生成的完整 CBC-AES 算法。
crypto_cbc_module_init
->crypto_register_template--注册crypto_cbc_tmpl模版。
->crypto_cbc_create
->skcipher_alloc_instance_simple
->skcipher_ialg_simple
->初始化encrypt和decrypt函数。
->crypto_cbc_encrypt
->crypto_cbc_decrypt
->skcipher_register_instance