Skip to content

cipher User Guide

REVISION HISTORY

Revision No.
Description
Date
1.00
  • Initial release
  • 06/12/2024

    1. Overview

    cipher module, which can be used for AES encryption and decryption, SHA calculation, RSA encryption and decryption, and digital signature verification.

    2. Keyword description

    • AESDMA

      Hardware module for encryption and decryption calculations.

    3. Function description

    • aes

      Supports AES128/AES192/AES256 encryption and decryption algorithms; modes include ECB/CBC/CTR modes; supports hardware key and software key usage.

    • hash

      Supports SHA1/SHA256 algorithms, input data length is unlimited.

    • rsa

      Supports RSA2048/RSA4096 encryption and decryption, signing and verification; supports the use of hardware keys and software keys.


    4. Uboot

    4.1. Code Framework

    img

    4.2. Cipher API Interface Description

    4.2.1 AES Encryption and Decryption Interface

    Function prototype:

        @pConfig: the config of configurating aes hardware
        void MDrv_AESDMA_Run(aesdmaConfig* pConfig);
    

    Description of the aesdmaConfig structure fields:

    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;
    

    A demo code is placed under the path: cmd/sstar/aes.c

    Take cbc encryption as an example:

    1. Configure encryption and decryption source data, target data address and length, aeskey type and length, aeskey address (required by cipherkey), whether to set IV and IV address (required in cbc/ctr mode), and encryption mode (ecb/cbc/ctr).
    2. Use the MDrv_AESDMA_Run interface to write the configuration to the register and trigger.
    3. The encrypted data can be read at the address config.u64DstAddr, and the length is 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");
        }
    }
    

    Note: The length of the encrypted data in ECB mode must be aligned to 16 bytes.

    otpkey as a key

    If you need to use otpkey as a key, you need to burn OTP_AES128_KEY in advance.

    AESKEY256 in OTP is actually composed of two AES128 keys in OTP. The combination and setting method are as follows.

    Want to set: KEY256_1:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F

    Need to set: key128_1:000102030405060708090A0B0C0D0E0F key128_2:101112131415161718191A1B1C1D1E1F

    The configuration methods and corresponding relationships are as follows:

    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)

    4.2.2 Hash Operation Interface

    @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)
    

    A demo code is placed under the path: cmd/sstar/aes.c

    Take sha256 as an example:

    1. Configure encryption and decryption source data, target data address and length, and encryption mode (sha1/sha256).
    2. Use the MDrv_SHA_Run interface to write the configuration to the register and trigger.
    3. The encrypted data can be read at the address pu16Output. The length of sha1 is 10-byte and the length of sha256 is 16-byte.
    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");
        }
    }
    

    Note: The u64SrcAddr of sha must be 16-byte aligned. Please use the __attribute__((aligned(16))) keyword to define the source data.

    4.2.3 RSA Encryption and Decryption Interface

    @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;
    

    Note: RSA only loads the hw key once when it is powered on, which is used for signature verification in the rom code stage. After that, the hw key cannot be used.

    A demo code is placed under the path: cmd/sstar/aes.c

    Take rsa2048 as an example:

    1. Configure encryption and decryption source data, target data address and length, KeyN, KeyE, KeyLen, and type (public key, private key), etc.
    2. Use the MDrv_RSA_Run interface to write the configuration to the register and trigger.
    3. The encrypted data can be read at the address pu16Output. The length of rsa2048 is 256-byte and the length of rsa4096 is 512-byte.
    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");
        }
    }
    

    Note: There are two keys in an asymmetric encryption algorithm: public key and private key. They are a pair. If a public key is used to encrypt, only only the corresponding private key can be used to decrypt; if a private key is used to encrypt, only the corresponding public key can be used to decrypt.

    5. Kernel

    5.1 Config Setting

    img

    5.2 Code Framework

    img

    5.3 Accessing Interface in Userspace

    Accessing the kernel through user layer ioctl:

    • aes, sha: With the natively provided kernel module cryptodev, it provides a universal encryption API that enables applications to utilize the hardware-accelerated encryption functions. The crypto functionality can be accessed by opening the /dev/crypto device file. Applications can perform encryption and decryption operations using common encryption algorithms (such as AES, DES, etc.) and modes (such as CBC, ECB, CTR, etc.).

    RSA

    • rsa: The kernel's native interface does not support the RSA algorithm, so RSA uses the Linux standard interface to register misc-type devices and generate /dev/rsa nodes. User Space can use the Hardware RSA algorithm through the nodes.

    5.3.1 AES Encryption and Decryption Interface

    A demo code is placed under the path: drivers/sstar/crypto/cryptodev/examples/aes.c

    1. Open the node.

      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. Create a 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;
      }
      

      Parameter key description:

      1) If using a software key, you can directly pass in the key data

      2) If hardware keys are used, refer to the following rules

      First, you need to burn the key to the OTP.

      Since the kernel native interface does not select whether to use otpkey, the program will determine whether to use otpkey based on whether the key header is a special character sequence "SStarU*".

      The configuration methods and corresponding relationships are shown in the following table:

      key keylen otpkey
      "SStarU\x01" 16 key128_1
      "SStarU\x02" 16 key128_2
      "SStarU\x03" 16 key128_3
      "SStarU\x04" 16 key128_4
      "SStarU\x05" 16 key128_5
      "SStarU\x06" 16 key128_6
      "SStarU\x07" 16 key128_7
      "SStarU\x08" 16 key128_8
      "SStarU\x01" 32 key256_1(key128_1+key128_2)
      "SStarU\x02" 32 key256_2(key128_3+key128_4)
      "SStarU\x03" 32 key256_3(key128_5+key128_6)
      "SStarU\x04" 32 key256_4(key128_7+key128_8)

      For example, if using the OTP key 128_1, then the key is set:

      unsigned char key[16] = {'S', 'S', 't', 'a', 'r', 'U', 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
      

      Note: The key length needs to meet 16 bytes/32 bytes, the first 7 bytes of data need to be set according to the above format, and the data in the remaining positions are not required.

    3. Perform encryption and decryption.

      Structure description:

      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;
      };
      

      Encryption and decryption example:

      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. Close the session.

      void aes_ctx_deinit(struct cryptodev_ctx* ctx)
      {
          if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses))
          {
              perror("ioctl(CIOCFSESSION)");
          }
      }
      
    5. Close the node.

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

      Note that currently hardware acceleration only supports aes (ecb/cbc/ctr). If other algorithms are required, software decryption will be used. The aes of hardware accelerated has the following alignment requirements for the input data size:

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

      There is no alignment requirement for the memory address of the input data, but it is recommended to align to 16 bytes when using aes, which can enable the zero copy function of cryptodev to reduce the memory copy between the user layer and the kernel layer.

      Hardware accelerated AES supports key sizes of 128/256 bits.

    5.3.2 Hash Operation Interface

    A demo code is placed under the path: drivers/sstar/crypto/cryptodev/examples/sha.c

    1. Open the node.

      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. Create a 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. Perform calculations.

      Structure description:

      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;
      };
      

      Encryption and decryption example:

      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. Close the session.

      void sha_ctx_deinit(struct cryptodev_ctx* ctx)
      {
          if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses))
          {
              perror("ioctl(CIOCFSESSION)");
          }
      }
      
    5. Close the node.

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

      Note that currently hardware acceleration only supports sha256 algorithm. If other algorithms (such as sha1 or md5) are employed, software decryption will be used.

    5.3.3 RSA Encryption and Decryption Interface

    The RSA encryption and decryption interface supports RSA512/1024/2048/4096 (Due to the low security of RSA512/1024, it is recommended to use RSA2048/4096). A demo code is placed under the path: drivers/sstar/crypto/cryptodev/examples/cipher/cipher_rsa_sync.c

    1. Open the node.

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

      Structure description:

      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
      };
      

      Encryption and decryption example:

      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 node.

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

      Among them, RSA requires the size of input data (pu32RSA_sig), KeyN (pu32RSA_KeyN), and KeyE (pu32RSA_KeyE) as follows:

      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