日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

[crypto]-30-The Armv8 Cryptographic Extension在linux中的应用

發布時間:2025/3/21 linux 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [crypto]-30-The Armv8 Cryptographic Extension在linux中的应用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

快速鏈接:
.
👉👉👉 個人博客筆記導讀目錄(全部) 👈👈👈


相關推薦:
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 blockveor q0, q0, q1 @ ..and xor with ivbl aes_encryptvst1.8 {q0}, [r0, :64]!subs r4, r4, #1bne .Lcbcencloopvst1.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, .Lcbcencloopld1 {v0.16b}, [x5] /* get iv */enc_prepare w3, x2, x6/* do preload for encryption */.macro enc_prepare, ignore0, ignore1, tempprepare .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的一些術語和思考

總結

以上是生活随笔為你收集整理的[crypto]-30-The Armv8 Cryptographic Extension在linux中的应用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。