cipher使用参考
REVISION HISTORY¶
Revision No. | Description |
Date |
---|---|---|
1.0 | 04/18/2024 | |
1.1 | 04/11/2025 |
1. 概述¶
cipher模块,可用于对数据进行aes加解密、sha计算、rsa加解密与签章验签。
2. 关键字说明¶
-
AESDMA
进行加解密计算的硬件模块。
3. 功能描述¶
-
aes
支持aes128/aes192/aes256加解密算法;模式包括ecb/cbc/ctr模式;支持使用硬件密钥以及软件密钥。
-
hash
支持sha1/sha256算法,输入数据长度无限制
-
rsa
支持rsa2048/rsa4096加解密,签章验签;支持使用硬件密钥以及软件密钥
-
sm⅔/4
支持国密sm⅔/4算法
4. Uboot用法介绍¶
4.1 代码框架和config¶
4.1.1 代码框架¶
4.1.2 uboot config¶
uboot下打开以下配置 [*] SigmaStar drivers ---> [*] SigmaStar AESDMA
4.2 cipher API接口解析¶
4.2.1 aes加解密接口¶
函数原型:
@pConfig:the config of configurating aes hardware void MDrv_AESDMA_Run(aesdmaConfig* pConfig);
aesdmaConfig结构体字段解释:
typedef struct { MS_U64 u64SrcAddr; //the address of source data U32 u32Size; //the size of data that needs to be encrypted MS_U64 u64DstAddr; //the address of destination data enumAESDMA_KeyType eKeyType; //the type of aeskey,ep: E_AESDMA_KEY_CIPHER, E_AESDMA_KEY_OTP_EFUSE_KEY1~8, U16 * pu16Key; //the address of cipherkey BOOL bSetIV; //set iv or not BOOL bDecrypt; //0:encrypt,1:decrypt U16 * pu16IV; //the address of iv(16byte) enumAESDMA_ChainMode eChainMode; //three mode: E_AESDMA_CHAINMODE_ECB, E_AESDMA_CHAINMODE_CTR, E_AESDMA_CHAINMODE_CBC U32 keylen; // 16->aes128,32->aes256 } __attribute__((aligned(16))) aesdmaConfig;
demo路径:cmd/sstar/aes.c
以cbc加密为例:
-
配置加解密数据源数据,目标数据地址和长度,aeskey类型和长度,aeskey地址(cipherkey need),是否设置iv和iv地址(cbc/ctr mode need),加密模式(ecb/cbc/ctr)。
-
使用MDrv_AESDMA_Run接口将配置写入寄存器并触发。
-
加密完成的数据可以在地址config.u64DstAddr中读取到,长度为config.u32Size。
char __attribute__((aligned(64))) out_buf[128] = {0}; char __attribute__((aligned(16))) aes_cbc_plaintext[] = { "\x00\x01\x02\x03\x04\x05\x06\x07" "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" "\x10\x11\x12\x13\x14\x15\x16\x17" "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"}; char __attribute__((aligned(16))) aes_cbc_key[] = { "\xc2\x86\x69\x6d\x88\x7c\x9a\xa0" "\x61\x1b\xbb\x3e\x20\x25\xa4\x5a"}; char __attribute__((aligned(16))) aes_cbc_iv[] = { "\x56\x2e\x17\x99\x6d\x09\x3d\x28" "\xdd\xb3\xba\x69\x5a\x2e\x6f\x58"}; char __attribute__((aligned(16))) aes_cbc_result[] = { "\xd2\x96\xcd\x94\xc2\xcc\xcf\x8a" "\x3a\x86\x30\x28\xb5\xe1\xdc\x0a" "\x75\x86\x60\x2d\x25\x3c\xff\xf9" "\x1b\x82\x66\xbe\xa6\xd6\x1a\xb1"}; void verify_cbc_aes_encrypt(void) { aesdmaConfig config = {0}; int in_size; printf("\nTest AES-CBC encryption "); in_size = aes_cbc_ilen; memcpy(in_buf, aes_cbc_plaintext, in_size); //config struct aesdmaConfig config.u64SrcAddr = (unsigned long)in_buf; config.u64DstAddr = (unsigned long)out_buf; config.u32Size = in_size; config.eKeyType = E_AESDMA_KEY_CIPHER; config.pu16Key = (U16 *)aes_cbc_key; config.pu16IV = (U16 *)aes_cbc_iv; config.bSetIV = 1; config.eChainMode = E_AESDMA_CHAINMODE_CBC; //trig aesdma hardware MDrv_AESDMA_Run(&config); //compare result if (Compare_data(out_buf, aes_cbc_result, config.u32Size)) { printf("Failed\n"); Dump_data(out_buf, config.u32Size); } else { printf("passed!!\n"); } }
注意:ECB模式的加密资料的长度必须是16byte对齐。
otpkey作为密钥
如果需要以otpkey作为密钥,需要提前烧录OTP_AES128_KEY。 具体otpkey的生成以及烧录方式请参考Secureboot使用文档:Security_Boot_zh.md 中的第2章 OTP Key读写操作说明,关于Security_Boot_zh.md文档可以咨询FAE窗口。
OTP中AESKEY256实际上是由OTP中两把AES128组合而成,组合和设置方式举例如下。
欲设置:
KEY256_1:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
需设置:
key128_1:000102030405060708090A0B0C0D0E0F
key128_2:101112131415161718191A1B1C1D1E1F
配置方法和对应关系如下表:
eKeyType | keylen | corresponding otpkey |
---|---|---|
E_AESDMA_KEY_OTP_EFUSE_KEY1 | 16 | key128_1 |
E_AESDMA_KEY_OTP_EFUSE_KEY2 | 16 | key128_2 |
E_AESDMA_KEY_OTP_EFUSE_KEY3 | 16 | key128_3 |
E_AESDMA_KEY_OTP_EFUSE_KEY4 | 16 | key128_4 |
E_AESDMA_KEY_OTP_EFUSE_KEY1 | 32 | key256_1(key128_1+key128_2) |
E_AESDMA_KEY_OTP_EFUSE_KEY2 | 32 | key256_2(key128_3+key128_4) |
4.2.2 hash运算接口¶
@u64SrcAddr: //the address of source data @u32Size: //the size of data that needs to be hashed @eMode: //E_SHA_MODE_1 or E_SHA_MODE_256 @pu16Output: //the address of destination data void MDrv_SHA_Run(MS_U64 u64SrcAddr, U32 u32Size, enumShaMode eMode, U16* pu16Output)
demo路径:cmd/sstar/aes.c
以sha256为例:
- 配置加解密数据源数据,目标数据地址和长度,加密模式(sha1/sha256)。
- 使用MDrv_SHA_Run接口将配置写入寄存器并触发。
- 加密完成的数据可以在地址pu16Output中读取到,sha1长度为10byte,sha256长度为16byte。
char __attribute__((aligned(16))) sha_plaintext[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; int sha_psize = 56; char sha_digest[] = "\x24\x8d\x6a\x61\xd2\x06\x38\xb8" "\xe5\xc0\x26\x93\x0c\x3e\x60\x39" "\xa3\x3c\xe4\x59\x64\xff\x21\x67" "\xf6\xec\xed\xd4\x19\xdb\x06\xc1"; void verify_sha(void) { char __attribute__((aligned(16))) out_buf[128] = {0}; printf("\nTest %s ", __FUNCTION__); MDrv_SHA_Run((unsigned long)sha_plaintext, sha_psize, E_SHA_MODE_256, (U16 *)out_buf); if (Compare_data(out_buf, sha_digest, 32)) { printf("Failed\n"); Dump_data(out_buf, 32); } else { printf("passed!!\n"); } }
注意:sha的u64SrcAddr必须是十六byte对齐的,源数据请用 __attribute__((aligned(16)))关键字进行定义。
4.2.3 rsa加解密接口¶
@pConfig:the config of configurating rsa hardware void MDrv_RSA_Run(rsaConfig* pConfig)
typedef struct { U32 *pu32Sig; //the address of source data U32 *pu32KeyN; //the address of KeyN U32 *pu32KeyE; //the address of KeyE U32 *pu32Output; //the address of destination data BOOL bHwKey; //Invalid parameter BOOL bPublicKey; //0:pvivate key,1:public key U32 u32KeyLen; //256->2048,512->4096 U32 u32SigLen; //256->2048,512->4096 U32 u32OutputLen; //0,256->2048,512->4096 } __attribute__((aligned(16))) rsaConfig;
注:rsa只在上电的时候load一次hw key,用于rom code阶段的验签,之后都无法使用hw key。
demo路径:cmd/sstar/aes.c
以rsa2048为例:
- 配置加解密数据源数据,目标数据地址和长度,KeyN,KeyE,KeyLen,类型(公钥,私钥)等。
- 使用MDrv_RSA_Run接口将配置写入寄存器并触发。
- 加密完成的数据可以在地址pu16Output中读取到,rsa2048长度为256byte,rsa4096长度为512byte。
char __attribute__((aligned(16))) RSA_plaintext[] = { 0x31, 0x5d, 0xfa, 0x52, 0xa4, 0x93, 0x52, 0xf8, 0xf5, 0xed, 0x39, 0xf4, 0xf8, 0x23, 0x4b, 0x30, 0x11, 0xa2, 0x2c, 0x5b, 0xa9, 0x8c, 0xcf, 0xdf, 0x19, 0x66, 0xf5, 0xf5, 0x1a, 0x6d, 0xf6, 0x25, 0x89, 0xaf, 0x06, 0x13, 0xdc, 0xa4, 0xd4, 0x0b, 0x3c, 0x1c, 0x4f, 0xb9, 0xd3, 0xd0, 0x63, 0x29, 0x2a, 0x5d, 0xfe, 0xb6, 0x99, 0x20, 0x58, 0x36, 0x2b, 0x1d, 0x57, 0xf4, 0x71, 0x38, 0xa7, 0x8b, 0xad, 0x8c, 0xef, 0x1f, 0x2f, 0xea, 0x4c, 0x87, 0x2b, 0xd7, 0xb8, 0xc8, 0xb8, 0x09, 0xcb, 0xb9, 0x05, 0xab, 0x43, 0x41, 0xd9, 0x75, 0x36, 0x4d, 0xb6, 0x8a, 0xd3, 0x45, 0x96, 0xfd, 0x9c, 0xe8, 0x6e, 0xc8, 0x37, 0x5e, 0x4f, 0x63, 0xf4, 0x1c, 0x18, 0x2c, 0x38, 0x79, 0xe2, 0x5a, 0xe5, 0x1d, 0x48, 0xf6, 0xb2, 0x79, 0x57, 0x12, 0xab, 0xae, 0xc1, 0xb1, 0x9d, 0x11, 0x4f, 0xa1, 0x4d, 0x1b, 0x4c, 0x8c, 0x3a, 0x2d, 0x7b, 0x98, 0xb9, 0x89, 0x7b, 0x38, 0x84, 0x13, 0x8e, 0x3f, 0x3c, 0xe8, 0x59, 0x26, 0x90, 0x77, 0xe7, 0xca, 0x52, 0xbf, 0x3a, 0x5e, 0xe2, 0x58, 0x54, 0xd5, 0x9b, 0x2a, 0x0d, 0x33, 0x31, 0xf4, 0x4d, 0x68, 0x68, 0xf3, 0xe9, 0xb2, 0xbe, 0x28, 0xeb, 0xce, 0xdb, 0x36, 0x1e, 0xae, 0xb7, 0x37, 0xca, 0xaa, 0xf0, 0x9c, 0x6e, 0x27, 0x93, 0xc9, 0x61, 0x76, 0x99, 0x1a, 0x0a, 0x99, 0x57, 0xa8, 0xea, 0x71, 0x96, 0x63, 0xbc, 0x76, 0x11, 0x5c, 0x0c, 0xd4, 0x70, 0x0b, 0xd8, 0x1c, 0x4e, 0x95, 0x89, 0x5b, 0x09, 0x17, 0x08, 0x44, 0x70, 0xec, 0x60, 0x7c, 0xc9, 0x8a, 0xa0, 0xe8, 0x98, 0x64, 0xfa, 0xe7, 0x52, 0x73, 0xb0, 0x04, 0x9d, 0x78, 0xee, 0x09, 0xa1, 0xb9, 0x79, 0xd5, 0x52, 0x4f, 0xf2, 0x39, 0x1c, 0xf7, 0xb9, 0x73, 0xe0, 0x3d, 0x6b, 0x54, 0x64, 0x86}; char __attribute__((aligned(16))) RSA_KEYN[] = { 0x82, 0x78, 0xA0, 0xC5, 0x39, 0xE6, 0xF6, 0xA1, 0x5E, 0xD1, 0xC6, 0x8B, 0x9C, 0xF9, 0xC4, 0x3F, 0xEA, 0x19, 0x16, 0xB0, 0x96, 0x3A, 0xB0, 0x5A, 0x94, 0xED, 0x6A, 0xD3, 0x83, 0xE8, 0xA0, 0xFD, 0x01, 0x5E, 0x92, 0x2A, 0x7D, 0x0D, 0xF9, 0x72, 0x1E, 0x03, 0x8A, 0x68, 0x8B, 0x4D, 0x57, 0x55, 0xF5, 0x2F, 0x9A, 0xC9, 0x45, 0xCF, 0x9B, 0xB7, 0xF5, 0x11, 0x94, 0x7A, 0x16, 0x0B, 0xED, 0xD9, 0xA3, 0xF0, 0x63, 0x8A, 0xEC, 0xD3, 0x21, 0xAB, 0xCF, 0x74, 0xFC, 0x6B, 0xCE, 0x06, 0x4A, 0x51, 0xC9, 0x7C, 0x7C, 0xA3, 0xC4, 0x10, 0x63, 0x7B, 0x00, 0xEC, 0x2D, 0x02, 0x18, 0xD5, 0xF1, 0x8E, 0x19, 0x7F, 0xBE, 0xE2, 0x45, 0x5E, 0xD7, 0xA8, 0x95, 0x90, 0x88, 0xB0, 0x73, 0x35, 0x89, 0x66, 0x1C, 0x23, 0xB9, 0x6E, 0x88, 0xE0, 0x7A, 0x57, 0xB0, 0x55, 0x8B, 0x81, 0x9B, 0x9C, 0x34, 0x9F, 0x86, 0x0E, 0x15, 0x94, 0x2C, 0x6B, 0x12, 0xC3, 0xB9, 0x56, 0x60, 0x25, 0x59, 0x3E, 0x50, 0x7B, 0x62, 0x4A, 0xD0, 0xF0, 0xB6, 0xB1, 0x94, 0x83, 0x51, 0x66, 0x6F, 0x60, 0x4D, 0xEF, 0x8F, 0x94, 0xA6, 0xD1, 0xA2, 0x80, 0x06, 0x24, 0xF2, 0x6E, 0xD2, 0xC7, 0x01, 0x34, 0x8D, 0x2B, 0x6B, 0x03, 0xF7, 0x05, 0xA3, 0x99, 0xCC, 0xC5, 0x16, 0x75, 0x1A, 0x81, 0xC1, 0x67, 0xA0, 0x88, 0xE6, 0xE9, 0x00, 0xFA, 0x62, 0xAF, 0x2D, 0xA9, 0xFA, 0xC3, 0x30, 0x34, 0x98, 0x05, 0x4C, 0x1A, 0x81, 0x0C, 0x52, 0xCE, 0xBA, 0xD6, 0xEB, 0x9C, 0x1E, 0x76, 0x01, 0x41, 0x6C, 0x34, 0xFB, 0xC0, 0x83, 0xC5, 0x4E, 0xB3, 0xF2, 0x5B, 0x4F, 0x94, 0x08, 0x33, 0x87, 0x5E, 0xF8, 0x39, 0xEF, 0x7F, 0x72, 0x94, 0xFF, 0xD7, 0x51, 0xE8, 0xA2, 0x5E, 0x26, 0x25, 0x5F, 0xE9, 0xCC, 0x2A, 0x7D, 0xAC, 0x5B, 0x35}; char __attribute__((aligned(16))) RSA_KEY_PrivateE[] = { 0x49, 0x7E, 0x93, 0xE9, 0xA5, 0x7D, 0x42, 0x0E, 0x92, 0xB0, 0x0E, 0x6C, 0x94, 0xC7, 0x69, 0x52, 0x2B, 0x97, 0x68, 0x5D, 0x9E, 0xB2, 0x7E, 0xA6, 0xF7, 0xDF, 0x69, 0x5E, 0xAE, 0x9E, 0x7B, 0x19, 0x2A, 0x0D, 0x50, 0xBE, 0xD8, 0x64, 0xE7, 0xCF, 0xED, 0xB2, 0x46, 0xE4, 0x2F, 0x1C, 0x29, 0x07, 0x45, 0xAF, 0x44, 0x3C, 0xFE, 0xB3, 0x3C, 0xDF, 0x7A, 0x10, 0x26, 0x18, 0x43, 0x95, 0x02, 0xAD, 0xA7, 0x98, 0x81, 0x2A, 0x3F, 0xCF, 0x8A, 0xD7, 0x12, 0x6C, 0xAE, 0xC8, 0x37, 0x6C, 0xF9, 0xAE, 0x6A, 0x96, 0x52, 0x4B, 0x99, 0xE5, 0x35, 0x74, 0x93, 0x87, 0x76, 0xAF, 0x08, 0xB8, 0x73, 0x72, 0x7D, 0x50, 0xA5, 0x81, 0x26, 0x5C, 0x8F, 0x94, 0xEA, 0x73, 0x59, 0x5C, 0x33, 0xF9, 0xC3, 0x65, 0x1E, 0x92, 0xCD, 0x20, 0xC3, 0xBF, 0xD7, 0x8A, 0xCF, 0xCC, 0xD0, 0x61, 0xF8, 0xFB, 0x1B, 0xF4, 0xB6, 0x0F, 0xD4, 0xCF, 0x3E, 0x55, 0x48, 0x4C, 0x99, 0x2D, 0x40, 0x44, 0x7C, 0xBA, 0x7B, 0x6F, 0xDB, 0x5D, 0x71, 0x91, 0x2D, 0x93, 0x80, 0x19, 0xE3, 0x26, 0x5D, 0x59, 0xBE, 0x46, 0x6D, 0x90, 0x4B, 0xDF, 0x72, 0xCE, 0x6C, 0x69, 0x72, 0x8F, 0x5B, 0xA4, 0x74, 0x50, 0x2A, 0x42, 0x95, 0xB2, 0x19, 0x04, 0x88, 0xD7, 0xDA, 0xBB, 0x17, 0x23, 0x69, 0xF4, 0x52, 0xEB, 0xC8, 0x55, 0xBE, 0xBC, 0x2E, 0xA9, 0xD0, 0x57, 0x7D, 0xC6, 0xC8, 0x8B, 0x86, 0x7B, 0x73, 0xCD, 0xE4, 0x32, 0x79, 0xC0, 0x75, 0x53, 0x53, 0xE7, 0x59, 0x38, 0x0A, 0x8C, 0xEC, 0x06, 0xA9, 0xFC, 0xA5, 0x15, 0x81, 0x61, 0x3E, 0x44, 0xCD, 0x05, 0xF8, 0x54, 0x04, 0x00, 0x79, 0xB2, 0x0D, 0x69, 0x2A, 0x47, 0x60, 0x1A, 0x2B, 0x79, 0x3D, 0x4B, 0x50, 0x8A, 0x31, 0x72, 0x48, 0xBB, 0x75, 0x78, 0xD6, 0x35, 0x90, 0xE1, }; char __attribute__((aligned(16))) RSA_KEY_PublicE[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01}; void verify_rsa(void) { U8 __attribute__((aligned(16))) rsa_encrypt_out[256]; U8 __attribute__((aligned(16))) rsa_decrypt_out[256]; memset(rsa_encrypt_out, 0, sizeof(rsa_encrypt_out)); memset(rsa_decrypt_out, 0, sizeof(rsa_decrypt_out)); printf("\nTest %s encrypt\n", __FUNCTION__); { rsaConfig config = {0}; config.pu32KeyN = (U32 *)RSA_KEYN; config.pu32KeyE = (U32 *)RSA_KEY_PrivateE; config.u32KeyLen = 256; config.pu32Sig = (U32 *)(RSA_plaintext); config.u32SigLen = sizeof(RSA_plaintext); config.bPublicKey = 0; config.pu32Output = (U32 *)rsa_encrypt_out; MDrv_RSA_Run(&config); } printf("Test %s decrypt\n", __FUNCTION__); { rsaConfig config = {0}; config.pu32KeyN = (U32 *)RSA_KEYN; config.pu32KeyE = (U32 *)RSA_KEY_PublicE; config.u32KeyLen = 256; config.pu32Sig = (U32 *)(rsa_encrypt_out); config.u32SigLen = sizeof(rsa_encrypt_out); config.pu32Output = (U32 *)rsa_decrypt_out; config.bPublicKey = 1; MDrv_RSA_Run(&config); } if (Compare_data((char *)RSA_plaintext, (char *)rsa_decrypt_out, 256)) { printf("Failed\n"); printf("RSA_plaintext:\n"); Dump_data(RSA_plaintext, 256); printf("rsa_encrypt_out:\n"); Dump_data(rsa_encrypt_out, 256); printf("rsa_decrypt_out:\n"); Dump_data(rsa_decrypt_out, 256); } else { printf("passed!!\n"); } }
注意:非对称加密算法中,有两个密钥:公钥和私钥。它们是一对,如果用公钥进行加密,只有用对应的私钥才能解密;如果用私钥进行加密,只有用对应的公钥才能解密。
4.2.4 sm⅔/4加解密接口¶
uboot下暂不支持sm⅔/4加解密
5. Kernel用法介绍¶
5.1 代码框架和kernel config¶
5.1.1 代码框架¶
5.1.2 kernel config¶
kernel下打开以下配置,才可正常使用aesdma.
Device Drivers ---> [*] Sstar SoC platform drivers ---> <*> SigmaStar Crypto driver [*] HW_RANDOM Random Number Generator support <*> Support cryptodev
5.2 userspace下访问接口¶
通过用户层ioctl访问kernel。
- aes, sha, sm3, sm4:借助模块cryptodev,它提供了一种通用的加密API,使应用程序能够利用硬件加速的加密功能。可以通过打开
/dev/crypto
设备文件来访问加密功能。应用程序可以使用常见的加密算法(如AES、DES等)和模式(如CBC、ECB、CTR等)来执行加密和解密操作。
rsa, sm2
- rsa, sm2:Kernel原生接口中不支持RSA/SM2算法,故RSA/SM2使用Linux标准接口注册misc类设备,产生
/dev/rsa
和/dev/sm2
节点, User Space可通过节点使用Hardware RSA/SM2算法。
5.2.1 aes/sm4加解密接口¶
demo路径:drivers/sstar/cryptodev/examples/aes.c
drivers/sstar/cryptodev/examples/sm4.c
使用otpkey的demo:drivers/sstar/cryptodev/examples/aes-sstar-unique.c
-
打开节点
int cfd = -1; /* Open the crypto device */ cfd = open("/dev/crypto", O_RDWR, 0); if (cfd < 0) { perror("open(/dev/crypto)"); return 1; } /* Set close-on-exec (not really needed here) */ if (fcntl(cfd, F_SETFD, 1) == -1) { perror("fcntl(F_SETFD)"); return 1; }
-
创建session
int aes_ctx_init(struct cryptodev_ctx* ctx, int cfd, const uint8_t* key, unsigned int key_size) { #ifdef CIOCGSESSINFO struct session_info_op siop; #endif memset(ctx, 0, sizeof(*ctx)); ctx->cfd = cfd; ctx->sess.cipher = CRYPTO_AES_CBC; // use CRYPTO_SM4_CBC for SM4 CBC mode ctx->sess.keylen = key_size; ctx->sess.key = (void*)key; if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) { perror("ioctl(CIOCGSESSION)"); return -1; } #ifdef CIOCGSESSINFO memset(&siop, 0, sizeof(siop)); siop.ses = ctx->sess.ses; if (ioctl(ctx->cfd, CIOCGSESSINFO, &siop)) { perror("ioctl(CIOCGSESSINFO)"); return -1; } printf("Got %s with driver %s\n", siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name); if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)) { printf("Note: This is not an accelerated cipher\n"); } /*printf("Alignmask is %x\n", (unsigned int)siop.alignmask); */ ctx->alignmask = siop.alignmask; #endif return 0; }
key参数说明:
1)如果使用软件密钥,直接传入密钥的数据即可
2)如果使用硬件密钥,参考如下规则:
需要先烧录key到otp中,otpkey的生成方式以及烧录方式请参考 4.2.1 节
由于kernel原生没有选择是否使用otpkey的接口,程序会根据key的头部是否是特殊的字符序列"SStarU*"判断是否使用otpkey。
配置方法和对应关系如下表:
key keylen otpkey "SStarU\x01" 16 key128_1 "SStarU\x02" 16 key128_2 "SStarU\x03" 16 key128_3 "SStarU\x04" 16 key128_4 "SStarU\x01" 32 key256_1(key128_1+key128_2) "SStarU\x02" 32 key256_2(key128_3+key128_4) 例如使用otp key128_1,则key设置
unsigned char key[16] = {'S', 'S', 't', 'a', 'r', 'U', 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
注意:key长度需要满足16byte/32byte,前7byte数据需要按如上格式进行设置,其余位置的数据没有要求。
-
进行加解密
结构体说明
struct crypt_op { __u32 ses; /* session identifier */ __u16 op; /* COP_ENCRYPT or COP_DECRYPT */ __u16 flags; /* see COP_FLAG_* */ __u32 len; /* length of source data */ __u8 __user *src; /* source data */ __u8 __user *dst; /* pointer to output data */ /* pointer to output data for hash/MAC operations */ __u8 __user *mac; /* initialization vector for encryption operations */ __u8 __user *iv; };
加解密实例
int aes_encrypt(struct cryptodev_ctx* ctx, const void* iv, const void* plaintext, void* ciphertext, size_t size) { struct crypt_op cryp; void* p; /* check plaintext and ciphertext alignment */ if (ctx->alignmask) { p = (void*)(((unsigned long)plaintext + ctx->alignmask) & ~ctx->alignmask); if (plaintext != p) { fprintf(stderr, "plaintext is not aligned\n"); return -1; } p = (void*)(((unsigned long)ciphertext + ctx->alignmask) & ~ctx->alignmask); if (ciphertext != p) { fprintf(stderr, "ciphertext is not aligned\n"); return -1; } } memset(&cryp, 0, sizeof(cryp)); /* Encrypt data.in to data.encrypted */ cryp.ses = ctx->sess.ses; cryp.len = size; cryp.src = (void*)plaintext; cryp.dst = ciphertext; cryp.iv = (void*)iv; cryp.op = COP_ENCRYPT; if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) { perror("ioctl(CIOCCRYPT)"); return -1; } return 0; }
-
关闭session
void aes_ctx_deinit(struct cryptodev_ctx* ctx) { if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses)) { perror("ioctl(CIOCFSESSION)"); } }
-
关闭节点
/* Close the original descriptor */ if (close(cfd)) { perror("close(cfd)"); return 1; }
注意目前硬件加速只支持aes(ecb/cbc/ctr)以及sm4(ecb/cbc/ctr),如果需要使用其他算法,将使用软件解密。其中,硬件加速的aes/sm4对输入数据大小的对齐要求如下:
mode size alignment ecb 16 bytes cbc 1 bytes ctr 1 bytes 对输入数据的内存地址没有对齐要求,但使用aes的时候建议为16bytes对齐,可使得cryptodev开启zero copy功能,减少用户层与内核层之间的内存拷贝。
硬件加速AES支持key size为128/256 bit,硬件加速SM4支持的key size为128 bit。
5.2.2 hash运算接口¶
demo路径:drivers/sstar/cryptodev/examples/sha.c
drivers/sstar/cryptodev/examples/sm3.c
-
打开节点
int cfd = -1, i; /* Open the crypto device */ cfd = open("/dev/crypto", O_RDWR, 0); if (cfd < 0) { perror("open(/dev/crypto)"); return 1; } /* Set close-on-exec (not really needed here) */ if (fcntl(cfd, F_SETFD, 1) == -1) { perror("fcntl(F_SETFD)"); return 1; }
-
创建session
int sha_ctx_init(struct cryptodev_ctx* ctx, int cfd, const uint8_t* key, unsigned int key_size) { #ifdef CIOCGSESSINFO struct session_info_op siop; #endif memset(ctx, 0, sizeof(*ctx)); ctx->cfd = cfd; if (key == NULL) ctx->sess.mac = CRYPTO_SHA2_256; // use CRYPTO_SM3 for sm3 else { ctx->sess.mac = CRYPTO_SHA2_256_HMAC; ctx->sess.mackeylen = key_size; ctx->sess.mackey = (void*)key; } if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) { perror("ioctl(CIOCGSESSION)"); return -1; } #ifdef CIOCGSESSINFO siop.ses = ctx->sess.ses; if (ioctl(ctx->cfd, CIOCGSESSINFO, &siop)) { perror("ioctl(CIOCGSESSINFO)"); return -1; } printf("Got %s with driver %s\n", siop.hash_info.cra_name, siop.hash_info.cra_driver_name); if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)) { printf("Note: This is not an accelerated cipher\n"); } /*printf("Alignmask is %x\n", (unsigned int)siop.alignmask);*/ ctx->alignmask = siop.alignmask; #endif return 0; }
-
进行运算
结构体说明
struct crypt_op { __u32 ses; /* session identifier */ __u16 op; /* COP_ENCRYPT or COP_DECRYPT */ __u16 flags; /* see COP_FLAG_* */ __u32 len; /* length of source data */ __u8 __user *src; /* source data */ __u8 __user *dst; /* pointer to output data */ /* pointer to output data for hash/MAC operations */ __u8 __user *mac; /* initialization vector for encryption operations */ __u8 __user *iv; };
加解密实例
int sha_hash(struct cryptodev_ctx* ctx, const void* text, size_t size, void* digest) { struct crypt_op cryp; void* p; /* check text and ciphertext alignment */ if (ctx->alignmask) { p = (void*)(((unsigned long)text + ctx->alignmask) & ~ctx->alignmask); if (text != p) { fprintf(stderr, "text is not aligned\n"); return -1; } } memset(&cryp, 0, sizeof(cryp)); /* Encrypt data.in to data.encrypted */ cryp.ses = ctx->sess.ses; cryp.len = size; cryp.src = (void*)text; cryp.mac = digest; if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) { perror("ioctl(CIOCCRYPT)"); return -1; } return 0; }
-
关闭session
void sha_ctx_deinit(struct cryptodev_ctx* ctx) { if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses)) { perror("ioctl(CIOCFSESSION)"); } }
-
关闭节点
/* Close the original descriptor */ if (close(cfd)) { perror("close(cfd)"); return 1; }
注意目前硬件加速只支持sha256/sm3算法,如果使用其他算法(如sha1,md5)会调用软件算法。
5.2.3 rsa加解密接口¶
RSA加解密接口支持RSA512/1024/2048/4096(由于RSA512/1024的安全性较低,建议使用RSA2048/4096)。
demo路径:drivers/sstar/cryptodev/examples/cipher/cipher_rsa_sync.c
-
打开节点
int fd = -1; /* Open the crypto device */ fd = open("/dev/rsa", O_RDWR, 0); if (fd < 0) { perror("open(/dev/rsa)"); return 1; }
-
进行运算
结构体说明
struct rsa_config { unsigned int *pu32RSA_Sig; //the address of source data unsigned int *pu32RSA_KeyN; //the address of KeyN unsigned int *pu32RSA_KeyE; //the address of KeyE unsigned int *pu32RSA_Output; //the address of destination data unsigned int u32RSA_KeyNLen; //64->512,128->1024,256->2048,512->4096 unsigned int u32RSA_KeyELen; //64->512,128->1024,256->2048,512->4096 unsigned int u32RSA_SigLen; //64->512,128->1024,256->2048,512->4096 unsigned char u8RSA_pub_ekey; //0:pvivate key,1:public key };
加解密实例
static int test_rsa(int fd, struct rsa_config *prsa_config) { int i = 0; #if 1 // RSA calculate if (ioctl(fd, MDrv_RSA_Calculate, prsa_config)) { perror("ioctl(MDrv_RSA_Calculate)"); return 1; } #endif return 0; }
-
关闭节点
/* Close the original descriptor */ if (close(fd)) { perror("close(fd)"); return 1; }
其中,RSA对输入数据(pu32RSA_Sig)、KeyN(pu32RSA_KeyN)、KeyE(pu32RSA_KeyE)的大小要求如下:
RSA input size KeyN size KeyE size 512 64 bytes 64 bytes 64 bytes 1024 128 bytes 128 bytes 128 bytes 2048 256 bytes 256 bytes 256 bytes 4096 512 bytes 512 bytes 512 bytes
5.2.4 sm2加解密接口¶
SM2加解密的demo路径:drivers/sstar/cryptodev/examples/sm2.c
-
打开节点
int fd = -1; /* Open the crypto device */ fd = open("/dev/sm2", O_RDWR, 0); if (fd < 0) { perror("open(/dev/sm2)"); return 1; }
-
进行运算
结构体说明
typedef struct DRV_Sm2Config_s { unsigned char *pu8PrivKey; // private key unsigned char *pu8PubKeyX; // public key in X coordinate unsigned char *pu8PubKeyY; // public key in Y coordinate unsigned int u32KeyLen; // key length (unit: byte) unsigned char bDecrypt; // decryption flag (set 1 for decryption, 0 for encryption) unsigned char *pu8Input; // input data unsigned int u32InputLen; // input data length (unit: byte) unsigned char *pu8Output; // output data } DRV_Sm2Config_t;
加解密实例
int UtSm2Encrypt(int s32Fd, void* pInput, void* pOutput, unsigned int u32Len) { DRV_Sm2Config_t stCfg; stCfg.bDecrypt = 0; stCfg.pu8PubKeyX = g_u8PubKeyX; stCfg.pu8PubKeyY = g_u8PubKeyY; stCfg.u32KeyLen = UT_SM2_PRECISION * 4; stCfg.pu8Input = pInput; stCfg.u32InputLen = u32Len; stCfg.pu8Output = pOutput; if (ioctl(s32Fd, SM2_IOCTL_CRYPT, &stCfg)) { fprintf(stderr, "ioctl(SM2_IOCTL_CRYPT) failed\n"); return -1; } return 0; }
-
关闭节点
/* Close the original descriptor */ if (close(fd)) { perror("close(fd)"); return 1; }
其中,SM2加解密要求密钥长度为32 byte,支持的输入数据长度最大为 1MB。