cipher使用参考

REVISION HISTORY

Revision No.
Description
Date
1.00
  • Initial release
  • 04/18/2024

    1. uboot

    1.1 代码框架

    img

    1.2 cipher API接口解析

    1.2.1 aes加解密接口

    函数原型:

    @pConfigthe 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加密为例:

    1. 配置加解密数据源数据,目标数据地址和长度,aeskey类型和长度,aeskey地址(cipherkey need),是否设置iv和iv地址(cbc/ctr mode need),加密模式(ecb/cbc/ctr)。
    2. 使用MDrv_AESDMA_Run接口将配置写入寄存器并触发。
    3. 加密完成的数据可以在地址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 ,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_KEY5 16 key128_5
    E_AESDMA_KEY_OTP_EFUSE_KEY6 16 key128_6
    E_AESDMA_KEY_OTP_EFUSE_KEY7 16 key128_7
    E_AESDMA_KEY_OTP_EFUSE_KEY8 16 key128_8
    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)
    E_AESDMA_KEY_OTP_EFUSE_KEY3 32 key256_3(key128_5+key128_6)
    E_AESDMA_KEY_OTP_EFUSE_KEY4 32 key256_4(key128_7+key128_8)

    1.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为例:

    1. 配置加解密数据源数据,目标数据地址和长度,加密模式(sha1/sha256)。
    2. 使用MDrv_SHA_Run接口将配置写入寄存器并触发。
    3. 加密完成的数据可以在地址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)))关键字进行定义。

    1.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为例:

    1. 配置加解密数据源数据,目标数据地址和长度,KeyN,KeyE,KeyLen,类型(公钥,私钥)等。
    2. 使用MDrv_RSA_Run接口将配置写入寄存器并触发。
    3. 加密完成的数据可以在地址pu16Output中读取到,rsa2048长度为256byte,rsa4096长度为512byte。
    char 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 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 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 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 rsa_encrypt_out[256];
        U8 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");
        }
    }
    

    注意:非对称加密算法中,有两个密钥:公钥和私钥。它们是一对,如果用公钥进行加密,只有用对应的私钥才能解密;如果用私钥进行加密,只有用对应的公钥才能解密。

    2. kernel

    2.1 config设定

    img

    2.2 代码框架

    img

    2.3 userspace下访问接口

    通过用户层ioctl访问kernel。

    • aes, sha:借助模块cryptodev,它提供了一种通用的加密API,使应用程序能够利用硬件加速的加密功能。可以通过打开 /dev/crypto 设备文件来访问加密功能。应用程序可以使用常见的加密算法(如AES、DES等)和模式(如CBC、ECB、CTR等)来执行加密和解密操作。

    rsa

    • rsa:Kernel原生接口中不支持RSA算法,故RSA使用Linux标准接口注册misc类设备,产生/dev/rsa, User Space可通过节点使用Hardware RSA算法。

    2.3.1 aes加解密接口

    demo路径:drivers/sstar/crypto/cryptodev/examples/aes.c

    1. 打开节点

      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;
      }
      
    2. 创建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;
          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;
      }
      
    3. 进行加解密

      结构体说明

      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;
      }
      
    4. 关闭session

      void aes_ctx_deinit(struct cryptodev_ctx* ctx)
      {
          if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses))
          {
              perror("ioctl(CIOCFSESSION)");
          }
      }
      
    5. 关闭节点

      /* Close the original descriptor */
      if (close(cfd))
      {
          perror("close(cfd)");
          return 1;
      }
      

    注意目前硬件加速只支持aes(ecb/cbc/ctr),如果需要使用其他算法,将使用软件解密。其中,硬件加速的aes对输入数据大小的对齐要求如下:

    mode size alignment
    ecb 16 bytes
    cbc 1 bytes
    ctr 1 bytes

    对输入数据的内存地址没有对齐要求,但使用aes的时候建议为16bytes对齐,可使得cryptodev开启zero copy功能,减少用户层与内核层之间的内存拷贝。 硬件加速AES支持key size为128 / 256 bit。

    otpkey作为密钥

    由于kernel原生没有选择是否使用otpkey的接口,程序会根据key的头部是否是特殊的字符序列"SStarU*"判断是否使用otpkey。

    如果需要以otpkey作为密钥,需要提前烧录OTP_AES128_KEY ,OTP中AESKEY256实际上是由OTP中两把AES128组合而成,组合和设置方式举例如下。

    欲设置

    KEY256_1:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F

    需设置

    key128_1:000102030405060708090A0B0C0D0E0F key128_2:101112131415161718191A1B1C1D1E1F

    配置方法和对应关系如下表:

    key keylen otpkey
    "SStarU1" 16 key128_1
    "SStarU2" 16 key128_2
    "SStarU3" 16 key128_3
    "SStarU4" 16 key128_4
    "SStarU5" 16 key128_5
    "SStarU6" 16 key128_6
    "SStarU7" 16 key128_7
    "SStarU8" 16 key128_8
    "SStarU1" 32 key256_1(key128_1+key128_2)
    "SStarU2" 32 key256_2(key128_3+key128_4)
    "SStarU3" 32 key256_3(key128_5+key128_6)
    "SStarU4" 32 key256_4(key128_7+key128_8)

    2.3.2 hash运算接口

    demo路径:drivers/sstar/crypto/cryptodev/examples/sha.c

    1. 打开节点

      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;
      }
      
    2. 创建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;
          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;
      }
      
    3. 进行运算

      结构体说明

      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;
      }
      
    4. 关闭session

      void sha_ctx_deinit(struct cryptodev_ctx* ctx)
      {
          if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses))
          {
              perror("ioctl(CIOCFSESSION)");
          }
      }
      
    5. 关闭节点

      /* Close the original descriptor */
      if (close(cfd))
      {
          perror("close(cfd)");
          return 1;
      }
      

    注意目前硬件加速只支持sha256算法,如果使用其他算法(如sha1,md5)会调用软件算法。

    2.3.3 rsa加解密接口

    RSA加解密接口支持RSA512/1024/2048/4096(由于RSA512/1024的安全性较低,建议使用RSA2048/4096),demo路径:drivers/sstar/crypto/cryptodev/examples/cipher/cipher_rsa_sync.c

    1. 打开节点

      int fd  = -1;
      
      /* Open the crypto device */
      fd = open("/dev/rsa", O_RDWR, 0);
      if (fd < 0)
      {
          perror("open(/dev/rsa)");
          return 1;
      }
      
    2. 进行运算

      结构体说明

      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;
      }
      
    3. 关闭节点

      /* 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