内核加密机制
- linux 3.3.8
总体框架
仅显示关键结构

内核加密机制在内核中保存两个全局链表crypto_template_list和crypto_alg_list
crypto_template_list 保存所有的加密方式
- e.g cbc ecb
crypto_alg_list 保存所有的加密算法
- e.g md5 sha128 aes
crypto_template_list由各个算法通过crypto_register_template函数添加到链表中
crypto_alg_list由各个算法通过crypto_register_alg函数添加到链表中
数据结构说明
crypto_alg结构可以理解为真正保存加密接口的一个通用结构
struct list_head cra_users;
指向crypto_spawn结构所在的链表
union cra_u;
union { struct ablkcipher_alg ablkcipher; struct aead_alg aead; struct blkcipher_alg blkcipher; struct cipher_alg cipher; struct compress_alg compress; struct rng_alg rng; } cra_u;保存实际算法实现的函数接口和算法相关信息
- blkcipher_alg
struct blkcipher_alg { int (* setkey) (struct crypto_tfm *tfm, const u8 *key,unsigned int keylen); int (* encrypt) (struct blkcipher_desc *desc,struct scatterlist *dst, struct scatterlist *src,unsigned int nbytes); int (* decrypt) (struct blkcipher_desc *desc,struct scatterlist *dst, struct scatterlist *src,unsigned int nbytes); const char * geniv; unsigned int min_keysize; unsigned int max_keysize; unsigned int ivsize; };int (* setkey)
将产生的密钥及其相关信息保存在crypto_tfm结构的__crt_ctx[]部分。
同它也负责检查密钥长度的合法性,以防在
cra_init函数调用时,使用密钥长度与实际设置长度不符。int (* encrypt)
加密存放在scatterlist里面的数据,需要对齐scatterlist并且确保每一个加密块大小已经设置好
这个函数不应该去修改__crt_ctx[]部分数据
int (* decrypt)
环境与encrypt一致 过程与encrypt相反
union中结构初始化流程
- cipher
首先由算法本身实现xxxxx_alg结构体的初始化,通过
xxx_mod_init函数调用crypto_register_xxxxx函数将xxxxx_alg传递到crypto_alg结构体中通过
__crypto_register_alg函数将当前crypto_alg结构体添加到crypto_alg_list链表当中至此加密算法在内核中已成功注册
- ablkcipher/rng/aead/blkcipher/compress
首先由算法本身实现crypto_alg结构体的初始化,使用
crypto_register_alg函数调用__crypto_register_alg函数将当前crypto_alg结构体添加到crypto_alg_list链表当中,至此xxxxx_alg算法在内核中已成功注册
crypto_template结构是通用组合算法的模板
struct hlist_head instances;
该字段保存temp下所有的实例
struct crypto_instance *(*alloc)(struct rtattr **tb);
每个算法在该函数中保存自己的模板
crypto_instance结构就是加密方式的一个实例对象 通过函数XXXX_alloc_instance
struct crypto_alg alg;
该算法实现的函数接口
struct crypto_template *tmpl;
算法实例对应的模板
void *__ctx[];
保存crypto_spawn结构
crypto_spawn结构保存加密算法和加密方式的所有信息,以便之后通过crypto_spawn_tfm生成crypto_tfm的对象
struct crypto_alg *alg;
保存的加密算法的接口
struct crypto_instance *inst;
保存的加密方式的接口
Ps.以上结构体在内存中一直存在
crypto_tfm结构是内核中真正组合算法的实例化对象,真正的操作对象
union crt_u;
union { struct ablkcipher_tfm ablkcipher; struct aead_tfm aead; struct blkcipher_tfm blkcipher; struct cipher_tfm cipher; struct hash_tfm hash; struct compress_tfm compress; struct rng_tfm rng; } crt_u;保存算法能够正常使用的最基本参数和函数接口
void *__crt_ctx[];
保存加密算法注册的结构体的相关内容
常用来保存加密算法密钥的相关信息
算法组合流程
仅涉及密钥加解密过程时,不需要算法的组合
crypto_xxxx_alloc
| run kthread(cryptomgr_probe)
+---->crypto_get_attr_alg-------------------------------> cryptomgr_probe[get crypto_alg]
|
+---->crypto_alloc_instance----> crypto_init_spawn[combine crypto_instance and crypto_alg]
函数中数据结构的传递
e.g xxxx = shash
xxxxxx_desc
|
+--->crypto_xxxxx
|
+---->crypto_tfm
|
+---> xxxx_tfm
|
+---> crypto_alg
|
+----> xxxx_alg
Ecryptfs中的使用
加密算法
确定算法
使用crypto_alloc_hash函数设置使用的算法
crypto_alloc_hash(ECRYPTFS_DEFAULT_HASH, 0, CRYPTO_ALG_ASYNC);
/* ECRYPTFS_DEFAULT_HASH 该字段设置算法 */
模块注册
init update final详细流程
以MD5为例介绍内核加密模块在内核中的注册过程
/* crypto/md5.c */
static struct shash_alg alg = {
.digestsize = MD5_DIGEST_SIZE,
.init = md5_init,
.update = md5_update,
.final = md5_final,
.export = md5_export,
.import = md5_import,
.descsize = sizeof(struct md5_state),
.statesize = sizeof(struct md5_state),
.base = {
.cra_name = "md5",
.cra_flags = CRYPTO_ALG_TYPE_SHASH,
.cra_blocksize = MD5_HMAC_BLOCK_SIZE,
.cra_module = THIS_MODULE,
}
};
首先由算法本身实现shash_alg结构体的初始化,通过md5_mod_init函数调用crypto_register_shash函数将shash_alg传递到crypto_alg结构体中
通过__crypto_register_alg函数将当前crypto_alg结构体添加到crypto_alg_list链表当中
至此加密算法在内核中已成功注册
相关结构体
- 函数调用关系
crypto_alloc_hash函数将crypto_alg与shash_alg连接起来

static struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type,
u32 mask)
{
struct crypto_alg *q, *alg = NULL;
int best = -2;
/* 遍历crypto_alg_list链表 查找符合条件的q并返回 */
list_for_each_entry(q, &crypto_alg_list, cra_list) {
int exact, fuzzy;
if (crypto_is_moribund(q))
continue;
if ((q->cra_flags ^ type) & mask)
continue;
if (crypto_is_larval(q) &&
!crypto_is_test_larval((struct crypto_larval *)q) &&
((struct crypto_larval *)q)->mask != mask)
continue;
exact = !strcmp(q->cra_driver_name, name);
fuzzy = !strcmp(q->cra_name, name);
if (!exact && !(fuzzy && q->cra_priority > best))
continue;
if (unlikely(!crypto_mod_get(q)))
continue;
best = q->cra_priority;
if (alg)
crypto_mod_put(alg);
alg = q;
if (exact)
break;
}
return alg;
}
static int crypto_init_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
{
const struct crypto_type *type_obj = tfm->__crt_alg->cra_type;
if (type_obj)
return type_obj->init(tfm, type, mask);/* 此步骤调用shash_compat_init函数 */
switch (crypto_tfm_alg_type(tfm)) {
case CRYPTO_ALG_TYPE_CIPHER:
return crypto_init_cipher_ops(tfm);
case CRYPTO_ALG_TYPE_COMPRESS:
return crypto_init_compress_ops(tfm);
default:
break;
}
BUG();
return -EINVAL;
}
- 结构体传递

至此找到MD5所对应的shash_alg结构体
加密方式
确定算法
通过ecryptfs_crypto_api_algify_cipher_name函数设置加密方式
ecryptfs_crypto_api_algify_cipher_name(&full_alg_name, crypt_stat->cipher, "cbc");
/* crypt_stat->cipher为加密算法 cbc为加密模式 */
模块注册
以cbc(aes)为例介绍在内核模块中的注册流程
static struct crypto_template crypto_cbc_tmpl = {
.name = "cbc",
.alloc = crypto_cbc_alloc,
.free = crypto_cbc_free,
.module = THIS_MODULE,
};
首先在结构体中初始化相关字段保存在crypto_template结构体中,通过crypto_cbc_module_init函数调用crypto_register_template函数将crypto_template结构体插入crypto_template_list链表中以完成注册
相关结构体
- 函数调用关系

将crypto_alg与blkcipher_alg对应起来
ecb
在
ecryptfs_process_key_cipher函数中初始化为ecb模式
本文介绍了Linux内核3.3.8中的加密机制,包括总体框架、数据结构和算法流程。内核加密机制涉及两个全局链表:crypto_template_list和crypto_alg_list,分别用于保存加密方式和加密算法。加密算法的注册过程涉及到crypto_alg和crypto_template结构体,以及crypto_spawn结构。以Ecryptfs为例,展示了加密算法的使用,包括确定算法、模块注册和相关结构体的细节。
3427

被折叠的 条评论
为什么被折叠?



