一、? ? ? ? 前言
Linux加密框架是內(nèi)核安全子系統(tǒng)的重要組成部份,同時(shí),它又一個(gè)的獨(dú)立子系統(tǒng)形式出現(xiàn),從它出現(xiàn)在內(nèi)核根目錄下的crypto/就可以看出其地位了。
Crypto實(shí)現(xiàn)較為復(fù)雜,其主要體現(xiàn)在其OOP的設(shè)計(jì)思路和高度的對(duì)像抽像與封裝模型,作者展現(xiàn)了其出色的架構(gòu)設(shè)計(jì)水準(zhǔn)和面向?qū)ο竦某橄衲芰Α1疚牧D從加密框架的重要應(yīng)用,即IPSec(xfrm)的兩個(gè)重要協(xié)議AH和ESP對(duì)加密框架的使用,展現(xiàn)其設(shè)計(jì)與實(shí)現(xiàn)。
內(nèi)核版本:2.6.31.13
二、? ? ? ? 算法模版
1.? ? ? ? 模版的基本概念
算法模版是加密框架的第一個(gè)重要概念。內(nèi)核中有很多算法是動(dòng)態(tài)生成的,例如cbc(des)算法。內(nèi)核并不存在這樣的算法,它事實(shí)上是cbc和des的組合,但是內(nèi)核加密框架從統(tǒng)一抽像管理的角度。將cbc(des)看做一個(gè)算法,在實(shí)際使用時(shí)動(dòng)態(tài)分配并向內(nèi)核注冊(cè)該算法。這樣,可以將cbc抽像為一個(gè)模版,它可以同任意的加密算法進(jìn)行組合。算法模版使用結(jié)構(gòu)crypto_template來(lái)描述,其結(jié)構(gòu)原型:
點(diǎn)擊(此處)折疊或打開(kāi)
struct crypto_template?{
struct list_head list;?//模版鏈表成員,用于注冊(cè)
struct hlist_head instances;?//算法實(shí)例鏈表首部
struct module?*module;?//模塊指針
struct crypto_instance?*(*alloc)(struct rtattr?**tb);?//算法實(shí)例分配
void?(*free)(struct crypto_instance?*inst);?//算法實(shí)例釋放
char name[CRYPTO_MAX_ALG_NAME];?//模版名稱
};
例如,一個(gè)名為cbc的算法模版,可以用它來(lái)動(dòng)態(tài)分配cbc(des),cbc(twofish)……諸如此類。
crypto/algapi.c下包含了模版的一些常用操作。最為常見(jiàn)的就是模版的注冊(cè)與注銷,其實(shí)質(zhì)是對(duì)以crypto_template_list為首的鏈表的操作過(guò)程:
點(diǎn)擊(此處)折疊或打開(kāi)
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,看當(dāng)前模板是否被注冊(cè)
list_for_each_entry(q,?&crypto_template_list,?list)?{
if?(q?==?tmpl)
goto out;
}
//注冊(cè)之
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);
注銷算法模版,除了模版本身,還有一個(gè)重要的內(nèi)容是處理算法模版產(chǎn)生的算法實(shí)例,關(guān)于算法實(shí)例,后文詳述。
點(diǎn)擊(此處)折疊或打開(kāi)
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);
//首先移除模版上的所有算法實(shí)例
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);
//釋放模版的所有算法實(shí)例分配的內(nèi)存
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.? ? ? ? 算法模版的查找
點(diǎn)擊(此處)折疊或打開(kāi)
crypto_lookup_template函數(shù)根據(jù)名稱,查找相應(yīng)的模版:
struct crypto_template?*crypto_lookup_template(const?char?*name)
{
return try_then_request_module(__crypto_lookup_template(name),?name);
}
__crypto_lookup_template完成實(shí)質(zhì)的模版模找工作,而try_then_request_module則嘗試動(dòng)態(tài)插入相應(yīng)的內(nèi)核模塊,如果需要的話:
點(diǎn)擊(此處)折疊或打開(kāi)
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;
//查找命中,需要對(duì)其增加引用,以防止其正在使用時(shí),模塊被卸載。完成該操作后返回查找到的模版
if?(unlikely(!crypto_tmpl_get(q)))
continue;
tmpl?=?q;
break;
}
up_read(&crypto_alg_sem);
return tmpl;
}
3.? ? ? ? 模版的算法實(shí)例分配時(shí)機(jī)
模版可以看做一個(gè)靜態(tài)的概念,其只有被動(dòng)態(tài)創(chuàng)建后才具有生命力,本文將模版通過(guò)alloc分配創(chuàng)建的算法(對(duì)像)稱為“實(shí)例(instance)”。
算法模版的核心作用是,上層調(diào)用者構(gòu)造一個(gè)完整合法的算法名稱,如hmac(md5),觸發(fā)模版的alloc動(dòng)作,為該名稱分配一個(gè)算法實(shí)例,類似于為類實(shí)例化一個(gè)對(duì)像,最終的目的還是使用算法本身。對(duì)于xfrm來(lái)說(shuō),一個(gè)典型的算法模版的實(shí)例分配觸發(fā)流程如下所述:
xfrm包裹了一層加密框架支持,參后文“ xfrm加密框架”一節(jié),其算法查找函數(shù)為xfrm_find_algo,它調(diào)用crypto_has_alg函數(shù)進(jìn)行算法的查找,以驗(yàn)證自己支持的算法是否被內(nèi)核支持,如xfrm支持cbc(des),但此時(shí)并不知道內(nèi)核是否有這個(gè)算法(如果該算法首次被使用,則還沒(méi)有分配算法實(shí)例)。crypto_has_alg會(huì)調(diào)用crypto_alg_mod_lookup完成查找工作,crypto_alg_mod_lookup函數(shù)查找不命中,會(huì)調(diào)用crypto_probing_notify函數(shù)進(jìn)行請(qǐng)求探測(cè):
點(diǎn)擊(此處)折疊或打開(kāi)
struct crypto_alg?*crypto_alg_mod_lookup(const?char?*name,?u32 type,?u32 mask)
{
……
ok?=?crypto_probing_notify(CRYPTO_MSG_ALG_REQUEST,?larval);
……
}
請(qǐng)求是通過(guò)通知鏈表來(lái)通告的:
點(diǎn)擊(此處)折疊或打開(kāi)
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中注冊(cè)了一個(gè)名為cryptomgr_notifier的通告塊結(jié)構(gòu),其通告處理函數(shù)為cryptomgr_notify
點(diǎn)擊(此處)折疊或打開(kāi)
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);
}
這樣,當(dāng)有算法被使用的時(shí)候,會(huì)調(diào)用通告塊的處理函數(shù)cryptomgr_notify,因?yàn)榇藭r(shí)的消息是CRYPTO_MSG_ALG_REQUEST,所以cryptomgr_schedule_probe進(jìn)行算法的探測(cè):
點(diǎn)擊(此處)折疊或打開(kāi)
static?int?cryptomgr_notify(struct notifier_block?*this,?unsigned long msg,
void?*data)
{
switch?(msg)?{
case?CRYPTO_MSG_ALG_REQUEST:
return cryptomgr_schedule_probe(data);
……
return NOTIFY_DONE;
}
cryptomgr_schedule_probe啟動(dòng)一個(gè)名為cryptomgr_probe的內(nèi)核線程來(lái)進(jìn)行算法模版的探測(cè):
點(diǎn)擊(此處)折疊或打開(kāi)
static?int?cryptomgr_schedule_probe(struct crypto_larval?*larval)
{
……
//構(gòu)造param,以供后面使用
……
thread?=?kthread_run(cryptomgr_probe,?param,?"cryptomgr_probe");
……
}
cryptomgr_probe完成具體的算法探測(cè)過(guò)程:
點(diǎn)擊(此處)折疊或打開(kāi)
static?int?cryptomgr_probe(void?*data)
{
struct cryptomgr_param?*param?=?data;
struct crypto_template?*tmpl;
struct crypto_instance?*inst;
int?err;
//查找算法模版
tmpl?=?crypto_lookup_template(param->template);
if?(!tmpl)
goto?err;
//循環(huán)調(diào)用模版的alloc函數(shù)分配算法實(shí)列,并將模版注冊(cè)之
//這里值得注意的是循環(huán)的條件,當(dāng)返回碼為-EAGAIN時(shí),會(huì)循環(huán)再次嘗試
//這樣使用的一個(gè)場(chǎng)景后面會(huì)分析到
do?{
inst?=?tmpl->alloc(param->tb);
if?(IS_ERR(inst))
err?=?PTR_ERR(inst);
else?if?((err?=?crypto_register_instance(tmpl,?inst)))
tmpl->free(inst);
}?while?(err?==?-EAGAIN?&&?!signal_pending(current));
//查找中會(huì)增加引用,這里已經(jīng)用完了釋放之
crypto_tmpl_put(tmpl);
if?(err)
goto?err;
out:
kfree(param);
module_put_and_exit(0);
err:
crypto_larval_error(param->larval,?param->otype,?param->omask);
goto out;
}
理解了算法的注冊(cè)與查找后,再來(lái)理解這個(gè)函數(shù)就非常容易了,其核心在do{}while循環(huán)中,包含了算法實(shí)例的分配和注冊(cè)動(dòng)作。針對(duì)每一種算法模版,其alloc動(dòng)作不盡一致。后文會(huì)對(duì)xfrm使用的算法模版一一闡述。
為什么不把“算法實(shí)例”直接稱之為“算法”,這是因?yàn)閷?shí)例包含了更多的內(nèi)容,其由結(jié)構(gòu)struct crypto_instance可以看出:
點(diǎn)擊(此處)折疊或打開(kāi)
struct crypto_instance?{
struct crypto_alg alg;?//對(duì)應(yīng)的算法名稱
struct crypto_template?*tmpl;?//所屬的算法模版
struct hlist_node list;?//鏈表成員
void?*__ctx[]?CRYPTO_MINALIGN_ATTR;?//上下文信息指針
};
內(nèi)核使用struct crypto_alg描述一個(gè)算法(該結(jié)構(gòu)在后文使用時(shí)再來(lái)分析),可見(jiàn)一個(gè)算法實(shí)例除了包含其對(duì)應(yīng)的算法,還包含更多的內(nèi)容。
當(dāng)分配成功后,cryptomgr_probe會(huì)調(diào)用crypto_register_instance將其注冊(cè),以期將來(lái)可以順利地找到并使用它:
點(diǎn)擊(此處)折疊或打開(kāi)
int?crypto_register_instance(struct crypto_template?*tmpl,
struct crypto_instance?*inst)
{
struct crypto_larval?*larval;
int?err;
//對(duì)算法進(jìn)行合法性檢查,并構(gòu)造完整的驅(qū)動(dòng)名稱
err?=?crypto_check_alg(&inst->alg);
if?(err)
goto?err;
//設(shè)置算法內(nèi)核模塊指針指向所屬模版
inst->alg.cra_module?=?tmpl->module;
down_write(&crypto_alg_sem);
//注冊(cè)算法實(shí)例對(duì)應(yīng)的算法
larval?=?__crypto_register_alg(&inst->alg);
if?(IS_ERR(larval))
goto unlock;
//成功后,將算法再注冊(cè)到所屬的模版上面
hlist_add_head(&inst->list,?&tmpl->instances);
//設(shè)置模版指針
inst->tmpl?=?tmpl;
unlock:
up_write(&crypto_alg_sem);
err?=?PTR_ERR(larval);
if?(IS_ERR(larval))
goto?err;
crypto_wait_for_test(larval);
err?=?0;
err:
return?err;
}
注冊(cè)的一個(gè)重要工作,就是調(diào)用__crypto_register_alg將實(shí)例所對(duì)應(yīng)的算法注冊(cè)到加密框架子系統(tǒng)中。算法注冊(cè)成功后,上層調(diào)用者就可以調(diào)用crypto_alg_mod_lookup等函數(shù)進(jìn)行查找,并使用該算法了。
三、? ? ? ? HMAC
MAC(消息認(rèn)證碼)與hash函數(shù)非常相似,只是生成固定長(zhǎng)度的消息摘要時(shí)需要秘密的密鑰而已。
HAMC是密鑰相關(guān)的哈希運(yùn)算消息認(rèn)證碼(keyed-Hash Message Authentication Code),HMAC運(yùn)算利用哈希算法,以一個(gè)密鑰和一個(gè)消息為輸入,生成一個(gè)消息摘要作為輸出。具體的算法描述詳見(jiàn):http://baike.baidu.com/view/1136366.htm?fr=ala0_1。
根據(jù)HMAC的特點(diǎn)(可以和類似md5、sha等hash算法組合,構(gòu)造出hmac(md5)這樣的算法),Linux 加密框架將其抽像為一個(gè)算法模版。本章將假設(shè)上層調(diào)用者使用了名為hmac(md5)的算法,展示這一算法是如何被構(gòu)造、初始化及調(diào)用以實(shí)現(xiàn)數(shù)據(jù)驗(yàn)證的。
1.? ? ? ? 算法模版的注冊(cè)與注銷
點(diǎn)擊(此處)折疊或打開(kāi)
static struct crypto_template hmac_tmpl?=?{
.name?=?"hmac",
.alloc?=?hmac_alloc,
.free?=?hmac_free,
.module?=?THIS_MODULE,
};
點(diǎn)擊(此處)折疊或打開(kāi)
static?int?__init hmac_module_init(void)
{
return crypto_register_template(&hmac_tmpl);
}
點(diǎn)擊(此處)折疊或打開(kāi)
static void __exit hmac_module_exit(void)
{
crypto_unregister_template(&hmac_tmpl);
}
模版的注冊(cè)與注銷前文已經(jīng)描述過(guò)了。
2.? ? ? ? 算法實(shí)例的分配
當(dāng)一個(gè)算法需要被使用卻查找不到的時(shí)候,會(huì)嘗試調(diào)用其模版對(duì)應(yīng)分配相應(yīng)的算法實(shí)列,這也適用于hmac,其alloc函數(shù)指針指向hmac_alloc:
點(diǎn)擊(此處)折疊或打開(kāi)
static struct crypto_instance?*?hmac_alloc?(struct rtattr?**tb)
{
struct crypto_instance?*inst;
struct crypto_alg?*alg;
int?err;
int?ds;
//類型檢查,所屬算法必需為hash類型
err?=?crypto_check_attr_type(tb,?CRYPTO_ALG_TYPE_HASH);
if?(err)
return ERR_PTR(err);
//根據(jù)參數(shù)名稱,查找相應(yīng)的子算法,如md5,shax等
alg?=?crypto_get_attr_alg(tb,?CRYPTO_ALG_TYPE_HASH,
CRYPTO_ALG_TYPE_HASH_MASK);
//查找失敗
if?(IS_ERR(alg))
return ERR_CAST(alg);
//初始化算法實(shí)例
inst?=?ERR_PTR(-EINVAL);
//計(jì)算算法實(shí)列的消息摘要大小(輸出大小)
ds?=?alg->cra_type?==?&crypto_hash_type??
alg->cra_hash.digestsize?:
alg->cra_type??
__crypto_shash_alg(alg)->digestsize?:
alg->cra_digest.dia_digestsize;
if?(ds?>?alg->cra_blocksize)
goto out_put_alg;
//分配一個(gè)算法實(shí)列,這樣,一個(gè)新的算法,如hmac(md5)就橫空出世了
inst?=?crypto_alloc_instance("hmac",?alg);
//分配失敗
if?(IS_ERR(inst))
goto out_put_alg;
//初始化算法實(shí)例,其相應(yīng)的成員等于其子算法中的對(duì)應(yīng)成員
//類型
inst->alg.cra_flags?=?CRYPTO_ALG_TYPE_HASH;
//優(yōu)先級(jí)
inst->alg.cra_priority?=?alg->cra_priority;
//計(jì)算消息摘要的塊長(zhǎng)度(輸入大小)
inst->alg.cra_blocksize?=?alg->cra_blocksize;
//對(duì)齊掩碼
inst->alg.cra_alignmask?=?alg->cra_alignmask;
//類型指針指向crypto_hash_type
inst->alg.cra_type?=?&crypto_hash_type;
//消息摘要大小
inst->alg.cra_hash.digestsize?=?ds;
//計(jì)算算法所需的上下文空間大小
inst->alg.cra_ctxsize?=?sizeof(struct hmac_ctx)?+
ALIGN(inst->alg.cra_blocksize?*?2?+?ds,
sizeof(void?*));
//初始化和退出函數(shù)
inst->alg.cra_init?=?hmac_init_tfm;
inst->alg.cra_exit?=?hmac_exit_tfm;
//置相應(yīng)hash算法的操作函數(shù),包含hash函數(shù)標(biāo)準(zhǔn)的init/update/final和digest/setkey
inst->alg.cra_hash.init?=?hmac_init;
inst->alg.cra_hash.update?=?hmac_update;
inst->alg.cra_hash.final?=?hmac_final;
//消息摘要函數(shù)
inst->alg.cra_hash.digest?=?hmac_digest;
//setkey(密鑰設(shè)置函數(shù))
inst->alg.cra_hash.setkey?=?hmac_setkey;
out_put_alg:
crypto_mod_put(alg);
return inst;
}
每個(gè)模版的alloc動(dòng)作雖不同,但是它們基本上遵循一些共性的操作:
1、? ? ? ? 合法性檢驗(yàn),如類型檢查;
2、? ? ? ? 取得其子算法(即被模版所包裹的算法,如hmac(md5)中,就是md5)的算法指針;?
3、? ? ? ? 調(diào)用crypto_alloc_instance分配一個(gè)相應(yīng)的算法實(shí)列;
4、? ? ? ? 對(duì)分配成功的算法實(shí)例進(jìn)行實(shí)始化,這也是理解該算法實(shí)例最核心的部份,因?yàn)樗跏蓟惴ㄟ\(yùn)行所需的一些必要參數(shù)和虛函數(shù)指針;
crypto_alloc_instance(algapi.c) 函數(shù)用于分配一個(gè)算法實(shí)例,這個(gè)函數(shù)有兩個(gè)重要功能,一個(gè)是分配內(nèi)存空間,另一個(gè)是初始化spawn。
點(diǎn)擊(此處)折疊或打開(kāi)
//name:?模版名稱?
//alg:模版的子算法
struct crypto_instance?*crypto_alloc_instance(const?char?*name,
struct crypto_alg?*alg)
{
struct crypto_instance?*inst;
struct crypto_spawn?*spawn;
int?err;
//分配一個(gè)算法實(shí)例,crypto_instance結(jié)構(gòu)的最后一個(gè)成員ctx是一個(gè)指針變量,所以,在分配空間的時(shí)候,在其尾部追加相應(yīng)的空間,可以使用ctx訪問(wèn)之。
//另一個(gè)重要的概念是,算法實(shí)例中包含了算法,這個(gè)分配,同時(shí)也完成了算法實(shí)例對(duì)應(yīng)的算法的分配工作。
inst?=?kzalloc(sizeof(*inst)?+?sizeof(*spawn),?GFP_KERNEL);
if?(!inst)
return ERR_PTR(-ENOMEM);
err?=?-ENAMETOOLONG;
//構(gòu)造完成的算法名稱
if?(snprintf(inst->alg.cra_name,?CRYPTO_MAX_ALG_NAME,?"%s(%s)",?name,
alg->cra_name)?>=?CRYPTO_MAX_ALG_NAME)
goto err_free_inst;
//構(gòu)造完整的算法驅(qū)動(dòng)名稱
if?(snprintf(inst->alg.cra_driver_name,?CRYPTO_MAX_ALG_NAME,?"%s(%s)",
name,?alg->cra_driver_name)?>=?CRYPTO_MAX_ALG_NAME)
goto err_free_inst;
//spawn指向算法實(shí)例的上下文成員,可以這樣做是因?yàn)開(kāi)_ctx是一個(gè)可變長(zhǎng)的成員,在分配實(shí)例的時(shí)候,
//在尾部增加了一個(gè)spawn的空間
spawn?=?crypto_instance_ctx(inst);
//初始化spawn
err?=?crypto_init_spawn(spawn,?alg,?inst,
CRYPTO_ALG_TYPE_MASK?|?CRYPTO_ALG_ASYNC);
if?(err)
goto err_free_inst;
return inst;
err_free_inst:
kfree(inst);
return ERR_PTR(err);
}
crypto_instance_ctx取出算法實(shí)例的ctx指針,返回值是void *,這意味著可以根具不同的需要,將其轉(zhuǎn)換為所需的類型:
點(diǎn)擊(此處)折疊或打開(kāi)
static inline void?*crypto_instance_ctx(struct crypto_instance?*inst)
{
return inst->__ctx;
}
一個(gè)算法實(shí)例被分配成員后,其會(huì)被注冊(cè)至加密子系統(tǒng),這樣,一個(gè)算法,例如,hmac(md5)就可以直接被使用了。
3.? ? ? ? 待孵化的卵
? ? ? ? 已經(jīng)看到了從模版到算法實(shí)例的第一層抽像,每個(gè)算法在每一次被使用時(shí),它們的運(yùn)行環(huán)境不盡相同,例如,可能會(huì)擁有不同的密鑰。將算法看成一個(gè)類,則在每一次運(yùn)行調(diào)用時(shí),需要為它產(chǎn)生一個(gè)“對(duì)像”,這在內(nèi)核中被稱為transform,簡(jiǎn)稱為tfm。后文會(huì)詳細(xì)看到分配一個(gè)tfm的過(guò)程,現(xiàn)在引入這一概念,主要是為了分析spawn。
加密或認(rèn)證算法,在調(diào)用時(shí),都需要分配其算法對(duì)應(yīng)的tfm,在分配算法實(shí)例的同時(shí),并沒(méi)有為之分配相應(yīng)的tfm結(jié)構(gòu),這是因?yàn)檎嬲乃惴ㄟ€沒(méi)有被調(diào)用,這并不是進(jìn)行tfm結(jié)構(gòu)分配的最佳地點(diǎn)。在初始化算法實(shí)例的時(shí)候,加密框架使用了XXX_spawn_XXX函數(shù)簇來(lái)解決這一問(wèn)題。這樣的算法對(duì)像,被稱為spawn(卵)。也就是說(shuō),在算法實(shí)例分配的時(shí)候,只是下了一個(gè)蛋(設(shè)置好spawn),等到合適的時(shí)候來(lái)對(duì)其進(jìn)行孵化,這個(gè)“合適的時(shí)候”,通常指為調(diào)用算法實(shí)際使用的時(shí)候。
在crypto_alloc_instance分配算法實(shí)例的時(shí)候,就順便分配了spawn,然后調(diào)用crypto_init_spawn對(duì)其進(jìn)行初始化:
點(diǎn)擊(此處)折疊或打開(kāi)
int?crypto_init_spawn(struct crypto_spawn?*spawn,?struct crypto_alg?*alg,
struct crypto_instance?*inst,?u32 mask)
{
int?err?=?-EAGAIN;
//初始化其成員
spawn->inst?=?inst;
spawn->mask?=?mask;
down_write(&crypto_alg_sem);
if?(!crypto_is_moribund(alg))?{
//加入鏈表,每個(gè)spawn,都被加入到算法的cra_users鏈,即算做算法的一個(gè)用戶
list_add(&spawn->list,?&alg->cra_users);
//spawn的alg成員指針指向當(dāng)前成員,這就方便引用了
spawn->alg?=?alg;
err?=?0;
}
up_write(&crypto_alg_sem);
return?err;
}
所以,所謂算法的spawn的初始化,就是初始化crypto_spawn結(jié)構(gòu),核心的操作是設(shè)置其對(duì)應(yīng)的算法實(shí)例、算法,以及一個(gè)加入算法的鏈表的過(guò)程。
4.? ? ? ? 算法的初始化
有了算法實(shí)例,僅表示內(nèi)核擁有這一種“算法”——加引號(hào)的意思是說(shuō),它可能并不以類似md5.c這樣的源代碼形式存現(xiàn),而是通過(guò)模版動(dòng)態(tài)創(chuàng)建的。實(shí)際要使用該算法,需要為算法分配“運(yùn)行的對(duì)像”,即tfm。
4.1? ? ? ? tfm
內(nèi)核加密框架中,使用結(jié)構(gòu)crypto_alg來(lái)描述一個(gè)算法,每一個(gè)算法(實(shí)例)相當(dāng)于一個(gè)類,在實(shí)際的使用環(huán)境中,需要為它分配一個(gè)對(duì)像,在內(nèi)核加密框架中,這個(gè)“對(duì)像”被稱為transform(簡(jiǎn)稱tfm)。transform意味“變換”,可能譯為“蛻變”更為合適。作者對(duì)它的注釋是:
/*
* Transforms: user-instantiated objects which encapsulate algorithms
* and core processing logic.??Managed via crypto_alloc_*() and
* crypto_free_*(), as well as the various helpers below.
……
*/
tfm是加密框架中一個(gè)極為重要的概念,它由結(jié)構(gòu)crypto_tfm描述:
點(diǎn)擊(此處)折疊或打開(kāi)
struct crypto_tfm?{
u32 crt_flags;
union?{
struct ablkcipher_tfm ablkcipher;
struct aead_tfm aead;
struct blkcipher_tfm blkcipher;
struct cipher_tfm cipher;
struct hash_tfm hash;
struct ahash_tfm ahash;
struct compress_tfm compress;
struct rng_tfm rng;
}?crt_u;
void?(*exit)(struct crypto_tfm?*tfm);
struct crypto_alg?*__crt_alg;
void?*__crt_ctx[]?CRYPTO_MINALIGN_ATTR;
};
這些成員的作用,將在后面一一看到,值得注意的是,針對(duì)每種算法不同,結(jié)構(gòu)定義了一個(gè)名為crt_u的聯(lián)合體,以對(duì)應(yīng)每種算法的tfm的具體操作,例如加密/解密,求hash,壓縮/解壓等,加密框架引入了一組名為xxx_tfm的結(jié)構(gòu)封裝,xxx表示算法類型,也就是crt_u成員。其定義如下:
點(diǎn)擊(此處)折疊或打開(kāi)
struct ablkcipher_tfm?{
int?(*setkey)(struct crypto_ablkcipher?*tfm,?const?u8?*key,
unsigned?int?keylen);
int?(*encrypt)(struct ablkcipher_request?*req);
int?(*decrypt)(struct ablkcipher_request?*req);
int?(*givencrypt)(struct skcipher_givcrypt_request?*req);
int?(*givdecrypt)(struct skcipher_givcrypt_request?*req);
struct crypto_ablkcipher?*base;
unsigned?int?ivsize;
unsigned?int?reqsize;
};
struct aead_tfm?{
int?(*setkey)(struct crypto_aead?*tfm,?const?u8?*key,
unsigned?int?keylen);
int?(*encrypt)(struct aead_request?*req);
int?(*decrypt)(struct aead_request?*req);
int?(*givencrypt)(struct aead_givcrypt_request?*req);
int?(*givdecrypt)(struct aead_givcrypt_request?*req);
struct crypto_aead?*base;
unsigned?int?ivsize;
unsigned?int?authsize;
unsigned?int?reqsize;
};
struct blkcipher_tfm?{
void?*iv;
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);
};
struct cipher_tfm?{
int?(*cit_setkey)(struct crypto_tfm?*tfm,
const?u8?*key,?unsigned?int?keylen);
void?(*cit_encrypt_one)(struct crypto_tfm?*tfm,?u8?*dst,?const?u8?*src);
void?(*cit_decrypt_one)(struct crypto_tfm?*tfm,?u8?*dst,?const?u8?*src);
};
struct hash_tfm?{
int?(*init)(struct hash_desc?*desc);
int?(*update)(struct hash_desc?*desc,
struct scatterlist?*sg,?unsigned?int?nsg);
int?(*final)(struct hash_desc?*desc,?u8?*out);
int?(*digest)(struct hash_desc?*desc,?struct scatterlist?*sg,
unsigned?int?nsg,?u8?*out);
int?(*setkey)(struct crypto_hash?*tfm,?const?u8?*key,
unsigned?int?keylen);
unsigned?int?digestsize;
};
struct ahash_tfm?{
int?(*init)(struct ahash_request?*req);
int?(*update)(struct ahash_request?*req);
int?(*final)(struct ahash_request?*req);
int?(*digest)(struct ahash_request?*req);
int?(*setkey)(struct crypto_ahash?*tfm,?const?u8?*key,
unsigned?int?keylen);
unsigned?int?digestsize;
unsigned?int?reqsize;
};
struct compress_tfm?{
int?(*cot_compress)(struct crypto_tfm?*tfm,
const?u8?*src,?unsigned?int?slen,
u8?*dst,?unsigned?int?*dlen);
int?(*cot_decompress)(struct crypto_tfm?*tfm,
const?u8?*src,?unsigned?int?slen,
u8?*dst,?unsigned?int?*dlen);
};
struct rng_tfm?{
int?(*rng_gen_random)(struct crypto_rng?*tfm,?u8?*rdata,
unsigned?int?dlen);
int?(*rng_reset)(struct crypto_rng?*tfm,?u8?*seed,?unsigned?int?slen);
};
為了直接訪問(wèn)這些成員,定義了如下宏:
點(diǎn)擊(此處)折疊或打開(kāi)
#define crt_ablkcipher crt_u.ablkcipher
#define crt_aead crt_u.aead
#define crt_blkcipher crt_u.blkcipher
#define crt_cipher crt_u.cipher
#define crt_hash crt_u.hash
#define crt_ahash crt_u.ahash
#define crt_compress crt_u.compress
#define crt_rng crt_u.rng
這樣,要訪問(wèn)hash算法的hash成員,就可以直接使用crt_hash,而不是crt_u.hash。
每種算法訪問(wèn)tfm都使用了二次封裝,例如:
點(diǎn)擊(此處)折疊或打開(kāi)
struct crypto_ablkcipher?{
struct crypto_tfm base;
};
struct crypto_aead?{
struct crypto_tfm base;
};
struct crypto_blkcipher?{
struct crypto_tfm base;
};
struct crypto_cipher?{
struct crypto_tfm base;
};
struct crypto_comp?{
struct crypto_tfm base;
};
struct crypto_hash?{
struct crypto_tfm base;
};
struct crypto_rng?{
struct crypto_tfm base;
};
其base成員就是相應(yīng)算法的tfm。因?yàn)樗鼈儞碛邢鄳?yīng)的起始地址,可以很方便地強(qiáng)制類型轉(zhuǎn)換來(lái)操作,內(nèi)核為此專門定義了一組函數(shù),以hash為例,完成這一工作的是crypto_hash_cast:
點(diǎn)擊(此處)折疊或打開(kāi)
static inline struct crypto_hash?*__crypto_hash_cast(struct crypto_tfm?*tfm)
{
return?(struct crypto_hash?*)tfm;
}
static inline struct crypto_hash?*crypto_hash_cast(struct crypto_tfm?*tfm)
{
BUG_ON((crypto_tfm_alg_type(tfm)?^ CRYPTO_ALG_TYPE_HASH)?&
CRYPTO_ALG_TYPE_HASH_MASK);
return __crypto_hash_cast(tfm);
}
當(dāng)然,針對(duì)各種不同的算法,還有許多不同的XXX_cast函數(shù)。這些cast函數(shù),將tfm強(qiáng)制轉(zhuǎn)換為其所屬的算法類型的封裝結(jié)構(gòu)。
4.2 tfm的分配
對(duì)于算法的實(shí)始化,其核心功能就是分配一個(gè)tfm,并設(shè)置其上下文環(huán)境,例如密鑰等參數(shù),然后初始化上述struct xxx_tfm結(jié)構(gòu)。對(duì)于hash類的算法來(lái)講,分配tfm是由crypto_alloc_hash(crypt.h) 這個(gè)API來(lái)完成的,以AH為例,在其初始化過(guò)程中有:
點(diǎn)擊(此處)折疊或打開(kāi)
static?int?ah_init_state(struct xfrm_state?*x)
{
struct crypto_hash?*tfm;
……
tfm?=?crypto_alloc_hash(x->aalg->alg_name,?0,?CRYPTO_ALG_ASYNC);
if?(IS_ERR(tfm))
goto?error;
……
}
AH調(diào)用crypto_alloc_hash為SA中指定的算法(如hmac(md5))分配一個(gè)tfm,第二個(gè)參數(shù)為0,第三個(gè)參數(shù)指明了AH使用異步模式。
點(diǎn)擊(此處)折疊或打開(kāi)
static inline struct crypto_hash?*crypto_alloc_hash(const?char?*alg_name,
u32 type,?u32 mask)
{
//初始化相應(yīng)的類型的掩碼
type?&=?~CRYPTO_ALG_TYPE_MASK;?//清除類型的CRYPTO_ALG_TYPE_MASK位
mask?&=?~CRYPTO_ALG_TYPE_MASK;?//清除掩碼的CRYPTO_ALG_TYPE_MASK位
type?|=?CRYPTO_ALG_TYPE_HASH;?//置類型CRYPTO_ALG_TYPE_HASH位
mask?|=?CRYPTO_ALG_TYPE_HASH_MASK;?//置掩碼CRYPTO_ALG_TYPE_HASH_MASK位
//最終的分配函數(shù)是crypto_alloc_base,它分配一個(gè)base(每個(gè)算法的tfm),再將其強(qiáng)制類型轉(zhuǎn)換為所需要結(jié)構(gòu)類型
return __crypto_hash_cast(crypto_alloc_base(alg_name,?type,?mask));
}
crypto_alloc_base首先檢查相應(yīng)的算法是否存在,對(duì)于hmac(md5)這個(gè)例子,xfrm在SA的增加中,會(huì)觸發(fā)相應(yīng)的算法查找,最終會(huì)調(diào)用hmac模版的alloc分配算法實(shí)例(當(dāng)然也包括算法本身),然后向內(nèi)核注冊(cè)算法及算法實(shí)例,所以,查找會(huì)命中。接下來(lái)的工作,是調(diào)用tfm的核心分配函數(shù)__crypto_alloc_tfm進(jìn)行分配,其實(shí)現(xiàn)如下:
點(diǎn)擊(此處)折疊或打開(kāi)
struct crypto_tfm?*crypto_alloc_base(const?char?*alg_name,?u32 type,?u32 mask)
{
struct crypto_tfm?*tfm;
int?err;
for?(;;)?{
struct crypto_alg?*alg;
//根據(jù)算法名稱,查找相應(yīng)的算法,它會(huì)首先嘗試已經(jīng)加載的算法,如果失敗,也會(huì)嘗試
//動(dòng)態(tài)插入內(nèi)核模塊
alg?=?crypto_alg_mod_lookup(alg_name,?type,?mask);
//查找失敗,返回退出循環(huán)
if?(IS_ERR(alg))?{
err?=?PTR_ERR(alg);
goto?err;
}
//查找成功,為算法分配tfm
tfm?=?__crypto_alloc_tfm(alg,?type,?mask);
//分配成功,返回之
if?(!IS_ERR(tfm))
return tfm;
//釋放引用計(jì)算,因?yàn)椴檎視?huì)增加引用
crypto_mod_put(alg);
//獲取返回錯(cuò)誤值,根據(jù)其值,決定是否要繼續(xù)嘗試
err?=?PTR_ERR(tfm);
err:
if?(err?!=?-EAGAIN)
break;
if?(signal_pending(current))?{
err?=?-EINTR;
break;
}
}
return ERR_PTR(err);
}
__crypto_alloc_tfm是內(nèi)核加密框架中又一重要的函數(shù),它完成了對(duì)算法tfm的分配和初始化的工作:
點(diǎn)擊(此處)折疊或打開(kāi)
struct crypto_tfm?*__crypto_alloc_tfm(struct crypto_alg?*alg,?u32 type,
u32 mask)
{
struct crypto_tfm?*tfm?=?NULL;
unsigned?int?tfm_size;
int?err?=?-ENOMEM;
//計(jì)算tfm所需的空間大小,它包括了tfm結(jié)構(gòu)本身和算法上下文大小
tfm_size?=?sizeof(*tfm)?+?crypto_ctxsize(alg,?type,?mask);
//分配tfm
tfm?=?kzalloc(tfm_size,?GFP_KERNEL);
if?(tfm?==?NULL)
goto out_err;
//__crt_alg成員指向其所屬的算法,對(duì)于hmac而言,它就是hmac(xxx),例如hmac(md5)
tfm->__crt_alg?=?alg;
//初始化tfm選項(xiàng)
err?=?crypto_init_ops(tfm,?type,?mask);
if?(err)
goto out_free_tfm;
//調(diào)用算法的初始化函數(shù),初始化tfm,這有個(gè)先決條件是tfm本身沒(méi)有exit函數(shù)的實(shí)現(xiàn)
if?(!tfm->exit?&&?alg->cra_init?&&?(err?=?alg->cra_init(tfm)))
goto cra_init_failed;
goto out;
cra_init_failed:
crypto_exit_ops(tfm);
out_free_tfm:
if?(err?==?-EAGAIN)
crypto_shoot_alg(alg);
kfree(tfm);
out_err:
tfm?=?ERR_PTR(err);
out:
return tfm;
}
crypto_init_ops負(fù)責(zé)初始化tfm的選項(xiàng),對(duì)于一個(gè)真正的算法(例如md5、dst)和一個(gè)偽算法(我說(shuō)的“偽”,是指由模版動(dòng)態(tài)分配的,如hmac(xxx), authenc(xxx,xxx)),因?yàn)椴⒉淮嬖谶@樣的算法,只是內(nèi)核的一個(gè)抽像,故稱為"偽",它們的初始化過(guò)程是截然不同的。一個(gè)偽算法,它都設(shè)置了其所屬的類型cra_type,例如,對(duì)于hmac(xxx)而言,它指向了crypto_hash_type。這樣,初始化時(shí),實(shí)質(zhì)上調(diào)用的是其所屬類型的init函數(shù):
點(diǎn)擊(此處)折疊或打開(kāi)
static?int?crypto_init_ops(struct crypto_tfm?*tfm,?u32 type,?u32 mask)
{
//獲取tfm所屬算法的所屬類型
const?struct crypto_type?*type_obj?=?tfm->__crt_alg->cra_type;
//如果設(shè)置了類型,調(diào)用類型的init
if?(type_obj)
return type_obj->init(tfm,?type,?mask);
//否則,判斷算法的類型,調(diào)用相應(yīng)的初始化函數(shù),這些在不同的算法實(shí)現(xiàn)中分析
switch?(crypto_tfm_alg_type(tfm))?{
case?CRYPTO_ALG_TYPE_CIPHER:
return crypto_init_cipher_ops(tfm);
case?CRYPTO_ALG_TYPE_DIGEST:
if?((mask?&?CRYPTO_ALG_TYPE_HASH_MASK)?!=
CRYPTO_ALG_TYPE_HASH_MASK)
return crypto_init_digest_ops_async(tfm);
else
return crypto_init_digest_ops(tfm);
case?CRYPTO_ALG_TYPE_COMPRESS:
return crypto_init_compress_ops(tfm);
default:
break;
}
BUG();
return?-EINVAL;
}
算法類型的概念很好理解,因?yàn)槿舾蓚€(gè)hmac(xxx)都擁有一此相同的類型屬性(其它偽算法同樣如此),所以可以將它們抽像管理。
對(duì)于hash類型的算法而言,它們擁有一個(gè)共同的類型crypto_hash_type,其定義在hash.c中:
點(diǎn)擊(此處)折疊或打開(kāi)
const?struct crypto_type crypto_hash_type?=?{
.ctxsize?=?crypto_hash_ctxsize,
.init?=?crypto_init_hash_ops,
#ifdef CONFIG_PROC_FS
.show?=?crypto_hash_show,
#endif
};
它的init函數(shù)指針指向crypto_init_hash_ops:
點(diǎn)擊(此處)折疊或打開(kāi)
static?int?crypto_init_hash_ops(struct crypto_tfm?*tfm,?u32 type,?u32 mask)
{
struct hash_alg?*alg?=?&tfm->__crt_alg->cra_hash;
//其消息摘要大小不同超過(guò)1/8個(gè)頁(yè)面
if?(alg->digestsize?>?PAGE_SIZE?/?8)
return?-EINVAL;
//根據(jù)掩碼位,判斷是同步初始化還是異步,對(duì)于crypto_alloc_hash調(diào)用下來(lái)的而言,它
//設(shè)置了CRYPTO_ALG_TYPE_HASH_MASK位,所以是同步初始化
if?((mask?&?CRYPTO_ALG_TYPE_HASH_MASK)?!=?CRYPTO_ALG_TYPE_HASH_MASK)
return crypto_init_hash_ops_async?(tfm);
else
return crypto_init_hash_ops_sync(tfm);
}
在我們AH的例子中,AH使用了異步模式,所以crypto_init_hash_ops_async會(huì)被調(diào)用。
前述hash_tfm結(jié)構(gòu)封裝了hash類型的算法的通用的操作:
點(diǎn)擊(此處)折疊或打開(kāi)
struct hash_tfm?{
int?(*init)(struct hash_desc?*desc);
int?(*update)(struct hash_desc?*desc,
struct scatterlist?*sg,?unsigned?int?nsg);
int?(*final)(struct hash_desc?*desc,?u8?*out);
int?(*digest)(struct hash_desc?*desc,?struct scatterlist?*sg,
unsigned?int?nsg,?u8?*out);
int?(*setkey)(struct crypto_hash?*tfm,?const?u8?*key,
unsigned?int?keylen);
unsigned?int?digestsize;
};
先來(lái)看同步模式的初始化操作,crypto_init_hash_ops_sync函數(shù)負(fù)責(zé)初始化這一結(jié)構(gòu):
點(diǎn)擊(此處)折疊或打開(kāi)
static?int?crypto_init_hash_ops_sync(struct crypto_tfm?*tfm)
{
struct hash_tfm?*crt?=?&tfm->crt_hash;
struct hash_alg?*alg?=?&tfm->__crt_alg->cra_hash;
//置tfm相應(yīng)操作為算法本身的對(duì)應(yīng)操作,
//對(duì)于hmac(xxx)算法而言,這些東東在hmac_alloc中已經(jīng)初始化過(guò)了,也就是hmac_init等函數(shù)
crt->init?=?alg->init;
crt->update?=?alg->update;
crt->final?=?alg->final;
crt->digest?=?alg->digest;
crt->setkey?=?hash_setkey;
crt->digestsize?=?alg->digestsize;
return 0;
}
異步模式則稍有不同,它使用了hash類型算法的通用函數(shù):
點(diǎn)擊(此處)折疊或打開(kāi)
static?int?crypto_init_hash_ops_async(struct crypto_tfm?*tfm)
{
struct ahash_tfm?*crt?=?&tfm->crt_ahash;
struct hash_alg?*alg?=?&tfm->__crt_alg->cra_hash;
crt->init?=?hash_async_init;
crt->update?=?hash_async_update;
crt->final?=?hash_async_final;
crt->digest?=?hash_async_digest;
crt->setkey?=?hash_async_setkey;
crt->digestsize?=?alg->digestsize;
return 0;
}
不論是同步還是異步,算法的tfm都得到的相應(yīng)的初始化。回到__crypto_alloc_tfm中來(lái),__crypto_alloc_tfm函數(shù)的最后一步是調(diào)用算法的cra_init函數(shù)(如果它存在的話),對(duì)于hmac(xxx)而言,它在分配的時(shí)候指向hmac_init_tfm。hmac_init_tfm的主要工作就是對(duì)hmac(xxx)的spawn進(jìn)行孵化操作。還記得“待孵化的卵”嗎?前面講了只是初始化它,現(xiàn)在到了孵化的時(shí)候了
點(diǎn)擊(此處)折疊或打開(kāi)
static?int?hmac_init_tfm(struct crypto_tfm?*tfm)
{
struct crypto_hash?*hash;
//因?yàn)樗惴▽?shí)例的第一個(gè)成員就是alg,在注冊(cè)算法時(shí),就是注冊(cè)的它,所以可以很方便地通過(guò)tfm的__crt_alg強(qiáng)制類型轉(zhuǎn)換得到對(duì)應(yīng)的算法實(shí)例
struct crypto_instance?*inst?=?(void?*)tfm->__crt_alg;
//取得算法實(shí)例的__ctx域,也就是spawn
struct crypto_spawn?*spawn?=?crypto_instance_ctx(inst);
//取得tfm的上下文指針
struct hmac_ctx?*ctx?=?hmac_ctx(__crypto_hash_cast(tfm));
//對(duì)hmac(xxx)進(jìn)行孵化,以hmac(md5)為例,這將得到一個(gè)md5算法的tfm,當(dāng)然,通過(guò)強(qiáng)制類型轉(zhuǎn)換,它被封裝在結(jié)構(gòu)crypto_hash中
hash?=?crypto_spawn_hash(spawn);
if?(IS_ERR(hash))
return PTR_ERR(hash);
//設(shè)置子算法指向孵化的tfm
ctx->child?=?hash;
return 0;
}
crypto_spawn_hash展示了如何對(duì)hash算法簇進(jìn)行spawn的孵化操作:
點(diǎn)擊(此處)折疊或打開(kāi)
static inline struct crypto_hash?*crypto_spawn_hash(struct crypto_spawn?*spawn)
{
//初始化孵化所需的類型和掩碼
u32 type?=?CRYPTO_ALG_TYPE_HASH;
u32 mask?=?CRYPTO_ALG_TYPE_HASH_MASK;
//調(diào)用crypto_spawn_tfm孵化一個(gè)tfm,并強(qiáng)制類型轉(zhuǎn)換
return __crypto_hash_cast(crypto_spawn_tfm(spawn,?type,?mask));
}
最后的任務(wù)交給了crypto_spawn_tfm函數(shù),它為算法孵化一個(gè)tfm,因?yàn)閟pawn的alg成員指向了所要孵化的算法,使得這一操作很容易實(shí)現(xiàn)
點(diǎn)擊(此處)折疊或打開(kāi)
struct crypto_tfm?*crypto_spawn_tfm(struct crypto_spawn?*spawn,?u32 type,
u32 mask)
{
struct crypto_alg?*alg;
struct crypto_alg?*alg2;
struct crypto_tfm?*tfm;
down_read(&crypto_alg_sem);
//要孵化的spawn所屬的算法
alg?=?spawn->alg;
alg2?=?alg;
//查找算法所屬模塊
if?(alg2)
alg2?=?crypto_mod_get(alg2);
up_read(&crypto_alg_sem);
//如果其所屬模塊沒(méi)了,則標(biāo)注算法為DYING,出錯(cuò)退回
if?(!alg2)?{
if?(alg)
crypto_shoot_alg(alg);
return ERR_PTR(-EAGAIN);
}
//初始化tfm
tfm?=?ERR_PTR(-EINVAL);
//驗(yàn)證掩碼標(biāo)志位
if?(unlikely((alg->cra_flags ^ type)?&?mask))
goto out_put_alg;
//為算法分配相應(yīng)的tfm,這樣,一個(gè)算法的spawn就孵化完成了
tfm?=?__crypto_alloc_tfm(alg,?type,?mask);
if?(IS_ERR(tfm))
goto out_put_alg;
return tfm;
out_put_alg:
crypto_mod_put(alg);
return tfm;
}
又繞回了__crypto_alloc_tfm函數(shù),其實(shí)現(xiàn)之前已經(jīng)分析過(guò)了,對(duì)于一個(gè)普通的算法(非模版產(chǎn)生的算法,如md5),其初始化工作略有不同,在了解其初始化工作之前,需要對(duì)一個(gè)實(shí)際的算法作了解。
順例說(shuō)一句,內(nèi)核的這種抽像管理方式,功能異常地強(qiáng)大,可以想像,它可以抽像更多層的嵌套。所以hmac(xxx)中,xxx不一定就是一個(gè)md5之類,可能還是一層形如xxx(xxx)的抽像,理論上,它可以像變形金剛一樣。
4.3 小結(jié)一下
本節(jié)分析了一個(gè)算法的tfm是如何生成的,因?yàn)樗惴梢允嵌鄬拥慕M裝,在生成上層算法的同時(shí),它也要為其所包含的算法分配tfm,這一過(guò)程稱之為spawn。
?
評(píng)論
查看更多