CIPHER USER GUIDE

REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 04/18/2024
    1.1
  • Document architecture optimization
  • 04/11/2025

    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.

    • sm⅔/4

      Support SM⅔/4 algorithm


    4. UBOOT

    4.1 Code Framework and Config

    4.1.1 Code Framework

    img

    4.1.2 Uboot Config

    Open the following configuration under uboot:

    [*] SigmaStar drivers  --->
        [*]   SigmaStar AESDMA
    

    4.2. Cipher API Interface Analysis

    4.2.1 AES Encryption and Decryption Interface

    Function prototype:

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

    AESDMAConfig structure field explanation:

    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 path: cmd/sstar/aes.c.

    Take cbc encryption as an example:

    1. Configure the encryption and decryption data source data, target data address and length, aeskey type and length, aeskey address (cipherkey need), whether to set iv and iv address (cbc/ctr mode need), encryption mode (ecb/cbc/ctr).
    2. Use the MDrv_AESDMA_Run interface to write the configuration to the register and trigger it.
    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. For the specific generation and burning methods of otpkey, please refer to Chapter 2 of the Secureboot User Manual: Security_Boot_zh.md, for inquiries about the Security_Boot_zh.md document, please consult the FAE window.

    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 shown in the following table:

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

    Demo path: cmd/sstar/aes.c.

    Take sha256 as an example:

    1. Configure the encryption and decryption data source data, target data address and length, encryption mode (sha1/sha256).
    2. Use the MDrv_SHA_Run interface to write the configuration to the register and trigger it.
    3. The encrypted data can be read at the address pu16Output. The length of sha1 is 10 bytes and the length of sha256 is 16 bytes.
    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: sha's u64SrcAddr 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 hw key once when powered on, which is used for signature verification in the rom code stage. After that, hw key cannot be used.

    Demo path: cmd/sstar/aes.c.

    Take rsa2048 as an example:

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

    Note: In an asymmetric encryption algorithm, there are two keys: a public key and a private key. They are a pair. If you encrypt with a public key, you can only decrypt with the corresponding private key; if you encrypt with a private key, you can only decrypt with the corresponding public key.

    4.2.4 SM⅔/4 Encryption and Decryption Interface

    uboot currently does not support sm⅔/4 encryption and decryption.

    5. KERNEL

    5.1. Code Framework and Kernel Config

    5.1.1 Code Framework

    img

    Figure 2-1: Cipher_02

    5.1.2 Kernel Config

    Open the following configuration under kernel to use aesdma normally.

    Device Drivers  --->
        [*] Sstar SoC platform drivers  --->
            <*>   SigmaStar Crypto driver
                [*]     HW_RANDOM Random Number Generator support
            <*>   Support cryptodev
    

    5.2. Access Interface in Userspace

    Access the kernel through user-level ioctl.

    • aes, sha, sm3, sm4: With the help of the module cryptodev, it provides a general encryption API that enables applications to take advantage of hardware-accelerated encryption functions. Encryption functions can be accessed by opening the /dev/crypto device file. Applications can use common encryption algorithms (such as AES, DES, etc.) and modes (such as CBC, ECB, CTR, etc.) to perform encryption and decryption operations.

    rsa, sm2

    • rsa, sm2: RSA/SM2 algorithms are not supported in the kernel native interface, so RSA/SM2 uses the Linux standard interface to register misc class devices, generating /dev/rsa and /dev/sm2 nodes, and User Space can use Hardware RSA/SM2 algorithms through nodes.

    5.2.1 aes/sm4 Encryption and Decryption Interface

    Demo path: drivers/sstar/cryptodev/examples/aes.c drivers/sstar/cryptodev/examples/sm4.c.

    use otpkey demo path:drivers/sstar/cryptodev/examples/aes-sstar-unique.c.

    1. Open notes

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

      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, the generation method and burning method of otpkey please refer to Section 4.2.1.

      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\x01" 32 key256_1(key128_1+key128_2)
      "SStarU\x02" 32 key256_2(key128_3+key128_4)

      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 examples

      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 session

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

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

      Note that currently hardware acceleration only supports aes (ecb/cbc/ctr) and sm4 (ecb/cbc/ctr). If other algorithms are required, software decryption will be used. The aes/sm4 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, and hardware accelerated SM4 supports key sizes of 128 bits.

    5.2.2 Hash Operation Interface

    Demo path: drivers/sstar/cryptodev/examples/sha.c drivers/sstar/cryptodev/examples/sm3.c

    1. Open nodes

      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 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;
      }
      
    3. Perform operation

      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 examples

      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 session

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

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

      Note that currently hardware acceleration only supports sha256/sm3 algorithms. If other algorithms (such as sha1, md5) are used, the software algorithm will be called.

    5.2.3 RSA Encryption and Decryption Interface

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

    demo path: drivers/sstar/cryptodev/examples/cipher/cipher_rsa_sync.c.

    1. Open nodes

      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 operation

      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 examples

      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 nodes

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

      Among them, RSA has the following requirements for the size of input data (pu32RSA_Sig), KeyN (pu32RSA_KeyN), and 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 Encryption and Decryption Interface

    SM2 encryption and decryption demo path: drivers/sstar/cryptodev/examples/sm2.c.

    1. Open nodes

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

      Structure description

      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;
      

      Encryption and decryption examples

      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;
      }
      
    3. Close nodes

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

      Among them, SM2 encryption and decryption requires a key length of 32 bytes and supports a maximum input data length of 1MB.