营销型网站建设沈阳,深圳市建设工程,女的和男做那个视频网站,百度推广一般多少钱密码算法分类
对称算法非对称算法消息摘要#xff08;单向哈希#xff09;算法这些算法作为加密函数框架的最底层#xff0c;提供加密和解密的实际操作。这些函数可以在内核crypto文件夹下#xff0c;相应的文件中找到。不过内核模块不能直接调用这些函数#xff0c;因为…密码算法分类
对称算法非对称算法消息摘要单向哈希算法这些算法作为加密函数框架的最底层提供加密和解密的实际操作。这些函数可以在内核crypto文件夹下相应的文件中找到。不过内核模块不能直接调用这些函数因为它们并没有export。内核提供一个统一的框架来管理这些算法。加密算法通过crypto_register_alg()和crypto_unregister_alg()注册。
对称算法
头文件
// 包含对称密码symmetric key算法API该文件内部包含了linux/crypto.h所以无需再次引入linux/crypto.h
#include crypto/skcipher.h
// 对称密码API需要使用的struct scatterlist结构用来保存输入/输出缓冲区
#include linux/scatterlist.h Linux内核scatterlist API介绍 - AlanTu - 博客园
需要使用的重要数据结构 和 函数
// 用来保存加/解密缓冲区的结构
struct scatterlist sg;
// 加密算法对象上下文
struct crypto_skcipher *tfm;
// 异步操作请求对象
struct skcipher_request *req;
// 异步操作等待对象
struct crypto_wait wait;// 该函数用于等待异步加密操作完成通常需要将crypto_skcipher_decrypt的返回值作为err参数传入
int crypto_wait_req(int err, struct crypto_wait *wait);// 该函数作为异步加密操作的回调函数传入req对象中在加密完成后被调用
void crypto_req_done(struct crypto_async_request *req, int err);// 该函数根据密码算法名称分配密码算法对象内核支持的密码算法可以在/proc/crypto文件中查看
struct crypto_skcipher *crypto_alloc_skcipher(const char *alg_name,u32 type, u32 mask);struct skcipher_request *skcipher_request_alloc(struct crypto_skcipher *tfm, gfp_t gfp);// init function
// 初始化scatterlist时需要使用kmalloc分配的内存如果使用vmalloc分配的内存会导致内存页分配错误目前还不知道具体原因
void sg_init_one(struct scatterlist *sg,const void *buf, unsigned int buflen);// 设置异步调用的回调函数这里data是一个自定数据结构其会被传给回调函数。
void skcipher_request_set_callback(struct skcipher_request *req,u32 flags,crypto_completion_t compl,void *data);// 内核的对称加密API可以“原地”加密即加解密共用相同的缓冲区因此这里的src和dst可以设置为同一个
void skcipher_request_set_crypt(struct skcipher_request *req,struct scatterlist *src, struct scatterlist *dst,unsigned int cryptlen, void *iv);// 设置密钥和密钥长度密码长度单位为字节
int crypto_skcipher_setkey(struct crypto_skcipher *tfm,const u8 *key, unsigned int keylen);// 解密将返回值传入crypto_wait_req函数来等待可能的异步操作完成
int crypto_skcipher_decrypt(struct skcipher_request *req);
// 加密
int crypto_skcipher_encrypt(struct skcipher_request *req)// 释放资源
void crypto_free_skcipher(struct crypto_skcipher *tfm);
void skcipher_request_free(struct skcipher_request *req);scatterlist.h
scatterlist.h - include/linux/scatterlist.h - Linux source code (v5.15.11) - Bootlin scatterlist类型数据可以认为是这些密码算法操纵的数据对象。
crypto_skcipher
Linux Kernel Crypto API — The Linux Kernel 4.7 documentation crypto_tfm类型指针tfm可以理解为指代了一个算法对象
操作流程
内核加密编程接口 - 老僧非是爱花红 - 博客园PPT中对内核加密算法的使用总结得很详细。总的来说在内核态使用加密算法的过程分为以下几步
分配tranform对象 也就是具体的算法分配request对象 异步操作等待对象设置上下文 如加密密钥/验签公钥填充数据源给scatterlist设置缓冲区给异步请求对象设置回调函数/初始化向量等给密码算法对象设置密钥完成加密/解密/摘要/验签释放transform,request等对象例子 SM3
struct crypto_ahash * atfm crypto_alloc_ahash(sm3-generic,0,0);struct ahash_request *req ahash_request_alloc(atfm,GFP_KERNEL);struct crypto_wait wait;crypto_init_wait(wait);ahash_request_set_callback(req,CRYPTO_TFM_REQ_MAY_BACKLOG,crypto_req_done,wait);struct scatterlist sg;sg_init_one(sg,data,size);ahash_request_set_crypt(req,sg,result,size);retcrypto_ahash_digest(req);ahash_request_free(req); crypto_free_ahash(atfm);
相关数据结构关联 上图粗略描述了静态算法构造transform、构造request的过程:分配空间/初始化函数指针/建立tfm、req和alg之间的关联。建立关联的过程被各种看似复杂的对象之间的包含/被包含的关系掩盖了简单的实质之所以实现得这么复杂是为了未来能灵活地对加密模块进行扩展阅读这部分代码时我们不要被这种复杂的假象所吓倒。最终干活的为transformtransform中保存的相关函数指针是在构造transform时从对应的alg实例中拷贝过来的对应上图中棕色的一部分。例子
int linux_kernel_crypto_decrypt(void* data_in_out, int data_len, void* key, int key_len, void* iv, int iv_len) {struct crypto_skcipher* cipher;struct skcipher_request* req;struct crypto_wait wait;struct scatterlist sg;size_t block_size;int ret;// 分配算法对象支持的算法可以在/proc/crypto文件中查看cipher crypto_alloc_skcipher(cbc(aes), 0, 0);if (IS_ERR(cipher)) {printk(fail to allocate cipher\n);return -1;}// skcipher api不支持填充所以加/解密数据需要为加密块的整数倍block_size crypto_skcipher_blocksize(cipher);if (data_len % block_size ! 0) {printk(data len not aligned);return -1;}// 分配req对象req skcipher_request_alloc(cipher, GFP_KERNEL);if (IS_ERR(req)) {printk(fail to allocate req\n);return -1;}sg_init_one(sg, data_in_out, data_len);skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, crypto_req_done, wait);skcipher_request_set_crypt(req, sg, sg, data_len, iv);ret crypto_skcipher_setkey(cipher, key, key_len);if ( 0 ! ret) {printk(fail to set key, error %d\n, ret);return -1;}// 执行解密操作ret crypto_wait_req(crypto_skcipher_decrypt(req), wait); if (0 ! ret) {printk(decryption error %d\n, ret);return -1}// 释放资源crypto_free_skcipher(cipher);skcipher_request_free(req);printk(decryption finished);return 0;
}相关学习
struct shash_desc {struct crypto_shash *tfm;u32 flags;void *__ctx[] CRYPTO_MINALIGN_ATTR;
};tfm: 加密handlerctx: 空数组的首地址相当于汇编里的一个标号指向结构体的后一个字节。 这个结构体可能会跟一段buffer一起被申请而ctx就相当于这段buffer的首地址所以为了防止访问buffer时出现对齐错误需要给ctx加上属性CRYPTO_MINALIGN_ATTRCRYPTO_MINALIGN_ATTR的含义是通过可能的字节填充使得ctx是以最大的对齐标准对齐的防止出现对齐错误。例如在我的机器上CRYPTO_MINALIGN_ATTR的含义是强制以64位对齐。
static struct sdesc *init_sdesc(struct crypto_shash *alg)
{struct sdesc *sdesc;int size;size sizeof(struct shash_desc) crypto_shash_descsize(alg);sdesc kmalloc(size, GFP_KERNEL);if (!sdesc)return ERR_PTR(-ENOMEM);sdesc-shash.tfm alg;return sdesc;
}crypto_shash_descsize(alg): 得到这个加密算法需要的buffer大小。struct shash_desc的大小加上buffer大小就是总共需要申请的内存大小size。kmalloc: 申请小于一页的内存。其中GFP_KERNEL表示申请正常的内核RAM可以睡眠。kmallocERR_PTR: 把错误码变成指针。解读PTR_ERR,ERR_PTR,IS_ERR_窗外云天的专栏-CSDN博客
适用场景
Kernel Crypto框架_内核工匠-CSDN博客_内核cryptoKernel crypto主要用于kernel层的安全特性实现但在user-space也可以通过系统调用的方式来使用它因为在Linux-2.6.38中已经通过socket (addr family: AF_ALG)方式导出接口到user-space.在开发时如要快速确认kernel中是否支持某种算法可以cat /proc/crypto 查看name代表算法名称hmac是对应的模式抽象成templatepriority代表算法的优先级在相同名称下数字越大代表优先级越高默认使用高优先级的算法selftest代表开机算法自检结果type指算法类型async指异步方式调用blocksize指最小单个数据处理块大小min keysize和max keysize指算法的最小/最大密钥长度ivsize指算法的IV初始向量长度。*selftest之后的所有字段其实都是crypto_type-show()所提供的后面会提及
crypto整体框架 crypto core是最基本骨架 它提供crypto的核心组件包括crypto_algcrypto_template的管理cryptd内核线程等基于crypto core内核实现了8类常用的算法DRBG伪随机数算法Hash算法SKCIPHER对称加解密算法AKCIPHER非对称加解密算法AEAD认证加密算法HMAC算法COMPRESS压缩算法KPP密钥协商算法。一些用于secure的硬件模块如hw_rng硬件随机数产生器qce硬加密模块的驱动程序会通过crypto core提供的算法注册接口crypto_register_alg将其注册到crypto子系统中并且在注册时会对算法做静态正确性自检并在/proc/crypto中的selftest中呈现到userspace。除了注册到crypto子系统以外驱动也可以通过VFS以设置节点形式提供给用户空间使用如/dev/qce/dev/hw_rng。Crypto core通过socket方式将kernel层的算法能力提供给用户空间。Kernel crypto中基本所有操作都是围绕着几个核心数据结构展开struct crypto_algstruct crypto_templatestruct crypto_instancestruct crypto_tfmstruct crypto_type。其他算法都可以基于它们做扩展。例如struct skcipher_algstruct shash_alg都是继承自struct crypto_alg结构体介绍
algapi.h - include/crypto/algapi.h - Linux source code (v5.15.11) - Bootlin
struct crypto_template 算法模板一般在module_init时通过调用crypto_register_template接口注册到crypto_template_list链表中。在算法加密中分块加密模式分为很多种以对称加解密为例有CBCECBGCMCTRXTS而这些加密模式适用于所有的对称加密算法如AESDES因此kernel就将加密模式抽象成模板在开发新的算法时只需要实现单个block的数据处理加密hmac等在申请使用算法时我们通过算法名来组合出相应的算法kernel会将组合出来的算法动态注册到crypto子系统格式为template(single block cipher)例如cbc(aes)ecb(des)。 list用于模块的crypto_template_list链表管理instance用于管理当前模板下所有的crypto_instancealloc接口用于申请算法实例free用于释放算法实例
struct crypto_alg crypto.h - include/linux/crypto.h - Linux source code (v5.15.11) - Bootlincrypto_alg是个基类任何算法都可以基于它派生出衍生类每个算法都对应着一个struct crypto_alg实例一般在module_init中调用crypto_register_alg接口将具体的crypto_alg对象添加到crypto_alg_list链表中。这里有一个很重要的数据成员cra_u因为它体现了kernel crypto架构设计者的设计思想它将四种比较常用的算法类型的处理方式抽象到基类当中即如果你要添加的算法为这4类就只需要实现这4类算法所对应的方法如果不是这4类当中就需要在基类上做派生实现特定的crypto_type。 cra_list是用作链表管理cra_users此算法被引用的所有crypto_spawn实例链表。cra_blocksize是单个处理数据块大小cra_ctxsize为transformation context大小cra_alignmask指待处理数据buffer的对齐要求cra_priority是当前算法优先级cra_refcnt为当前算法的引用计数cra_name和cra_driver_name分别指代算法名及驱动名cra_type指算法类型cra_u将四大类算法类型进行了统一。cra_init是用于每次数据操作上下文前的初始化比如在硬件加密中会实现此接口对相关寄存器做初始化cra_exit则与前者相反。cra_destroy是用于crypto在kernel中注销的相关操作。
struct crypto_instance algapi.h - include/crypto/algapi.h - Linux source code (v5.15.11) - Bootlin这个结构体是代表kernel通过template动态创建的算法实例并且会与crypto_template相关联可以看到这里的alg并不是个指针。它是通过template-alloc()创建的创建的同时会将算法name初始化。__ctx当前只指向crypto_spawn我个人理解可能是架构设计者考虑到未来扩展性就将crypto_spawn与crypto_instance拆分开来了。
struct crypto_spawn 通过模板动态生成的算法实例的一部分。
list添加到crypto_alg-cra_users链表中。frontend见下文。
struct crypto_type crypto_type就是用于重载crypto_alg中的cra_u中的各个类中的成员函数当通过crypto_alloc_basecrypto_create_tfm等接口申请相应的crypto的TFM上下文时若有传入crypto_type参数TFM优先使用crypto_type中的init_tfm成员函数去初始化crypto_tfm衍生类的操作方法。 ctxsize:获取当前算法类型TFM上下文大小crypto_tfmcrypto_tfm.__crt_ctxextsize:获取当前算法类型TFM上下文大小即crypto_tfm衍生类的大小。init:一般为空功能与init_tfm类似通常在后者中初始化TFM。init_tfm:顾名思义初始化TFM。show:呈现当前算法类型的基本信息/proc/crypto后半段信息就是从这获取的。free:释放crypto_instance。
struct crypto_tfm 具体算法处理(transformation)上下文的实例里面会将此次算法上下文的key,IV等信息设置到__crt_ctx中。crt_u算法的operationkernel会在__crypto_alloc_tfm接口中关联到crypto_type或xxx_alg中的实现方法。
例子讲解
通过用例介绍crypto子系统逻辑在文件系统加密FBE中通过kernel crypto做密钥派生。背景在Android 7.0时引入了文件加密功能所谓文件加密即每个文件都用不同的key对文件进行加密。原理密钥派生中使用了crypto中的ecb(aes)算法通过类密钥及inode.nonce派生出每个文件的密钥。具体实现在kernel/fs/crypto/keyinfo.ccrypto.c - fs/crypto/crypto.c - Linux source code (v5.15.11) - Bootlin1申请“ecb(aes)”算法的tfm上下文。这里会涉及到“算法动态注册”即如果在crypto_alg_list链表中没有找到name为”ecb(aes)”的crypto_alg对象那crypto子系统会通过一个名为”cryptomgr_probe”的内核线程查找到name为“ecb”的crypto_template对象以及查找到name为”aes”的crypto_alg对象动态创建出一个name为“ecb(aes)”的crypto_alg并注册到链表当中。在获取到了crypto_alg后就会申请crypto_tfm并用crypto_alg-cra_init()或crypto_type-init_tfm()对其进行初始化主要是当前算法的各个函数指针。2 在tfm上下文中申请一个数据处理请求req。一个tfm中可以做多次数据加解密。这里只是申请内存并关联到tfm的操作。3 设置密钥到tfm-__crt_ctx中。4 把待加密数据信息放入req当中。5以异步方式调用crypto_skcipher_encrypt对req做加密处理线程在此会block一段时间直到req请求被处理完成。因此不能在中断上下文中使用。算法自检
出于安全性考虑FIPS等相关标准要求在系统开机时必须做算法正确性自检如果自检失败则停止系统的启动因此算法自检这部分自然也在框架中实现了。源码位于kernel/crypto/testmgr.cKernel中的算法自检为静态自检即给定输入参数及正确结果如果算法计算出来的结果与正确结果不匹配则自检失败。算法自检的时间点固定为每个crypto_alg注册的时候具体流程如下图2.4所示Linux加密框架设计和实现
Linux加密框架设计与实现(第一部份) - 内核源码-Chinaunix
内核 crypto介绍
Linux kernel crypto的介绍_代码改变世界-CSDN博客_crypto linux af_alg是linux kernel crypto算法接口
实现了底层算法的调用(skcipher、aead、hash、rng)并且将这些接口export出去给linux kernel其它模块使用(如tcrypt.c使用);将这些接口注册sock_register, 用户程序通过sock通信来调用这些底层接口在linux kernel中仅支下四种crypto算法: algif_skcipher 对称加解密算法algif_aead 也算一种对称的加解密算法具体介绍参见什么是AEAD加密algif_hash 数字摘要算法algif_rng 随机数产生在Linux kernel的module_init阶段会将algif_type_skcipher、algif_type_aead、algif_type_hash、algif_type_rng 四种算法注册.也就是添加到af_alg维护的alg_types链表种. alg_types链表种仅有这四个数据.在userspace通过netlink调用了kernel种的af_alg模块收到消息后, 根据上层传来的算法种类名字来选择走哪一个结构体(alg_type_xxx)的ops函数
sendmsg/recvmsg如何调用到底层encrypt/decrypt
以skcipher为例, 在userspace调用send()和recive()函数对应的底层调用recvmsg和sendmsg函数。先看skcipher_recvmsg()函数接受数据然后再调用encrypt/decrypt处理数据 而skcipher_sendmsg()函数就是将处理后的数据在发送到sock端.
static int skcipher_recvmsg(struct socket *sock, struct msghdr *msg,size_t ignored, int flags)
{return (msg-msg_iocb !is_sync_kiocb(msg-msg_iocb)) ?skcipher_recvmsg_async(sock, msg, flags) :skcipher_recvmsg_sync(sock, msg, flags);
}算法的底层实现(以为aes/hash为例)
在linux crypto底层实现aes/hash的算法有四种方式1cpu的纯软实现使用cpu的ALU,x0-x30等寄存器加加减减的计算2ARM-CE就是The Armv8 Cryptographic Extension了调用arm-ce的指令和寄存器进行加加减减计算3ARM-NEON 调用arm neon指令128bit的寄存器v0-v31进行加加减减计算4SOC crypto engine的实现
参考链接
Linux source code (v5.15.11) - Bootlin Linux内核 在线源代码 查询函数定义和使用Linux Kernel(Android) 加密算法总结(一)cipher、compress、digest_万能的终端和网络-程序员宅基地 - 程序员宅基地没有调用crypto_skcipher_encrypt回调 | 码农俱乐部 - Golang中国 - Go语言中文社区Linux内核加密接口分析_一些笔记杂谈-CSDN博客_linux内核加密接口Linux内核中使用crypto进行sha1方法_Rain的博客-CSDN博客Linux内核模块开发_j5856004的博客-CSDN博客Linux驱动开发1-内核入门之hello模块_zusi_csdn-CSDN博客_linux内核驱动开发linux crypto_u014044624的博客-CSDN博客Linux内核crypto子系统学习笔记_scarecrow_byr的专栏-CSDN博客_crypto驱动