Linux 加密框架设计与实现
目录
Linux 加密框架设计与实现 .................................................................................................. 1
一、 前言 ....................................................................................................................... 3
二、 算法模版 ................................................................................................................ 3
1. 模版的基本概念 ........................................................................................................ 3
2. 算法模版的查找 ........................................................................................................ 5
3. 模版的算法实例分配时机 ......................................................................................... 6
三、
HMAC ................................................................................................................... 10
1. 算法模版的注册与注销 ....................................................................................... 10
2. 算法实例的分配 .................................................................................................. 11
3. 待孵化的卵 .......................................................................................................... 14
4. 算法的初始化 ...................................................................................................... 15
5. MD5 的 tfm 分配 .................................................................................................. 27
6. 密钥设置 .............................................................................................................. 37
7. 数据验证 .............................................................................................................. 40
8. MD5 的实现 ......................................................................................................... 52
9. 小结 ..................................................................................................................... 59
四、
authenc ................................................................................................................ 59
1. 注册算法模版 ...................................................................................................... 59
2. 算法实列的分配 .................................................................................................. 60
3.
cbc 算法模版 ....................................................................................................... 63
4. authenc 的 spawn................................................................................................. 65
5.
crypto_lookup_skcipher........................................................................................ 66
6. 分配 tfm ............................................................................................................... 75
7.
8.
spawn 的孵化 ...................................................................................................... 83
crypto_aead_setauthsize ...................................................................................... 93
9. 密钥设置 crypto_aead_setkey ............................................................................ 94
10. 解密 ................................................................................................................ 100
11. 加密 ................................................................................................................ 114
五、 硬件加密支持 .................................................................................................... 121
1. 设备及算法初始化 ............................................................................................ 121
2.
tfm 初始化 ......................................................................................................... 124
3. 设置密钥 ............................................................................................................ 126
4. 加密 ................................................................................................................... 127
5. 解密 ................................................................................................................... 130
后记 .................................................................................................................................. 131
作者:独孤九贱
版权所有,转载请注明作者及出处
一、 前言
Linux 加密框架是内核安全子系统的重要组成部份,同时,它又一个的独立子系统形式
出现,从它出现在内核根目录下的 crypto/就可以看出其地位了。
Crypto 实现较为复杂,其主要体现在其 OOP 的设计思路和高度的对像抽像与封装模型,
作者展现了其出色的架构设计水准和面向对像的抽像能力。本文力图从 xfrm 的两个重要协
议 AH 和 ESP 对加密框架的使用,展现其设计与实现。
内核版本:2.6.31.13
二、 算法模版
1. 模版的基本概念
算法模版是加密框架的第一个重要概念。内核中有很多算法是动态生成的,例如 cbc(des)
算法。内核并不存在这样的算法,它事实上是 cbc 和 des 的组合,但是内核加密框架从统一
抽像管理的角度。将 cbc(des)看做一个算法,在实际使用时动态分配并向内核注册该算法。
这样,可以将 cbc 抽像为一个模版,它可以同任意的加密算法进行组合。算法模版使用结构
crypto_template 来描述,其结构原型:
//模版链表成员,用于注册
//算法实例链表首部
//模块指针
struct crypto_instance *(*alloc)(struct rtattr **tb);
void (*free)(struct crypto_instance *inst);
struct crypto_template {
struct list_head list;
struct hlist_head instances;
struct module *module;
};
例如,一个名为 cbc 的算法模版,可以用它来动态分配 cbc(des),cbc(twofish)……诸如此
类。
crypto/algapi.c 下包含了模版的一些常用操作。最为常见的就是模版的注册与注销,其实质
char name[CRYPTO_MAX_ALG_NAME];
//模版名称
//算法实例分配
//算法实例释放
down_write(&crypto_alg_sem);
if (q == tmpl)
goto out;
struct crypto_template *q;
int err = -EEXIST;
//遍历 crypto_template_list,看当前模板是否被注册
list_for_each_entry(q, &crypto_template_list, list) {
}
是对以 crypto_template_list 为首的链表的操作过程:
static LIST_HEAD(crypto_template_list);
int crypto_register_template(struct crypto_template *tmpl)
{
out:
}
EXPORT_SYMBOL_GPL(crypto_register_template);
//注册之
list_add(&tmpl->list, &crypto_template_list);
//事件通告
crypto_notify(CRYPTO_MSG_TMPL_REGISTER, tmpl);
err = 0;
up_write(&crypto_alg_sem);
return err;
注销算法模版,除了模版本身,还有一个重要的内容是处理算法模版产生的算法实例,
struct crypto_instance *inst;
struct hlist_node *p, *n;
struct hlist_head *list;
LIST_HEAD(users);
关于算法实例,后文详述。
void crypto_unregister_template(struct crypto_template *tmpl)
{
BUG_ON(list_empty(&tmpl->list));
//注销算法模版,并重新初始化模版的 list 成员
list_del_init(&tmpl->list);
//首先移除模版上的所有算法实例
down_write(&crypto_alg_sem);
crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl);
int err = crypto_remove_alg(&inst->alg, &users);
BUG_ON(err);
list = &tmpl->instances;
hlist_for_each_entry(inst, p, list, list) {
}
}
EXPORT_SYMBOL_GPL(crypto_unregister_template);
up_write(&crypto_alg_sem);
//释放模版的所有算法实例分配的内存
hlist_for_each_entry_safe(inst, p, n, list, list) {
}
crypto_remove_final(&users);
BUG_ON(atomic_read(&inst->alg.cra_refcnt) != 1);
tmpl->free(inst);
2. 算法模版的查找
return try_then_request_module(__crypto_lookup_template(name), name);
crypto_lookup_template 函数根据名称,查找相应的模版:
struct crypto_template *crypto_lookup_template(const char *name)
{
}
__crypto_lookup_template 完成实质的模版模找工作,而 try_then_request_module 则尝试动
态插入相应的内核模块,如果需要的话:
static struct crypto_template *__crypto_lookup_template(const char *name)
{
后返回查找到的模版
down_read(&crypto_alg_sem);
//遍历 crypto_template_list 链,匹备模版名称
list_for_each_entry(q, &crypto_template_list, list) {
if (strcmp(q->name, name))
//查找命中,需要对其增加引用,以防止其正在使用时,模块被卸载。完成该操作
struct crypto_template *q, *tmpl = NULL;
if (unlikely(!crypto_tmpl_get(q)))
continue;
continue;
tmpl = q;
break;
}
up_read(&crypto_alg_sem);
return tmpl;
}
3. 模版的算法实例分配时机
模版可以看做一个静态的概念,其只有被动态创建后才具有生命力,本文将模版通过
alloc 分配创建的算法(对像)称为“实例(instance)”。
……
ok = crypto_probing_notify(CRYPTO_MSG_ALG_REQUEST, larval);
……
算法模版的核心作用是,上层调用者构造一个完整合法的算法名称,如 hmac(md5),触
发模版的 alloc 动作,为该名称分配一个算法实例,类似于为类实例化一个对像,最终的目
的还是使用算法本身。对于 xfrm 来说,一个典型的算法模版的实例分配触发流程如下所述:
xfrm 包裹了一层加密框架支持,参后文“ xfrm 加密框架”一节,其算法查找函数为
xfrm_find_algo,它调用 crypto_has_alg 函数进行算法的查找,以验证自己支持的算法是否被
内核支持,如 xfrm 支持 cbc(des),但此时并不知道内核是否有这个算法(如果该算法首次被
使用,则还没有分配算法实例)。crypto_has_alg 会调用 crypto_alg_mod_lookup 完成查找工
作,crypto_alg_mod_lookup 函数查找不命中,会调用 crypto_probing_notify 函数进行请求探
测:
struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
{
}
请求是通过通知链表来通告的:
int crypto_probing_notify(unsigned long val, void *v)
{
ok = blocking_notifier_call_chain(&crypto_chain, val, v);
if (ok == NOTIFY_DONE) {
}
int ok;
return ok;
request_module("cryptomgr");
ok = blocking_notifier_call_chain(&crypto_chain, val, v);
.notifier_call = cryptomgr_notify,
return crypto_register_notifier(&cryptomgr_notifier);
}
在 algboss.c 中注册了一个名为 cryptomgr_notifier 的通告块结 构,其通告处理函数为
cryptomgr_notify:
static struct notifier_block cryptomgr_notifier = {
};
static int __init cryptomgr_init(void)
{
}
static void __exit cryptomgr_exit(void)
{
}
这样,当有算法被使用的时候,会调用通告块的处理函数 cryptomgr_notify,因为此时的消
息是 CRYPTO_MSG_ALG_REQUEST,所以 cryptomgr_schedule_probe 进行算法的探测:
static int cryptomgr_notify(struct notifier_block *this, unsigned long msg,
{
int err = crypto_unregister_notifier(&cryptomgr_notifier);
BUG_ON(err);
switch (msg) {
case CRYPTO_MSG_ALG_REQUEST:
……
void *data)
return cryptomgr_schedule_probe(data);
return NOTIFY_DONE;
}
cryptomgr_schedule_probe 启动一个名为 cryptomgr_probe 的内核线程来进行算法模版的探
测:
static int cryptomgr_schedule_probe(struct crypto_larval *larval)
{
}
……
//构造 param,以供后面使用
……
thread = kthread_run(cryptomgr_probe, param, "cryptomgr_probe");
……
goto err;
inst = tmpl->alloc(param->tb);
if (IS_ERR(inst))
else if ((err = crypto_register_instance(tmpl, inst)))
err = PTR_ERR(inst);
tmpl->free(inst);
struct cryptomgr_param *param = data;
struct crypto_template *tmpl;
struct crypto_instance *inst;
int err;
//查找算法模版
tmpl = crypto_lookup_template(param->template);
if (!tmpl)
//循环调用模版的 alloc 函数分配算法实列,并将模版注册之
//这里值得注意的是循环的条件,当返回码为-EAGAIN 时,会循环再次尝试
//这样使用的一个场景后面会分析到
do {
} while (err == -EAGAIN && !signal_pending(current));
cryptomgr_probe 完成具体的算法探测过程:
static int cryptomgr_probe(void *data)
{
out:
err:
}
理解了算法的注册与查找后,再来理解这个函数就非常容易了,其核心在 do{}while 循环中,
包含了算法实例的分配和注册动作。针对每一种算法模版,其 alloc 动作不尽一致。后文会
对 xfrm 使用的算法模版一一阐述。
crypto_larval_error(param->larval, param->otype, param->omask);
goto out;
//查找中会增加引用,这里已经用完了释放之
crypto_tmpl_put(tmpl);
if (err)
goto err;
kfree(param);
module_put_and_exit(0);
为什么不把“算法实例”直接称之为“算法”,这是因为实例包含了更多的内容,其由