快速鏈接: . 👉👉👉 個人博客筆記導讀目錄(全部) 👈👈👈 相關推薦: 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
, #
1 bne
. Lcbcencloopvst1
. 8 { q0
} , [ r5
] pop
{ r4
- r6
, pc
}
ENDPROC ( ce_aes_cbc_encrypt
)
aes_encrypt
: add ip
, r2
, #
32 @
3 rd 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
. 16 b
} , [ x5
] enc_prepare w3
, x2
, x6
. macro enc_prepare
, ignore0
, ignore1
, tempprepare
. LForward_Sbox
, . LForward_ShiftRows
, \temp
. endm
. macro prepare
, sbox
, shiftrows
, temp
adr \temp
, \sbox
movi v12
. 16 b
, #
0x40
ldr q13
, \shiftrows
movi v14
. 16 b
, #
0x1b
ld1
{ v16
. 16 b
- v19
. 16 b
} , [ \temp
] , #
64
ld1
{ v20
. 16 b
- v23
. 16 b
} , [ \temp
] , #
64
ld1
{ v24
. 16 b
- v27
. 16 b
} , [ \temp
] , #
64
ld1
{ v28
. 16 b
- v31
. 16 b
} , [ \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中的应用 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。