技术标签: linux linux kernel arm cryptoapi crypto
快速链接:
.
个人博客笔记导读目录(全部)
相关推荐:
Armv8 Cryptographic Extension介绍
Linux Kernel aarch64 Crypto原理和框架介绍
Linux kernel内核调用crypto算法的方法
Linux Kernel aarch64的ARM-CE aes-ecb的底层代码导读
说明: 在无特别的说明下,本文讲述得都是armv8-aarch64体系、linux kernel 4.14 arm64软件环境!
1、在linux crypto底层,实现aes/hash的算法有三种方式:
(1)、cpu的纯软实现,使用cpu的ALU,x0-x30等寄存器,加加减减的计算。(本文不讨论此项)
(2)、ARM-CE,就是The Armv8 Cryptographic Extension了,调用arm-ce的指令和寄存器,进行加加减减计算
(3)、ARM-NEON : 调用arm neon指令(128bit的寄存器v0-v31),进行加加减减计算
再进一步阐述ARM-CE,其实也调用NEON的浮点型运算器,读写arm-ce的寄存器、以前使用arm-ce的指令,进行加解密运算。
2、需要明确一点
The Armv8 Cryptographic Extension provides instructions for the acceleration of encryption and decryption
Armv8 Cryptographic Extension 并不是单独的硬件 ,只是ARM扩展了一套寄存器和命令,依然还是cpu计算的
ARM NEON也是,也是一套寄存器和命令,依然还是cpu在下执行
3、以aes为例,arm-ce和arm-neon的crypto的暴露给上层的接口代码,都在下列文件中
在aes-glue.c中, 注册了aes算法接口:
static struct crypto_alg aes_algs[] = {
{
.cra_name = "__ecb-aes-" MODE,
.cra_driver_name = "__driver-ecb-aes-" MODE,
.cra_priority = 0,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
CRYPTO_ALG_INTERNAL,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct crypto_aes_ctx),
.cra_alignmask = 7,
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
.cra_blkcipher = {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = 0,
.setkey = aes_setkey,
.encrypt = ecb_encrypt,
.decrypt = ecb_decrypt,
},
}, {
.cra_name = "__cbc-aes-" MODE,
.cra_driver_name = "__driver-cbc-aes-" MODE,
.cra_priority = 0,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
CRYPTO_ALG_INTERNAL,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct crypto_aes_ctx),
.cra_alignmask = 7,
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
.cra_blkcipher = {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
.setkey = aes_setkey,
.encrypt = cbc_encrypt,
.decrypt = cbc_decrypt,
},
}, {
.cra_name = "__ctr-aes-" MODE,
.cra_driver_name = "__driver-ctr-aes-" MODE,
.cra_priority = 0,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
CRYPTO_ALG_INTERNAL,
.cra_blocksize = 1,
.cra_ctxsize = sizeof(struct crypto_aes_ctx),
.cra_alignmask = 7,
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
.cra_blkcipher = {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
.setkey = aes_setkey,
.encrypt = ctr_encrypt,
.decrypt = ctr_encrypt,
},
}, {
.cra_name = "__xts-aes-" MODE,
.cra_driver_name = "__driver-xts-aes-" MODE,
.cra_priority = 0,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
CRYPTO_ALG_INTERNAL,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct crypto_aes_xts_ctx),
.cra_alignmask = 7,
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
.cra_blkcipher = {
.min_keysize = 2 * AES_MIN_KEY_SIZE,
.max_keysize = 2 * AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
.setkey = xts_set_key,
.encrypt = xts_encrypt,
.decrypt = xts_decrypt,
},
}, {
.cra_name = "ecb(aes)",
.cra_driver_name = "ecb-aes-" MODE,
.cra_priority = PRIO,
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct async_helper_ctx),
.cra_alignmask = 7,
.cra_type = &crypto_ablkcipher_type,
.cra_module = THIS_MODULE,
.cra_init = ablk_init,
.cra_exit = ablk_exit,
.cra_ablkcipher = {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = 0,
.setkey = ablk_set_key,
.encrypt = ablk_encrypt,
.decrypt = ablk_decrypt,
}
}, {
.cra_name = "cbc(aes)",
.cra_driver_name = "cbc-aes-" MODE,
.cra_priority = PRIO,
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct async_helper_ctx),
.cra_alignmask = 7,
.cra_type = &crypto_ablkcipher_type,
.cra_module = THIS_MODULE,
.cra_init = ablk_init,
.cra_exit = ablk_exit,
.cra_ablkcipher = {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
.setkey = ablk_set_key,
.encrypt = ablk_encrypt,
.decrypt = ablk_decrypt,
}
}, {
.cra_name = "ctr(aes)",
.cra_driver_name = "ctr-aes-" MODE,
.cra_priority = PRIO,
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
.cra_blocksize = 1,
.cra_ctxsize = sizeof(struct async_helper_ctx),
.cra_alignmask = 7,
.cra_type = &crypto_ablkcipher_type,
.cra_module = THIS_MODULE,
.cra_init = ablk_init,
.cra_exit = ablk_exit,
.cra_ablkcipher = {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
.setkey = ablk_set_key,
.encrypt = ablk_encrypt,
.decrypt = ablk_decrypt,
}
}, {
.cra_name = "xts(aes)",
.cra_driver_name = "xts-aes-" MODE,
.cra_priority = PRIO,
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct async_helper_ctx),
.cra_alignmask = 7,
.cra_type = &crypto_ablkcipher_type,
.cra_module = THIS_MODULE,
.cra_init = ablk_init,
.cra_exit = ablk_exit,
.cra_ablkcipher = {
.min_keysize = 2 * AES_MIN_KEY_SIZE,
.max_keysize = 2 * AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
.setkey = ablk_set_key,
.encrypt = ablk_encrypt,
.decrypt = ablk_decrypt,
}
} };
4、aes-glue.c文件中并且定义了每一个接口指向的底层函数, 这里根据USE_V8_CRYPTO_EXTENSIONS分为了两中情况:
(1)、使用arm的crypto extension硬件算aes
(2)、使用arm的SIMD指令(ARM NEON)来算aes
#ifdef USE_V8_CRYPTO_EXTENSIONS
#define MODE "ce"
#define PRIO 300
#define aes_setkey ce_aes_setkey
#define aes_expandkey ce_aes_expandkey
#define aes_ecb_encrypt ce_aes_ecb_encrypt
#define aes_ecb_decrypt ce_aes_ecb_decrypt
#define aes_cbc_encrypt ce_aes_cbc_encrypt
#define aes_cbc_decrypt ce_aes_cbc_decrypt
#define aes_ctr_encrypt ce_aes_ctr_encrypt
#define aes_xts_encrypt ce_aes_xts_encrypt
#define aes_xts_decrypt ce_aes_xts_decrypt
MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 Crypto Extensions");
#else
#define MODE "neon"
#define PRIO 200
#define aes_setkey crypto_aes_set_key
#define aes_expandkey crypto_aes_expand_key
#define aes_ecb_encrypt neon_aes_ecb_encrypt
#define aes_ecb_decrypt neon_aes_ecb_decrypt
#define aes_cbc_encrypt neon_aes_cbc_encrypt
#define aes_cbc_decrypt neon_aes_cbc_decrypt
#define aes_ctr_encrypt neon_aes_ctr_encrypt
#define aes_xts_encrypt neon_aes_xts_encrypt
#define aes_xts_decrypt neon_aes_xts_decrypt
MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 NEON");
#endif
5、以ce_aes_cbc_encrypt为例,看下crypto extension的硬件实现:
在aes-ce-core.S中, 由此可以看出,这里最终调用的都是aesd、aesmc…等armv8 crypto extension的汇编指令
ENTRY(ce_aes_cbc_encrypt)
push {
r4-r6, lr}
ldrd r4, r5, [sp, #16]
vld1.8 {
q0}, [r5]
prepare_key r2, r3
.Lcbcencloop:
vld1.8 {
q1}, [r1, :64]! @ get next pt block
veor q0, q0, q1 @ ..and xor with iv
bl aes_encrypt
vst1.8 {
q0}, [r0, :64]!
subs r4, r4, #1
bne .Lcbcencloop
vst1.8 {
q0}, [r5]
pop {
r4-r6, pc}
ENDPROC(ce_aes_cbc_encrypt)
aes_encrypt:
add ip, r2, #32 @ 3rd round key
.Laes_encrypt_tweak:
do_block enc_dround, enc_fround
ENDPROC(aes_encrypt)
.macro enc_dround, key1, key2
enc_round q0, \key1
enc_round q0, \key2
.endm
.macro enc_round, state, key
aese.8 \state, \key
aesmc.8 \state, \state
.endm
6、以ce_aes_cbc_encrypt为例,看下NEON的硬件实现:
在aes-neon.S/aes-modes.S中, 由此可以看出,这里最终操作的都是v0-v31等128bit的SIMD寄存器
AES_ENTRY(aes_cbc_encrypt)
cbz w6, .Lcbcencloop
ld1 {
v0.16b}, [x5] /* get iv */
enc_prepare w3, x2, x6
/* do preload for encryption */
.macro enc_prepare, ignore0, ignore1, temp
prepare .LForward_Sbox, .LForward_ShiftRows, \temp
.endm
/* preload the entire Sbox */
.macro prepare, sbox, shiftrows, temp
adr \temp, \sbox
movi v12.16b, #0x40
ldr q13, \shiftrows
movi v14.16b, #0x1b
ld1 {
v16.16b-v19.16b}, [\temp], #64
ld1 {
v20.16b-v23.16b}, [\temp], #64
ld1 {
v24.16b-v27.16b}, [\temp], #64
ld1 {
v28.16b-v31.16b}, [\temp]
.endm
7、疑问与答案
kernel进程A在cpu0上跑的时候,被调度了,此时会将通用寄存器(如x0-x30,sp,pc等)保存起来,然后调度。等再回来时,(假设被cpu1接着执行了)再恢复下这些寄存器。程序就可以接着跑。
调度时只是保存了x0-x30等通用寄存器,并没有保存NEON寄存器v0-v31、ARM-CE的寄存器。
假如kernel线程A正在cpu0上执行浮点型运算(ARM NEON运算),然后被调度了(没有保存v0-v31),等再回来时是cpu1再来执行该线程,那么怎么可以回复之前的状态呢?
答案在Documentation/arm/kernel_mode_neon.txt中:
Use only NEON instructions, or VFP instructions that don’t rely on support
(1)Isolate your NEON code in a separate compilation unit, and compile it with ‘-mfpu=neon -mfloat-abi=softfp’
(2)Put kernel_neon_begin() and kernel_neon_end() calls around the calls into your NEON code
(3)Don’t sleep in your NEON code, and be aware that it will be executed with preemption disabled
也就是说在执行NEON的代码中 ,需要使用kernel_neon_begin()/kernel_neon_end()包上,这样这段代码就不会被抢占、属于原子操作了。就没有调度之说了
示例:请看arch/arnm64/crypto/aes-glue.c,在该代码中,在调用ARM-NEON或ARM-CE时,都是使用kernel_neon_begin()/kernel_neon_end()包上了
如下列代码所示,arm-neon和arm-ce的ecb_encrypt都是调用的下列函数,然后aes_ecb_encrypt是一个宏,有USE_V8_CRYPTO_EXTENSIONS宏来决定,其要么指向ARM-CE的函数,要么指向ARM-NEON的函数
ecb_encrypt的主体是被kernel_neon_begin()/kernel_neon_end()包裹着的,所以这段函数是原子操作。
static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
struct scatterlist *src, unsigned int nbytes)
{
struct crypto_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
int err, first, rounds = 6 + ctx->key_length / 4;
struct blkcipher_walk walk;
unsigned int blocks;
desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
kernel_neon_begin();
for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) {
aes_ecb_encrypt(walk.dst.virt.addr, walk.src.virt.addr,
(u8 *)ctx->key_enc, rounds, blocks, first);
err = blkcipher_walk_done(desc, &walk, walk.nbytes % AES_BLOCK_SIZE);
}
kernel_neon_end();
return err;
}
8、userspace调用、物理地址的连续性、对齐、block
linux kernel crypto和用户空间通过netlink交互,在linux kernel的algif_skcipher.c程序中,会将userspace sock传来的数据,保存在scatterlist结构体(离散的物理块).
然后在aes-ce-glue.c中,依次对每一块连续的物理地址数据调用底层的加解密函数
在底层的加解密函数中,需要自行解决对齐的处理、分block的处理
相关推荐:
[crypto]-01-对称加解密AES原理概念详解
[crypto]-02-非对称加解密RSA原理概念详解
[crypto]-03-数字摘要HASH原理概念详解
[crypto]-04-国产密码算法(国密算法sm2/sm3/sm4)介绍
[crypto]-05-转载:PKCS #1 RSA Encryption Version 1.5介绍
[crypto]-05.1-PKCS PKCS#1 PKCS#7 PKCS#11的介绍
[crypto]-06-CA证书介绍和使用方法
[crypto]-30-The Armv8 Cryptographic Extension在linux中的应用
[crypto]-31-crypto engion的学习和总结
[crypto]-50-base64_encode和base64_decode的C语言实现
[crypto]-51-RSA私钥pem转换成der, 在将der解析出n e d p q dp dq qp
[crypto]-52-python3中rsa(签名验签加密解密)aes(ecb cbc ctr)hmac的使用,以及unittest测试用
[crypto]-53-openssl命令行的使用(aes/rsa签名校验/rsa加密解密/hmac)
[crypto]-90-crypto的一些术语和思考
文章浏览阅读131次。我需要将一个xml的数据或者json数据的字符串转化为一个mysql中的表格形式。json_extract函数只能处理单个json数据,无法处理json数组,ExtractValue函数取出来的数据是拼接在一起的,不知道怎么分开,有没有其他办法呢,请教各位大神数据样例:[{"fCategoryId":"796","fCondition":"0.8"},{"fCategoryId":"730","f...
文章浏览阅读327次。首先在我的电脑选择一个盘打开然后在一个位置创建一个文件夹然后新建一个记事本文档将文件后缀名改为.v然后将实验代码输入到记事本文件中并保存然后打开Quartus II软件新建一个工程在弹出的选择界面中找到刚刚建立的记事本文档,工程名和记事本文档名字一样然后在下一个选择框中同样找到那个文件所在位置,调整相应的状态点击完成然后代码就导入到了工程中在最左侧的方框中右键文件点击setting然后又会弹出一个选择框然后调成modesilm然后调整一系列数据点击OK然后最左侧方框点击files点击文件右_module shared(x1,x2,s,f); input x1,x2,s; output f; assign f = (~s&x1)|(s&x2)
文章浏览阅读1.2k次,点赞29次,收藏24次。摘 要 IAbstract II引 言 11 控制系统设计 21.1 主控系统方案设计 21.2 脉搏传感器方案设计 31.3 系统工作原理 52 硬件设计 62.1 主电路 62.1.1 单片机的选择 62.1.2 STC89C51的主要功能及性能参数 62.1.3 STC89C51单片机引脚说明 62.2 驱动电路 82.2.1 比较器的介绍 82.3放大电路 82.4最小系统 113 软件设计 133.1编程语言的选择 133.2 Keil程序开发环境 _51单片机心率体温测量仪
文章浏览阅读770次,点赞3次,收藏8次。OneNET介绍_nb-iot工作步骤
文章浏览阅读1.5w次,点赞12次,收藏84次。Android Camera MIPI接口知识总结_csi的带宽估算adc色彩深度
文章浏览阅读3.4k次,点赞2次,收藏19次。计算机网络原理公式及计算题 (25页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦!11.90 积分 计算机网络原理公式及计算题第三章物理层公式一:数据传输速率的定义和计算每秒能传输的二进制信息位数,单位为位/秒(bits per second),记作bps或b/s R=1/T*Log2N(bps)T为一个数字脉冲信号的宽度(全宽码情况)或重复周期(归..._计算机网络公式总结
文章浏览阅读2.2k次,点赞31次,收藏36次。每年美赛结束后,评委根据参赛情况撰写评论文章,其中包括:以23年C题为代表的预测模型问题的关键点是什么?对23年C题各个小问的评价:哪些队伍的方案做得好,好在哪里?对文章其他部分的评价:数据预处理、敏感性分析…本文结合评委意见和当年O奖论文对23年美国大学生数学建模竞赛C题做出要点分析和总结,让我们一起来看看2023年美赛C题赛题分析吧!_美赛2023c题o奖论文
文章浏览阅读251次,点赞8次,收藏2次。通过在线工具超级ping,如果结果各地ping ip不太一样,证明使用了cdn。服务器可能会有多个域名,如果它的服务器的子域名可能因为访问量问题而不需要做CDN。这样我们直接nslookup 域名就直接解析出目标真实ip了。和各地ping一个原理,服务器可能在偏僻国家并没有做cdn。以国外的ip请求访问 因为可能对方只做了国内的cdn。查询历史ip域名绑定记录,很可能ip还是和现在一样的。直接ddos对方 消耗掉cdn资源。ico文件的hash值在引擎上搜索。通过邮件原文查看真实ip。
文章浏览阅读444次。在Sublime的setting里面添加:"update_check": false,保存即可。
文章浏览阅读455次。一、认识微服务跟踪的基础设施1.zipkintwitter开源的分布式跟踪系统,它的主要功能是收集系统的时序数据,从而追踪微服务架构的系统延时等问题。同时,它还提供了一个非常友好的界面,来帮助分析追踪数据。另外,它还有助于分析微服务之间的依赖关系。2.Spring Cloud Sleuth为Spring Cloud提供了分布式跟踪的解决方案。3.微服务跟踪的目的服务之间通过网络进行..._微服务链路追踪
文章浏览阅读1.7k次。报错找不到符号,可能原因很多,也许是jdk版本原因,也许是配置原因,等等先查看下以下配置框选中的,应该为勾选状态。如果不是这个原因,再去查找其他可能。_isnull找不到符号
文章浏览阅读1.5k次,点赞2次,收藏3次。如果要在阿里云上部署django网站,建议不要使用django自带的sqlite,虽然一时省事,但带来了很多其他的麻烦。建议使用MySQL或者PostgreSQL。由于MySQL比较流行,我就选择了MySQL。安装MySQL在使用MySQL之前,首先需要安装。在ubuntu系统下,输入以下命令:sudo apt-get install mysql-serversudo apt-get isntal_django使用阿里rds mysql数据库