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

上传人:白大夫 文档编号:3372010 上传时间:2019-08-19 格式:DOC 页数:29 大小:113KB
返回 下载 相关 举报
了解并学习Linux加密框架设计与实现.doc_第1页
第1页 / 共29页
亲,该文档总共29页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《了解并学习Linux加密框架设计与实现.doc》由会员分享,可在线阅读,更多相关《了解并学习Linux加密框架设计与实现.doc(29页珍藏版)》请在三一文库上搜索。

1、了解并学习Linux加密框架设计与实现一、 前言Linux加密框架是内核安全子系统的重要组成部份,同时,它又一个的独立子系统形式出现,从它出现在内核根目录下的crypto/就可以看出其地位了。Crypto实现较为复杂,其主要体现在其OOP的设计思路和高度的对像抽像与封装模型,作者展现了其出色的架构设计水准和面向对像的抽像能力。本文力图从加密框架的重要应用,即IPSec(xfrm)的两个重要协议AH和ESP对加密框架的使用,展现其设计与实现。内核版本:2.6.31.13二、 算法模版1. 模版的基本概念算法模版是加密框架的第一个重要概念。内核中有很多算法是动态生成的,例如cbc(des)算法。内

2、核并不存在这样的算法,它事实上是cbc和des的组合,但是内核加密框架从统一抽像管理的角度。将cbc(des)看做一个算法,在实际使用时动态分配并向内核注册该算法。这样,可以将cbc抽像为一个模版,它可以同任意的加密算法进行组合。算法模版使用结构crypto_template来描述,其结构原型:点击(此处)折叠或打开struct crypto_templatestruct list_head list;/模版链表成员,用于注册struct hlist_head instances;/算法实例链表首部struct module*module;/模块指针struct crypto_instance

3、*(*alloc)(struct rtattr*tb);/算法实例分配void(*free)(struct crypto_instance*inst);/算法实例释放char nameCRYPTO_MAX_ALG_NAME;/模版名称;例如,一个名为cbc的算法模版,可以用它来动态分配cbc(des),cbc(twofish)诸如此类。crypto/algapi.c下包含了模版的一些常用操作。最为常见的就是模版的注册与注销,其实质是对以crypto_template_list为首的链表的操作过程:点击(此处)折叠或打开static LIST_HEAD(crypto_template_list)

