新闻资讯
Group news
青岛广盛源肥业有限公司    您的位置: 首页  >  新闻资讯  >  正文

了解并学习Linux加密框架设计与实现

2019年10月12日 文章来源:网络整理 热度:115℃ 作者:刘英

一、        前言

Linux加密框架是内核安全子系统的重要组成部份,同时,它又一个的独立子系统形式出现,从它出现在内核根目录下的crypto/就可以看出其地位了。
Crypto实现较为复杂,其主要体现在其OOP的设计思路和高度的对像抽像与封装模型,作者展现了其出色的架构设计水准和面向对像的抽像能力。本文力图从加密框架的重要应用,即IPSec(xfrm)的两个重要协议AH和ESP对加密框架的使用,展现其设计与实现。
内核版本:2.6.31.13

二、        算法模版
1.        模版的基本概念
算法模版是加密框架的第一个重要概念。内核中有很多算法是动态生成的,例如cbc(des)算法。内核并不存在这样的算法,它事实上是cbc和des的组合,但是内核加密框架从统一抽像管理的角度。将cbc(des)看做一个算法,在实际使用时动态分配并向内核注册该算法。这样,可以将cbc抽像为一个模版,它可以同任意的加密算法进行组合。算法模版使用结构crypto_template来描述,其结构原型:

点击(此处)折叠或打开

struct crypto_template {

struct list_head list; //模版链表成员,用于注册

struct hlist_head instances; //算法实例链表首部

struct module *module; //模块指针

struct crypto_instance *(*alloc)(struct rtattr **tb); //算法实例分配

void (*free)(struct crypto_instance *inst); //算法实例释放

char name[CRYPTO_MAX_ALG_NAME]; //模版名称

};

例如,一个名为cbc的算法模版,可以用它来动态分配cbc(des),cbc(twofish)……诸如此类。

crypto/algapi.c下包含了模版的一些常用操作。最为常见的就是模版的注册与注销,其实质是对以crypto_template_list为首的链表的操作过程:

点击(此处)折叠或打开

static LIST_HEAD(crypto_template_list);

int crypto_register_template(struct crypto_template *tmpl)

{

struct crypto_template *q;

int err = -EEXIST;

down_write(&crypto_alg_sem);

//遍历crypto_template_list,看当前模板是否被注册

list_for_each_entry(q, &crypto_template_list, list) {

if (q == tmpl)

goto out;

}

//注册之

list_add(&tmpl->list, &crypto_template_list);

//事件通告

crypto_noTIfy(CRYPTO_MSG_TMPL_REGISTER, tmpl);

err = 0;

out:

up_write(&crypto_alg_sem);

return err;

}

EXPORT_SYMBOL_GPL(crypto_register_template);

注销算法模版,除了模版本身,还有一个重要的内容是处理算法模版产生的算法实例,关于算法实例,后文详述。

点击(此处)折叠或打开

void crypto_unregister_template(struct crypto_template *tmpl)

{

struct crypto_instance *inst;

struct hlist_node *p, *n;

struct hlist_head *list;

LIST_HEAD(users);

down_write(&crypto_alg_sem);

BUG_ON(list_empty(&tmpl->list));

//注销算法模版,并重新初始化模版的list成员

list_del_init(&tmpl->list);

//首先移除模版上的所有算法实例

list = &tmpl->instances;

hlist_for_each_entry(inst, p, list, list) {

int err = crypto_remove_alg(&inst->alg, &users);

BUG_ON(err);

}

crypto_noTIfy(CRYPTO_MSG_TMPL_UNREGISTER, tmpl);

up_write(&crypto_alg_sem);

//释放模版的所有算法实例分配的内存

hlist_for_each_entry_safe(inst, p, n, list, list) {

BUG_ON(atomic_read(&inst->alg.cra_refcnt) != 1);

tmpl->free(inst);

}

crypto_remove_final(&users);

}

EXPORT_SYMBOL_GPL(crypto_unregister_template);

2.        算法模版的查找

点击(此处)折叠或打开

crypto_lookup_template函数根据名称,查找相应的模版:

struct crypto_template *crypto_lookup_template(const char *name)

{

return try_then_request_module(__crypto_lookup_template(name), name);

}

__crypto_lookup_template完成实质的模版模找工作,而try_then_request_module则尝试动态插入相应的内核模块,如果需要的话:

点击(此处)折叠或打开

staTIc struct crypto_template *__crypto_lookup_template(const char *name)

{

struct crypto_template *q, *tmpl = NULL;

down_read(&crypto_alg_sem);

//遍历crypto_template_list链,匹备模版名称

list_for_each_entry(q, &crypto_template_list, list) {

if (strcmp(q->name, name))

conTInue;

//查找命中,需要对其增加引用,以防止其正在使用时,模块被卸载。完成该操作后返回查找到的模版

if (unlikely(!crypto_tmpl_get(q)))

continue;

tmpl = q;

break;

}

up_read(&crypto_alg_sem);

return tmpl;

}

3.        模版的算法实例分配时机
模版可以看做一个静态的概念,其只有被动态创建后才具有生命力,本文将模版通过alloc分配创建的算法(对像)称为“实例(instance)”。
算法模版的核心作用是,上层调用者构造一个完整合法的算法名称,如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)

{

……

ok = crypto_probing_notify(CRYPTO_MSG_ALG_REQUEST, larval);

……

}

请求是通过通知链表来通告的:

点击(此处)折叠或打开

int crypto_probing_notify(unsigned long val, void *v)

{

int ok;

ok = blocking_notifier_call_chain(&crypto_chain, val, v);

if (ok == NOTIFY_DONE) {

request_module("cryptomgr");

ok = blocking_notifier_call_chain(&crypto_chain, val, v);

}

return ok;

}

在algboss.c中注册了一个名为cryptomgr_notifier的通告块结构,其通告处理函数为cryptomgr_notify

点击(此处)折叠或打开

static struct notifier_block cryptomgr_notifier = {

.notifier_call = cryptomgr_notify,

};

static int __init cryptomgr_init(void)

{

return crypto_register_notifier(&cryptomgr_notifier);

}

static void __exit cryptomgr_exit(void)

{

int err = crypto_unregister_notifier(&cryptomgr_notifier);

BUG_ON(err);

}

上一篇:linux 内核与用户空间通信之netlink使用方法


下一篇:Linux内核初始化过程中的调用顺序

友情链接
Links