跳转至

cipher使用参考


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 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加解密,签章验签;支持使用硬件密钥以及软件密钥

    • sm2/sm3/sm4

      支持国密sm2/sm3/sm4算法

    • ECC160/192/256/384/512/521

      支持椭圆曲线算法ECC160/192/256/384/512/521

    4. Uboot用法介绍

    4.1 代码框架和config

    4.1.1 代码框架

    img

    4.1.2 uboot config

    uboot下打开以下配置
    
    [*] Sgs SoC platform drivers  --->
    
        [*]   Sgs Crypto driver
    

    4.2 cipher API接口解析

    uboot下cipher api接口使用方法与kernel下的api用法一致,api介绍请参考5.3章节。

    demo请参考cmd/sgs/aes.c文件中 do_verifyaes 接口的测试用例。

    5. Kernel用法介绍

    5.1 代码框架和kernel config

    5.1.1 代码框架

    img

    5.1.2 kernel config

    kernel下打开以下配置,才可正常使用aesdma.
    
    Device Drivers  --->
    
        [*] Sgs SoC platform drivers  --->
            <*>   Sgs Crypto driver
                [*]     HW_RANDOM Random Number Generator support
                [*]     Enable aesdma debug node
                [ ]     crypto in optee
            <*>   Support cryptodev
    

    5.2 userspace下访问接口

    通过用户层ioctl访问kernel。

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

    rsa, sm2, ecc

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

    5.2.1 aes/sm4加解密接口

    demo路径:drivers/sgs_common/cryptodev/examples/aes.c drivers/sgs_common/cryptodev/examples/sm4.c

    使用otpkey的demo:drivers/sgs_common/cryptodev/examples/aes-sgs-unique.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;  // 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)如果使用硬件密钥,参考如下规则:

      具体otpkey的生成以及烧录方式请参考Secureboot使用文档:Security_Boot使用参考文档中的第2章 OTP Key读写操作说明,关于Security_Boot使用参考文档可以咨询FAE窗口。

      OTP中AESKEY256实际上是由OTP中两把AES128组合而成,组合和设置方式举例如下。

      欲设置:

      KEY256_1:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F

      需设置:

      key128_1:000102030405060708090A0B0C0D0E0F

      key128_2:101112131415161718191A1B1C1D1E1F

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

      eKeyType keylen corresponding otpkey
      DRV_SKCIPHER_KEY_SEL_HW_1 16 key128_1
      DRV_SKCIPHER_KEY_SEL_HW_2 16 key128_2
      DRV_SKCIPHER_KEY_SEL_HW_3 16 key128_3
      DRV_SKCIPHER_KEY_SEL_HW_4 16 key128_4
      DRV_SKCIPHER_KEY_SEL_HW_1 32 key256_1(key128_1+key128_2)
      DRV_SKCIPHER_KEY_SEL_HW_2 32 key256_2(key128_3+key128_4)

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

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

      key keylen otpkey
      "SGSKEYN\x01" 16 key128_1
      "SGSKEYN\x02" 16 key128_2
      "SGSKEYN\x03" 16 key128_3
      "SGSKEYN\x04" 16 key128_4
      "SGSKEYN\x01" 32 key256_1(key128_1+key128_2)
      "SGSKEYN\x02" 32 key256_2(key128_3+key128_4)

      例如使用otp key128_1,则key设置

      unsigned char key[16] = {'S', 'G', 'S', 'K', 'E', 'Y', 'N', 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
      

      注意:key长度需要满足16byte/32byte,前8byte数据需要按如上格式进行设置,其余位置的数据没有要求。

    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)以及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/sgs_common/cryptodev/examples/sha.c drivers/sgs_common/cryptodev/examples/sm3.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; // 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. 进行运算

      结构体说明

      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/sm3算法,如果使用其他算法(如sha1,md5)会调用软件算法。

    5.2.3 rsa加解密接口

    RSA加解密接口支持RSA512/1024/2048/4096(由于RSA512/1024的安全性较低,建议使用RSA2048/4096)。

    demo路径:drivers/sgs_common/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

    5.2.4 sm2/ECC加解密接口

    SM2/ECC加解密的demo路径:drivers/sgs_common/cryptodev/examples/cipher/cipher_sm2_sync.c

    1. 打开节点

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

      结构体说明

      typedef struct drv_sm2_config_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   u8Mode;      // 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
          unsigned char * pu8Sign;     // Signature data
          drv_sm2_curve_e ecurve;      //Curve parameters
      } drv_sm2_config_t;
      

      加解密实例

      int UtSm2Encrypt(int s32Fd, void *pInput, void *pOutput, unsigned int u32Len)
      {
          drv_sm2_config_t stCfg;
      
          stCfg.u8Mode      = 0;
          stCfg.ecurve      = E_DRV_SM2_CURVE_DEFAULT;
          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 the original descriptor */
      if (close(fd))
      {
          perror("close(fd)");
          return 1;
      }
      

      其中,SM2加解密要求密钥长度为32 byte,支持的输入数据长度最大为 1MB。

    5.3. kernel space使用Crypto模块提供的API接口

    API名称 功能
    drv_skcipher_run aes/sm4加解密接口
    drv_hash_run hash计算接口
    drv_akcipher_run rsa/sm2加解密接口
    drv_rng_read rng值读取接口
    run_decrypt 数据解密接口
    run_authenticate2 数据验签接口
    run_authenticate 数据验签接口

    5.3.1. drv_skcipher_run

    • 目的

      对数据进行aes/sm4加密或者解密

    • 语法

      u32 drv_skcipher_run(drv_skcipher_config *config)

    • 参数

      参数名称 描述
      config aes加解密过程使用的配置信息,包括数据地址信息,加解密信息等
      typedef struct
      {
          drv_skcipher_key_sel    key_sel;    // select key
          u8                      swkey[DRV_SKCIPHER_KEY_LEN_256]; // software key,max 256
          drv_skcipher_key_len    key_len;    // skcipher key len
          drv_skcipher_alg_type   alg_type;   // skcipher algtype
          drv_skcipher_op_mode    op_mode;    // skcipher alg mode
          drv_skcipher_op_dir     op_dir;     // decrypt or encrypt
          drv_skcipher_mround_num mround_num; // aesdma multiround num
          u64                     src_phys;   // src phys addr
          u64                     dst_phys;   // dst phys addr
          u8 *                    src_virt;   // src virt addr
          u8 *                    dst_virt;   // dst virt addr
          u32                     len;        // plaintext len
          u8 *                    iv;         // (CBC/CTR need)iv value
          u8                      async;      // 0:sync,1:async
      } __attribute__((aligned(16))) drv_skcipher_config;
      
    • 返回值

      返回值 描述
      config->len 加密或解密后数据的长度
      0 加解密失败
      1 参数错误
    • 注意

      • 使用该接口可参考drivers/sgs_common/crypto/ut/lnx/ut_aes.c。

        在测试aesdma之前,需要先执行以下内容来开启aesdma的时钟:

        打开CONFIG_SGS_AESDMA_DEBUG
        echo aesdma_clk_state=1 > /sys/bus/platform/devices/soc:aesdma/debug
        echo rng_clk_state=1 > /sys/bus/platform/devices/soc:aesdma/debug
        
      • skcipher 密钥类型:

        key macro support
        SW KEY DRV_SKCIPHER_KEY_SEL_SW YES
        HW KEY 1 DRV_SKCIPHER_KEY_SEL_HW_1 YES
        HW KEY 2 DRV_SKCIPHER_KEY_SEL_HW_2 YES
        HW KEY 3 DRV_SKCIPHER_KEY_SEL_HW_3 YES
        HW KEY 4 DRV_SKCIPHER_KEY_SEL_HW_4 YES
        HW KEY 5 DRV_SKCIPHER_KEY_SEL_HW_5 YES
        HW KEY 6 DRV_SKCIPHER_KEY_SEL_HW_6 YES
        HW KEY 7 DRV_SKCIPHER_KEY_SEL_HW_7 YES
        HW KEY 8 DRV_SKCIPHER_KEY_SEL_HW_8 YES
        key sel key
        0 SW KEY
        1 key1:1st HW key for aes128;{key1+key2 for aes256}
        2 key2:2nd HW key for aes128;{key2+key3 for aes256}
        3 key3:3rd HW key for aes128;{key3+key4 for aes256}
        4 key4:4th HW key for aes128;{key4+key5 for aes256}
        5 key5:5th HW key for aes128;{key5+key6 for aes256}
        6 key6:6th HW key for aes128;{key6+key7 for aes256}
        7 key7:7th HW key for aes128;{key7+key8 for aes256}
        8 key8:8th HW key for aes128;{key8+key1 for aes256}
      • skcipher 算法类型:

        alg type macro support
        AES DRV_SKCIPHER_ALG_TYPE_AES YES
        DES DRV_SKCIPHER_ALG_TYPE_DES YES
        TDES DRV_SKCIPHER_ALG_TYPE_TDES YES
        SM4 DRV_SKCIPHER_ALG_TYPE_SM4 YES
      • skcipher 密钥长度:

        key len macro support
        64bit DRV_SKCIPHER_KEY_LEN_64 YES
        128bit DRV_SKCIPHER_KEY_LEN_128 YES
        192bit DRV_SKCIPHER_KEY_LEN_192 YES
        256bit DRV_SKCIPHER_KEY_LEN_256 YES

        AES算法长度可以选择128bit,192bit,256bit

        DES算法长度固定为64bit

        TDES算法长度固定为192bit,且只能使用ABA模式,即最后密钥64bit要和前64bit一致。

        SM4算法长度固定为128bit

      • skcipher 操作模式:

        operate mode macro support
        ECB DRV_SKCIPHER_OP_MODE_ECB YES
        CBC DRV_SKCIPHER_OP_MODE_CBC YES
        CTR DRV_SKCIPHER_OP_MODE_CTR YES
      • skcipher 加密or解密:

        operate dir macro support
        COPY DRV_SKCIPHER_OP_DIR_COPY NO
        ENCRYPT DRV_SKCIPHER_OP_DIR_ENCRYPT YES
        DECRYPT DRV_SKCIPHER_OP_DIR_DECRYPT YES
      • skcipher 重复计算次数:

        operate dir macro support
        Multi Round 1 DRV_SKCIPHER_MROUND_NUM_1 YES
        Multi Round 2 DRV_SKCIPHER_MROUND_NUM_2 YES
        Multi Round 3 DRV_SKCIPHER_MROUND_NUM_3 YES
        Multi Round 4 DRV_SKCIPHER_MROUND_NUM_4 YES

    5.3.2. drv_hash_run

    • 目的

      对数据进行哈希计算

    • 语法

      u32 drv_hash_run(drv_hash_config *config)

    • 参数

      参数名称 描述
      config 数据进行hash计算的配置信息
      typedef struct
      {
          drv_hash_alg_type  alg_type;    // hash alg type
          drv_hash_work_mode work_mode;   // auto or manual mode
          drv_hash_state *   ctx;         // hash state
          u64                src_phys;    // src phys addr
          u8 *               src_virt;    // src virt addr
          u8 *               digest;      // hash result addr
          u32                len;         // plaintext len
          u8                 async;       // 0:sync,1:async
      } __attribute__((aligned(16))) drv_hash_config;
      
    • 返回值

      返回值 描述
      0 成功
      1 失败
    • 注意

      • 使用该接口可参考drivers/sgs_common/crypto/ut/lnx/ut_aes.c。

        在测试aesdma之前,需要先执行以下内容来开启aesdma的时钟:

        打开CONFIG_SGS_AESDMA_DEBUG
        echo aesdma_clk_state=1 > /sys/bus/platform/devices/soc:aesdma/debug
        echo rng_clk_state=1 > /sys/bus/platform/devices/soc:aesdma/debug
        
      • hash 算法类型:

        alg type macro support
        SHA1 DRV_HASH_ALG_TYPE_SHA1 YES
        SHA256 DRV_HASH_ALG_TYPE_SHA256 YES
        SM3 DRV_HASH_ALG_TYPE_SM3 YES
      • hash 计算模式:

        mode macro support
        AUTO DRV_HASH_WORK_MODE_AUTO YES
        MANUAL DRV_HASH_WORK_MODE_MANUAL YES

    5.3.3. drv_akcipher_run

    • 目的

      rsa/sm2加解密接口

    • 语法

      u32 drv_akcipher_run(drv_akcipher_config *config)

    • 参数

      参数名称 描述
      config 数据进行rsa加解密的配置信息
      typedef struct
      {
          drv_akcipher_key_sel  key_sel;   // select key
          drv_akcipher_alg_type alg_type;  // akcipher alg type
          drv_akcipher_key_len  key_n_len; // key_n_len or ecc precision
          u8                    async;     // 0:sync,1:async
          union
          {
              struct
              {
                  DRV_AKCIPHER_KEY_TYPE key_type; // public key or private key
                  u8 *                  key_n;    // RSA N key addr
                  u8 *                  dst_virt; // dst virt addr
                  u8 *                  key_e;    // RSA E key addr
                  u32                   key_e_len;// RSA E key len
                  u8 *                  src_virt; // src virt addr
                  u32                   data_len; // plaintext len
              } rsa;
              struct
              {
                  /* For the specific parameters of ECC,
                          please refer to the formula below. */
                  drv_sm2_curve *curve;           // ecc curve addr
                  drv_sm2_point *point_out;       // output poinit
                  drv_sm2_point *point_g;         // g point
                  drv_sm2_point *point_p;         // p point
                  u32 *          K;               // K
                  u32 *          S;               // S
                  u32 *          T;               // T
                  u32 *          in_curve;        // 0:not in curve,1:in curve
              } ecc;
          };
      } __attribute__((aligned(16))) drv_akcipher_config;
      
    • 返回值

      返回值 描述
      0 成功
      1 失败
    • 注意

      • 使用该接口可参考drivers/sgs_common/crypto/ut/lnx/ut_aes.c。

        在测试aesdma之前,需要先执行以下内容来开启aesdma的时钟:

        打开CONFIG_SGS_AESDMA_DEBUG
        echo aesdma_clk_state=1 > /sys/bus/platform/devices/soc:aesdma/debug
        echo rng_clk_state=1 > /sys/bus/platform/devices/soc:aesdma/debug
        
      • akcipher 密钥类型(software key or hardware key):

        key macro support
        SW KEY DRV_AKCIPHER_KEY_SEL_SW YES
        HW KEY DRV_AKCIPHER_KEY_SEL_HW NO
      • akcipher 密钥类型(public key or private key):

        key macro support
        PRIVATE KEY DRV_AKCIPHER_KEY_TYPE_PRI YES
        PUBLIC KEY DRV_AKCIPHER_KEY_TYPE_PUB YES
      • akcipher 算法类型:

        alg type macro support
        RSA DRV_AKCIPHER_ALG_TYPE_RSA YES
        ECC MULT DRV_AKCIPHER_ALG_TYPE_ECC_POINT_MULT YES
        ECC MULT AND ADD DRV_AKCIPHER_ALG_TYPE_ECC_POINT_MULT_AND_ADD YES
        ECC VERIFY DRV_AKCIPHER_ALG_TYPE_ECC_POINT_VERIFY YES
      • akcipher N KEY长度:

        N key len macro support
        256byte DRV_AKCIPHER_KEY_LEN_RSA2048 YES
        256byte DRV_AKCIPHER_KEY_LEN_RSA4096 YES
        20byte DRV_AKCIPHER_KEY_LEN_ECC160 YES
        24byte DRV_AKCIPHER_KEY_LEN_ECC192 YES
        28byte DRV_AKCIPHER_KEY_LEN_ECC224 YES
        32byte DRV_AKCIPHER_KEY_LEN_ECC255 YES
        32byte DRV_AKCIPHER_KEY_LEN_ECC256 YES
        40byte DRV_AKCIPHER_KEY_LEN_ECC320 YES
        48byte DRV_AKCIPHER_KEY_LEN_ECC384 YES
        64byte DRV_AKCIPHER_KEY_LEN_ECC512 YES
        68byte DRV_AKCIPHER_KEY_LEN_ECC521 YES

    5.3.4. drv_rng_read

    • 目的

      读取硬件随机数

    • 语法

      u16 drv_rng_read(void);

    • 参数

      参数名称 描述
    • 返回值

      返回值 描述
      value 16位的硬件随机数
      0 获取硬件随机数失败
    • 注意·

      • 使用该接口可参考drivers/sgs_common/crypto/ut/lnx/ut_aes.c。

        在测试aesdma之前,需要先执行以下内容来开启aesdma的时钟:

        打开CONFIG_SGS_AESDMA_DEBUG
        echo aesdma_clk_state=1 > /sys/bus/platform/devices/soc:aesdma/debug
        echo rng_clk_state=1 > /sys/bus/platform/devices/soc:aesdma/debug
        

    5.3.5. run_decrypt

    • 目的

      对指定数据进行解密,结果保存在数据源地址中

    • 语法

      void run_decrypt(u64 u64ImageAddr, u32 u32ImageSize, u32 u32KeySel, u16 *pu16Key, u32 keylen)

    • 参数

      参数名称 描述
      u64ImageAddr input data start address
      u32ImageSize input data size
      u32KeySel aes(ecb) key number
      pu16Key aes(ecb) sw key
      keylen key len
    • 返回值

      返回值 描述
    • 注意

      • 使用该接口可参考drivers/sgs_common/crypto/os/rtk/drv_aesdma_test.c中的run_auth_test测试接口。

        在测试aesdma之前,需要先执行以下内容来开启aesdma的时钟:

        打开CONFIG_SGS_AESDMA_DEBUG
        echo aesdma_clk_state=1 > /sys/bus/platform/devices/soc:aesdma/debug
        echo rng_clk_state=1 > /sys/bus/platform/devices/soc:aesdma/debug
        
      • 在run_decrypt中,固定为 AES(ECB) 的解密模式,可以使用sw key和hw key

    5.3.6. run_authenticate2

    • 目的

      数据验签接口

    • 语法

      u8 run_authenticate2(u64 u64ImageAddr, u32 u32ImageSize, u64 u32Key, u32 u32KeySize, u32 u32Sig, u32 u32SigSize)

    • 参数

      参数名称 描述
      u64ImageAddr input data start address
      u32ImageSize input data size(no include signature data size)
      u32Key rsa2048 public n key
      u32KeySize n key size
      u32Sig sig data start addr
      u32SigSize sig data size
    • 返回值

      返回值 描述
      1 验签通过
      0 验签失败
    • 注意

      固定使用rsa2048对数据进行验签,在run_authenticate2中,先计算输入数据的sha256结果,再对签章数据进行验签计算,然后比较验签计算结果和sha256计算结果是否一致来判断验签是否成功。

    5.3.7. run_authenticate

    • 目的

      数据验签接口

    • 语法

      u8 run_authenticate(u64 u64ImageAddr, u32 u32ImageSize, u32 *pu32Key)

    • 参数

      参数名称 描述
      u64ImageAddr input data start address
      u32ImageSize input data size(no include signature data size)
      pu32Key rsa2048 public n key
    • 返回值

      返回值 描述
      1 验签通过
      0 验签失败
    • 注意

      • run_authenticate是将run_authenticate2封装了一层,输入的数据应该为plaintext+signature的格式,并且输入的u32ImageSize应该不包含签章数据的size。

      • 该接口使用可以参考drivers/sgs/crypto/ut/rtk/drv_aesdma_test.c中的run_auth_test测试接口

        在测试aesdma之前,需要先执行以下内容来开启aesdma的时钟:

        打开CONFIG_SGS_AESDMA_DEBUG
        echo aesdma_clk_state=1 > /sys/bus/platform/devices/soc:aesdma/debug
        echo rng_clk_state=1 > /sys/bus/platform/devices/soc:aesdma/debug
        

    5.4 调试节点

    节点地址:/sys/bus/platform/devices/soc:aesdma/debug

    5.4.1 debug节点说明

    名称 说明
    rng_init 随机数初始化状态
    sca 硬件防旁路攻击使能状态
    mcg 硬件门控时钟使能状态
    pa 增强power saving,注:该功能开启后,模块只保留最基础的供电,并失去计算能力
    wadr_irq skcipher中断使能状态
    ps_irq hash/akcipher中断使能状态
    aesdma_clk_state aesdma时钟状态
    aesdma_clk_freq aesdma时钟频率
    rng_clk_state rng时钟状态
    rng_clk_freq rng时钟频率
    log_level 可以调整driver打印等级。EMERG:0,ERROR:1,INFO:2,DEBUG:3

    5.4.2 使用示例

    查看所有信息:

    cat /sys/bus/platform/devices/soc:aesdma/debug
    

    debug节点会汇总其他子节点的信息,读取该节点,打印信息如图:

    img

    开启/关闭随机数初始化:

    echo rng_init=1 > /sys/bus/platform/devices/soc:aesdma/debug
    
    echo rng_init=0 > /sys/bus/platform/devices/soc:aesdma/debug
    

    开启/关闭mcg:

    echo mcg=1 > /sys/bus/platform/devices/soc:aesdma/debug
    
    echo mcg=0 > /sys/bus/platform/devices/soc:aesdma/debug
    

    开启/关闭pa:

    echo pa=1 > /sys/bus/platform/devices/soc:aesdma/debug
    
    echo pa=0 > /sys/bus/platform/devices/soc:aesdma/debug
    

    开启/关闭skcipher中断:

    echo wadr_irq=1 > /sys/bus/platform/devices/soc:aesdma/debug
    
    echo wadr_irq=0 > /sys/bus/platform/devices/soc:aesdma/debug
    

    开启/关闭hash/akcipher中断:

    echo ps_irq=1 > /sys/bus/platform/devices/soc:aesdma/debug
    
    echo ps_irq=0 > /sys/bus/platform/devices/soc:aesdma/debug
    

    开启/关闭aesdma时钟:

    echo aesdma_clk_state=1 > /sys/bus/platform/devices/soc:aesdma/debug
    
    echo aesdma_clk_state=0 > /sys/bus/platform/devices/soc:aesdma/debug
    

    调整aesdma时钟频率:

    可选值(172000000,216000000)

    echo aesdma_clk_freq=216000000 > /sys/bus/platform/devices/soc:aesdma/debug
    

    开启/关闭rng时钟:

    echo rng_clk_state=1 > /sys/bus/platform/devices/soc:aesdma/debug
    
    echo rng_clk_state=0 > /sys/bus/platform/devices/soc:aesdma/debug
    

    调整rng时钟频率:

    可选值(12000000,288000000)

    echo rng_clk_freq=288000000 > /sys/bus/platform/devices/soc:aesdma/debug
    

    调整打印等级:

    DRV_AESDMA_LOG_LEVEL_EMERG = 0,

    DRV_AESDMA_LOG_LEVEL_ERROR = 1,

    DRV_AESDMA_LOG_LEVEL_INFO = 2,

    DRV_AESDMA_LOG_LEVEL_DEBUG = 3

    可选值(0,1,2,3)

    e.g. 开启全部log

    echo log_level=3 > /sys/bus/platform/devices/soc:aesdma/debug
    

    注:敏感信息默认不会打印(如SKCIPHER,AKCIPHER的密钥),需要提前将drivers/sgs/crypto/drv/drv_aesdma_internal.h中的宏SECRET_MSG_PRINT置为1。

    5.5 sysfs调试信息

    使用该功能需要提前开启kernel下配置:

    • CONFIG_HWIP_DEBUG=y

    aesdma是一个比较典型的唯一系统资源,在sysfs下使用了一个漂亮的列表展示了aesdma的调试信息,该调试节点有如下特性:

    • 所有调试信息一次性输出
    • 可以通过写节点的方式控制输出的信息

    示例:

    echo 'help'     > /sys/class/sgs/aesdma/debug         # show this help
    
    echo '[-]state' > /sys/class/sgs/aesdma/debug         # disable|enable show all aesdma state
    echo '[-]statistic' > /sys/class/sgs/aesdma/debug     # disable|enable show all aesdma statistic
    echo '[-]reg'   > /sys/class/sgs/aesdma/debug         # disable|enable show all aesdma raw register value
    cat  /sys/class/sgs/aesdma/debug                      # show aesdma state | statistic | raw register value
    

    读取该节点,打印信息如图:

    1. 驱动状态

      img

    2. 统计数据

      img

    3. 寄存器信息

      img