4、;intcrypto_register_template(struct crypto_template*tmpl)struct crypto_template*q;interr=-EEXIST;down_write(/遍历crypto_template_list,看当前模板是否被注册list_for_each_entry(q,if(q=tmpl)goto out;/注册之list_add(/事件通告crypto_noTIfy(CRYPTO_MSG_TMPL_REGISTER,tmpl);err=0;out:up_write(returnerr;EXPORT_SYMBOL_GPL(crypto_

5、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(BUG_ON(list_empty(/注销算法模版,并重新初始化模版的list成员list_del_init(/首先

6、移除模版上的所有算法实例list=hlist_for_each_entry(inst,p,list,list)interr=crypto_remove_alg(BUG_ON(err);crypto_noTIfy(CRYPTO_MSG_TMPL_UNREGISTER,tmpl);up_write(/释放模版的所有算法实例分配的内存hlist_for_each_entry_safe(inst,p,n,list,list)BUG_ON(atomic_read(tmpl-free(inst);crypto_remove_final(EXPORT_SYMBOL_GPL(crypto_unregister

7、_template);2. 算法模版的查找点击(此处)折叠或打开crypto_lookup_template函数根据名称,查找相应的模版:struct crypto_template*crypto_lookup_template(constchar*name)return try_then_request_module(_crypto_lookup_template(name),name);_crypto_lookup_template完成实质的模版模找工作,而try_then_request_module则尝试动态插入相应的内核模块,如果需要的话:点击(此处)折叠或打开staTIc stru

8、ct crypto_template*_crypto_lookup_template(constchar*name)struct crypto_template*q,*tmpl=NULL;down_read(/遍历crypto_template_list链,匹备模版名称list_for_each_entry(q,if(strcmp(q-name,name)conTInue;/查找命中,需要对其增加引用,以防止其正在使用时,模块被卸载。完成该操作后返回查找到的模版if(unlikely(!crypto_tmpl_get(q)continue;tmpl=q;break;up_read(return

9、 tmpl;3. 模版的算法实例分配时机模版可以看做一个静态的概念,其只有被动态创建后才具有生命力,本文将模版通过alloc分配创建的算法(对像)称为“实例(instance)”。算法模版的核心作用是,上层调用者构造一个完整合法的算法名称,如hmac(md5),触发模版的alloc动作,为该名称分配一个算法实例,类似于为类实例化一个对像,最终的目的还是使用算法本身。对于xfrm来说,一个典型的算法模版的实例分配触发流程如下所述:xfrm包裹了一层加密框架支持,参后文“ xfrm加密框架”一节,其算法查找函数为xfrm_find_algo,它调用crypto_has_alg函数进行算法的查找,以

10、验证自己支持的算法是否被内核支持,如xfrm支持cbc(des),但此时并不知道内核是否有这个算法(如果该算法首次被使用,则还没有分配算法实例)。crypto_has_alg会调用crypto_alg_mod_lookup完成查找工作,crypto_alg_mod_lookup函数查找不命中,会调用crypto_probing_notify函数进行请求探测:点击(此处)折叠或打开struct crypto_alg*crypto_alg_mod_lookup(constchar*name,u32 type,u32 mask)ok=crypto_probing_notify(CRYPTO_MSG_

11、ALG_REQUEST,larval);请求是通过通知链表来通告的:点击(此处)折叠或打开intcrypto_probing_notify(unsigned long val,void*v)intok;ok=blocking_notifier_call_chain(if(ok=NOTIFY_DONE)request_module(cryptomgr);ok=blocking_notifier_call_chain(return ok;在algboss.c中注册了一个名为cryptomgr_notifier的通告块结构,其通告处理函数为cryptomgr_notify点击(此处)折叠或打开sta

12、tic struct notifier_block cryptomgr_notifier=.notifier_call=cryptomgr_notify,;staticint_init cryptomgr_init(void)return crypto_register_notifier(static void _exit cryptomgr_exit(void)interr=crypto_unregister_notifier(BUG_ON(err);这样,当有算法被使用的时候,会调用通告块的处理函数cryptomgr_notify,因为此时的消息是CRYPTO_MSG_ALG_REQUES

13、T,所以cryptomgr_schedule_probe进行算法的探测:点击(此处)折叠或打开staticintcryptomgr_notify(struct notifier_block*this,unsigned long msg,void*data)switch(msg)caseCRYPTO_MSG_ALG_REQUEST:return cryptomgr_schedule_probe(data);return NOTIFY_DONE;cryptomgr_schedule_probe启动一个名为cryptomgr_probe的内核线程来进行算法模版的探测:点击(此处)折叠或打开stati

14、cintcryptomgr_schedule_probe(struct crypto_larval*larval)/构造param,以供后面使用thread=kthread_run(cryptomgr_probe,param,cryptomgr_probe);cryptomgr_probe完成具体的算法探测过程:点击(此处)折叠或打开staticintcryptomgr_probe(void*data)struct cryptomgr_param*param=data;struct crypto_template*tmpl;struct crypto_instance*inst;interr;

15、/查找算法模版tmpl=crypto_lookup_template(param-template);if(!tmpl)gotoerr;/循环调用模版的alloc函数分配算法实列,并将模版注册之/这里值得注意的是循环的条件,当返回码为-EAGAIN时,会循环再次尝试/这样使用的一个场景后面会分析到doinst=tmpl-alloc(param-tb);if(IS_ERR(inst)err=PTR_ERR(inst);elseif(err=crypto_register_instance(tmpl,inst)tmpl-free(inst);while(err=-EAGAIN/查找中会增加引用,这

16、里已经用完了释放之crypto_tmpl_put(tmpl);if(err)gotoerr;out:kfree(param);module_put_and_exit(0);err:crypto_larval_error(param-larval,param-otype,param-omask);goto out;理解了算法的注册与查找后,再来理解这个函数就非常容易了,其核心在dowhile循环中,包含了算法实例的分配和注册动作。针对每一种算法模版,其alloc动作不尽一致。后文会对xfrm使用的算法模版一一阐述。为什么不把“算法实例”直接称之为“算法”,这是因为实例包含了更多的内容,其由结构s

17、truct crypto_instance可以看出:点击(此处)折叠或打开struct crypto_instancestruct crypto_alg alg;/对应的算法名称struct crypto_template*tmpl;/所属的算法模版struct hlist_node list;/链表成员void*_ctxCRYPTO_MINALIGN_ATTR;/上下文信息指针;内核使用struct crypto_alg描述一个算法(该结构在后文使用时再来分析),可见一个算法实例除了包含其对应的算法,还包含更多的内容。当分配成功后,cryptomgr_probe会调用crypto_regis

18、ter_instance将其注册,以期将来可以顺利地找到并使用它:点击(此处)折叠或打开intcrypto_register_instance(struct crypto_template*tmpl,struct crypto_instance*inst)struct crypto_larval*larval;interr;/对算法进行合法性检查,并构造完整的驱动名称err=crypto_check_alg(if(err)gotoerr;/设置算法内核模块指针指向所属模版inst-alg.cra_module=tmpl-module;down_write(/注册算法实例对应的算法larval=

19、_crypto_register_alg(if(IS_ERR(larval)goto unlock;/成功后,将算法再注册到所属的模版上面hlist_add_head(/设置模版指针inst-tmpl=tmpl;unlock:up_write(err=PTR_ERR(larval);if(IS_ERR(larval)gotoerr;crypto_wait_for_test(larval);err=0;err:returnerr;注册的一个重要工作,就是调用_crypto_register_alg将实例所对应的算法注册到加密框架子系统中。算法注册成功后,上层调用者就可以调用crypto_alg_

20、mod_lookup等函数进行查找,并使用该算法了。三、 HMACMAC(消息认证码)与hash函数非常相似,只是生成固定长度的消息摘要时需要秘密的密钥而已。HAMC是密钥相关的哈希运算消息认证码(keyed-Hash Message Authentication Code),HMAC运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。具体的算法描述详见:http:/baike.baidu/view/1136366?fr=ala0_1。根据HMAC的特点(可以和类似md5、sha等hash算法组合,构造出hmac(md5)这样的算法),Linux 加密框架将其抽像为一个算法

21、模版。本章将假设上层调用者使用了名为hmac(md5)的算法,展示这一算法是如何被构造、初始化及调用以实现数据验证的。1. 算法模版的注册与注销点击(此处)折叠或打开static struct crypto_template hmac_tmpl=.name=hmac,.alloc=hmac_alloc,.free=hmac_free,.module=THIS_MODULE,;点击(此处)折叠或打开staticint_init hmac_module_init(void)return crypto_register_template(点击(此处)折叠或打开static void _exit hm

22、ac_module_exit(void)crypto_unregister_template(模版的注册与注销前文已经描述过了。2. 算法实例的分配当一个算法需要被使用却查找不到的时候,会尝试调用其模版对应分配相应的算法实列,这也适用于hmac,其alloc函数指针指向hmac_alloc:点击(此处)折叠或打开static struct crypto_instance*hmac_alloc(struct rtattr*tb)struct crypto_instance*inst;struct crypto_alg*alg;interr;intds;/类型检查,所属算法必需为hash类型err

23、=crypto_check_attr_type(tb,CRYPTO_ALG_TYPE_HASH);if(err)return ERR_PTR(err);/根据参数名称,查找相应的子算法,如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);/初始化算法实例inst=ERR_PTR(-EINVAL);/计算算法实列的消息摘要大小(输出大小)ds=alg-cra_type=alg-cra_hash.dig

24、estsize:alg-cra_type?_crypto_shash_alg(alg)-digestsize:alg-cra_digest.dia_digestsize;if(dsalg-cra_blocksize)goto out_put_alg;/分配一个算法实列,这样,一个新的算法,如hmac(md5)就横空出世了inst=crypto_alloc_instance(hmac,alg);/分配失败if(IS_ERR(inst)goto out_put_alg;/初始化算法实例,其相应的成员等于其子算法中的对应成员/类型inst-alg.cra_flags=CRYPTO_ALG_TYPE_

25、HASH;/优先级inst-alg.cra_priority=alg-cra_priority;/计算消息摘要的块长度(输入大小)inst-alg.cra_blocksize=alg-cra_blocksize;/对齐掩码inst-alg.cra_alignmask=alg-cra_alignmask;/类型指针指向crypto_hash_typeinst-alg.cra_type=/消息摘要大小inst-alg.cra_hash.digestsize=ds;/计算算法所需的上下文空间大小inst-alg.cra_ctxsize=sizeof(struct hmac_ctx)+ALIGN(in

26、st-alg.cra_blocksize*2+ds,sizeof(void*);/初始化和退出函数inst-alg.cra_init=hmac_init_tfm;inst-alg.cra_exit=hmac_exit_tfm;/置相应hash算法的操作函数,包含hash函数标准的init/update/final和digest/setkeyinst-alg.cra_hash.init=hmac_init;inst-alg.cra_hash.update=hmac_update;inst-alg.cra_hash.final=hmac_final;/消息摘要函数inst-alg.cra_hash

27、.digest=hmac_digest;/setkey(密钥设置函数)inst-alg.cra_hash.setkey=hmac_setkey;out_put_alg:crypto_mod_put(alg);return inst;每个模版的alloc动作虽不同,但是它们基本上遵循一些共性的操作:1、 合法性检验,如类型检查;2、 取得其子算法(即被模版所包裹的算法,如hmac(md5)中,就是md5)的算法指针;3、 调用crypto_alloc_instance分配一个相应的算法实列;4、 对分配成功的算法实例进行实始化,这也是理解该算法实例最核心的部份,因为它初始化算法运行所需的一些必要

28、参数和虚函数指针;crypto_alloc_instance(algapi.c) 函数用于分配一个算法实例,这个函数有两个重要功能,一个是分配内存空间,另一个是初始化spawn。点击(此处)折叠或打开/name:模版名称/alg:模版的子算法struct crypto_instance*crypto_alloc_instance(constchar*name,struct crypto_alg*alg)struct crypto_instance*inst;struct crypto_spawn*spawn;interr;/分配一个算法实例,crypto_instance结构的最后一个成员ct

29、x是一个指针变量,所以,在分配空间的时候,在其尾部追加相应的空间,可以使用ctx访问之。/另一个重要的概念是,算法实例中包含了算法,这个分配,同时也完成了算法实例对应的算法的分配工作。inst=kzalloc(sizeof(*inst)+sizeof(*spawn),GFP_KERNEL);if(!inst)return ERR_PTR(-ENOMEM);err=-ENAMETOOLONG;/构造完成的算法名称if(snprintf(inst-alg.cra_name,CRYPTO_MAX_ALG_NAME,%s(%s),name,alg-cra_name)=CRYPTO_MAX_ALG_NA

30、ME)goto err_free_inst;/构造完整的算法驱动名称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指向算法实例的上下文成员,可以这样做是因为_ctx是一个可变长的成员,在分配实例的时候,/在尾部增加了一个spawn的空间spawn=crypto_instance_ctx(inst);/初始化spawnerr=crypto_init_spawn(spawn,a

31、lg,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取出算法实例的ctx指针,返回值是void *,这意味着可以根具不同的需要,将其转换为所需的类型:点击(此处)折叠或打开static inline void*crypto_instance_ctx(struct crypto_instance*inst)return inst-_ctx;一个算法实例

32、被分配成员后,其会被注册至加密子系统,这样,一个算法,例如,hmac(md5)就可以直接被使用了。3. 待孵化的卵 已经看到了从模版到算法实例的第一层抽像,每个算法在每一次被使用时,它们的运行环境不尽相同,例如,可能会拥有不同的密钥。将算法看成一个类,则在每一次运行调用时,需要为它产生一个“对像”,这在内核中被称为transform,简称为tfm。后文会详细看到分配一个tfm的过程,现在引入这一概念,主要是为了分析spawn。加密或认证算法,在调用时,都需要分配其算法对应的tfm,在分配算法实例的同时,并没有为之分配相应的tfm结构,这是因为真正的算法还没有被调用,这并不是进行tfm结构分配的

33、最佳地点。在初始化算法实例的时候,加密框架使用了XXX_spawn_XXX函数簇来解决这一问题。这样的算法对像,被称为spawn(卵)。也就是说,在算法实例分配的时候,只是下了一个蛋(设置好spawn),等到合适的时候来对其进行孵化,这个“合适的时候”,通常指为调用算法实际使用的时候。在crypto_alloc_instance分配算法实例的时候,就顺便分配了spawn,然后调用crypto_init_spawn对其进行初始化:点击(此处)折叠或打开intcrypto_init_spawn(struct crypto_spawn*spawn,struct crypto_alg*alg,stru

34、ct crypto_instance*inst,u32 mask)interr=-EAGAIN;/初始化其成员spawn-inst=inst;spawn-mask=mask;down_write(if(!crypto_is_moribund(alg)/加入链表,每个spawn,都被加入到算法的cra_users链,即算做算法的一个用户list_add(/spawn的alg成员指针指向当前成员,这就方便引用了spawn-alg=alg;err=0;up_write(returnerr;所以,所谓算法的spawn的初始化,就是初始化crypto_spawn结构,核心的操作是设置其对应的算法实例、算

35、法,以及一个加入算法的链表的过程。4. 算法的初始化有了算法实例,仅表示内核拥有这一种“算法”加引号的意思是说,它可能并不以类似md5.c这样的源代码形式存现,而是通过模版动态创建的。实际要使用该算法,需要为算法分配“运行的对像”,即tfm。4.1 tfm内核加密框架中,使用结构crypto_alg来描述一个算法,每一个算法(实例)相当于一个类,在实际的使用环境中,需要为它分配一个对像,在内核加密框架中,这个“对像”被称为transform(简称tfm)。transform意味“变换”,可能译为“蜕变”更为合适。作者对它的注释是:/* Transforms: user-instantiated

36、 objects which encapsulate algorithms* and core processing logic.Managed via crypto_alloc_*() and* crypto_free_*(), as well as the various helpers below.*/tfm是加密框架中一个极为重要的概念,它由结构crypto_tfm描述:点击(此处)折叠或打开struct crypto_tfmu32 crt_flags;unionstruct ablkcipher_tfm ablkcipher;struct aead_tfm aead;struct b

37、lkcipher_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_ctxCRYPTO_MINALIGN_ATTR;这些成员的作用,将在后面一一看到,值得注意的是,针对每种算法不同,结构定义了一个名为crt_u的联合体,以对应每种算

38、法的tfm的具体操作,例如加密/解密,求hash,压缩/解压等,加密框架引入了一组名为xxx_tfm的结构封装,xxx表示算法类型,也就是crt_u成员。其定义如下:点击(此处)折叠或打开struct ablkcipher_tfmint(*setkey)(struct crypto_ablkcipher*tfm,constu8*key,unsignedintkeylen);int(*encrypt)(struct ablkcipher_request*req);int(*decrypt)(struct ablkcipher_request*req);int(*givencrypt)(struc

39、t skcipher_givcrypt_request*req);int(*givdecrypt)(struct skcipher_givcrypt_request*req);struct crypto_ablkcipher*base;unsignedintivsize;unsignedintreqsize;struct aead_tfmint(*setkey)(struct crypto_aead*tfm,constu8*key,unsignedintkeylen);int(*encrypt)(struct aead_request*req);int(*decrypt)(struct aea

40、d_request*req);int(*givencrypt)(struct aead_givcrypt_request*req);int(*givdecrypt)(struct aead_givcrypt_request*req);struct crypto_aead*base;unsignedintivsize;unsignedintauthsize;unsignedintreqsize;struct blkcipher_tfmvoid*iv;int(*setkey)(struct crypto_tfm*tfm,constu8*key,unsignedintkeylen);int(*enc

41、rypt)(struct blkcipher_desc*desc,struct scatterlist*dst,struct scatterlist*src,unsignedintnbytes);int(*decrypt)(struct blkcipher_desc*desc,struct scatterlist*dst,struct scatterlist*src,unsignedintnbytes);struct cipher_tfmint(*cit_setkey)(struct crypto_tfm*tfm,constu8*key,unsignedintkeylen);void(*cit

42、_encrypt_one)(struct crypto_tfm*tfm,u8*dst,constu8*src);void(*cit_decrypt_one)(struct crypto_tfm*tfm,u8*dst,constu8*src);struct hash_tfmint(*init)(struct hash_desc*desc);int(*update)(struct hash_desc*desc,struct scatterlist*sg,unsignedintnsg);int(*final)(struct hash_desc*desc,u8*out);int(*digest)(st

43、ruct hash_desc*desc,struct scatterlist*sg,unsignedintnsg,u8*out);int(*setkey)(struct crypto_hash*tfm,constu8*key,unsignedintkeylen);unsignedintdigestsize;struct ahash_tfmint(*init)(struct ahash_request*req);int(*update)(struct ahash_request*req);int(*final)(struct ahash_request*req);int(*digest)(str

44、uct ahash_request*req);int(*setkey)(struct crypto_ahash*tfm,constu8*key,unsignedintkeylen);unsignedintdigestsize;unsignedintreqsize;struct compress_tfmint(*cot_compress)(struct crypto_tfm*tfm,constu8*src,unsignedintslen,u8*dst,unsignedint*dlen);int(*cot_decompress)(struct crypto_tfm*tfm,constu8*src,unsignedintslen,u8*dst,unsignedint*dlen)

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1