CRYPTO Devices

Encryption/Decryption is a file and message encryption and decryption technology. With the rapid development of the Internet of Things, users have a strong demand for data encryption and decryption in their normal work.

To ensure the information security of IoT devices, the TLS secure transport layer protocol was introduced at the software level. At the same time, security-related encryption and decryption modules were gradually added to hardware chips, and even security chips designed specifically for security appeared. The hardware security module on the chip has a faster computing speed and smaller resource usage than the security algorithm implemented purely by software. However, most IoT devices still use pure software security algorithms. One of the most important reasons is that the hardware interfaces are different and diverse, making it difficult to connect with software.

Therefore, RT-Thread launched the hwcrypto hardware encryption and decryption driver framework and connected it to common security transmission kits. As long as the hardware supports the encryption and decryption module, the hardware-based encryption and decryption security transmission kit can be used directly, and the transmission speed can be increased several times.

hwcrypto is a hardware encryption and decryption device driver framework. It is mainly composed of two parts: the hardware encryption and decryption driver abstraction layer and various encryption and decryption API interfaces. For upper-layer applications, it can be connected to a security suite or used directly, and the usage is very flexible. For the driver, there are few interfaces to be connected, the function is single, and the driver development is simple and fast. The following figure is a Crypto framework hierarchy diagram:

The main features are as follows:

  • Thin and light design, efficient operation

The most important function of the hardware encryption and decryption driver is interface conversion, which realizes interface unification and facilitates upper-layer applications to use hardware encryption and decryption. Therefore, it is designed to be very thin and light. It has extremely low resource usage, ROM < 0.8K / RAM < 0.2K.

Encryption and decryption also have very high requirements on running speed. Therefore, for frequently called code, careful consideration is given to reduce the steps of the running process to a minimum, so as to minimize the performance loss, and make it as fast as directly operating the hardware registers.

  • Thoughtful and easy to use

In API design, we start from two dimensions: simplicity and ease of use, and full functionality. First, users directly use the hardware encryption and decryption API, which requires easy to use. For this reason, we evaluated many software interfaces in the early stage. After personal use and testing, we finally defined a set of APIs with full functionality and simple interfaces.

While meeting the needs of users, we also made a lot of considerations in the connection with the secure transmission suite. We added an API specifically for the secure transmission suite. In the end, this set of API users can use or connect to the secure transmission suite with ease.

  • Fully compatible and versatile

The interface design of the driver docking is also carefully designed. In the early stage, the encryption and decryption peripherals of many hardware manufacturers were classified according to their functions, analyzed and sorted, and a set of driver interfaces with single functions and comprehensive parameters were extracted. This driver interface can fully adapt to conventional MCU encryption and decryption peripherals. It has been verified on multiple platforms, such as Lianshengde W60X series, STM32 series, etc.

The hardware encryption and decryption framework currently supports encryption and decryption related interfaces such as AES/DES/3DES/RC4/SHA1/SHA2/MD5/CRC/RNG/BIGNUM.

The above encryption and decryption algorithms are divided into the following categories according to different types. Each category has rich APIs available for use. The currently supported types are as follows:

  • hash: hash algorithm

  • symmetric: symmetric encryption and decryption algorithm

  • gcm: GMAC message authentication code

  • crc: CRC redundancy check

  • rng: random number generator

  • bignum: large number operations

A hash algorithm transforms an input of any length into an output of a fixed length through a hash algorithm. It is a function that compresses a message of any length into a message digest of a fixed length. The space of hash values ​​is usually much smaller than the space of inputs. Different inputs may hash to the same output, so it is impossible to determine the unique input value from the hash value.

The application accesses the hash algorithm device hardware through the hash algorithm device management interface provided by RT-Thread. The relevant interface is as follows:

function

describe

rt_hwcrypto_hash_create()

Creating a hash context

rt_hwcrypto_hash_destroy()

Release context

rt_hwcrypto_hash_finish()

Calculate the final hash value

rt_hwcrypto_hash_update()

Process a packet of data

rt_hwcrypto_hash_cpy()

Copy context

rt_hwcrypto_hash_reset()

Reset Context

rt_hwcrypto_hash_set_type()

Set the hash algorithm type

The application creates a hash context based on the handle of the hash device as follows:

struct rt_hwcrypto_ctx *rt_hwcrypto_hash_create(struct rt_hwcrypto_device *device,
                                                hwcrypto_type type);copymistakeCopy Success

parameter

describe

device

Encryption and decryption device handle

type

Hash algorithm type

return

——

NULL

fail

other

Device Object

Common types and subtypes of hash algorithms are as follows

    /* HASH Type */
    HWCRYPTO_TYPE_MD5     = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16,  /**< MD5 */
    HWCRYPTO_TYPE_SHA1    = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16,  /**< SHA1 */
    HWCRYPTO_TYPE_SHA2    = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16,  /**< SHA2 */

    /* SHA2 Subtype */
    HWCRYPTO_TYPE_SHA224 = HWCRYPTO_TYPE_SHA2 | (0x01 << 8),
    HWCRYPTO_TYPE_SHA256 = HWCRYPTO_TYPE_SHA2 | (0x02 << 8),
    HWCRYPTO_TYPE_SHA384 = HWCRYPTO_TYPE_SHA2 | (0x03 << 8),
    HWCRYPTO_TYPE_SHA512 = HWCRYPTO_TYPE_SHA2 | (0x04 << 8),
copymistakeCopy Success

If you create a hash algorithm of the MD5 type, the usage example is as follows

    struct rt_hwcrypto_ctx *ctx;

    ctx = rt_hwcrypto_hash_create(rt_hwcrypto_dev_default(), HWCRYPTO_TYPE_MD5);copymistakeCopy Success
  • The prototype of the rt_hwcrypto_dev_default() function is struct rt_hwcrypto_device *rt_hwcrypto_dev_default(void)to return the default hardware encryption and decryption device handle.

The application deletes the context based on the hash context and releases the resources as follows:

void rt_hwcrypto_hash_destroy(struct rt_hwcrypto_ctx *ctx);copymistakeCopy Success

parameter

describe

ctx

Context

return

——

Based on the hash context, the application can output the final hash value as follows:

rt_err_t rt_hwcrypto_hash_finish(struct rt_hwcrypto_ctx *ctx, rt_uint8_t *output, rt_size_t length);copymistakeCopy Success

parameter

describe

ctx

Context

output

Output Data

length

Data length

return

——

RT_EOK

Calculation success

other

fail

The application inputs a packet of data and calculates the hash value according to the hash context, as shown below:

rt_err_t rt_hwcrypto_hash_update(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *input, rt_size_t length);copymistakeCopy Success

parameter

describe

ctx

Context

input

Input Data

length

Input data length

return

——

RT_EOK

Calculation success

other

fail

The usage examples are as follows:

int main(void)
{
    rt_uint8_t buf_in[32];
    int i;
    struct rt_hwcrypto_ctx *ctx;

    /* 填充测试数据 */
    for (i = 0; i < sizeof(buf_in); i++)
    {
        buf_in[i] = (rt_uint8_t)i;
    }
    /* 创建一个 SHA1/MD5 类型的上下文 */
    ctx = rt_hwcrypto_hash_create(rt_hwcrypto_dev_default(), type);

    /* 将输入数据进行 hash 运算 */
    rt_hwcrypto_hash_update(ctx, in, 32);
    /* 获得运算结果 */
    rt_hwcrypto_hash_finish(ctx, out, 32);
    /* 删除上下文,释放资源 */
    rt_hwcrypto_hash_destroy(ctx);
}copymistakeCopy Success

The application copies the context of the source hash to the context of the target hash as follows:

rt_err_t rt_hwcrypto_hash_cpy(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src);copymistakeCopy Success

parameter

describe

of the

Target context

src

Source context

return

——

RT_EOK

Calculation success

other

fail

The application resets the hash context text according to the hash context, as follows:

void rt_hwcrypto_hash_reset(struct rt_hwcrypto_ctx *ctx);copymistakeCopy Success

parameter

describe

ctx

Context

return

——

  • Before releasing the context, the next packet of data can be calculated only after it is reset.

The application sets the hash algorithm type according to the hash context, as follows:

rt_err_t rt_hwcrypto_hash_set_type(struct rt_hwcrypto_ctx *ctx, hwcrypto_type type);copymistakeCopy Success

parameter

describe

ctx

Context

type

Hash algorithm type

return

——

RT_EOK

Calculation success

other

fail

  • Common hash algorithm types, refer to the type introduction in the creation of hash context

  • Setting the type is only valid before data operation. Changing the type during operation will result in incorrect operation results.

Symmetric encryption and decryption refers to an encryption algorithm that uses the same key for encryption and decryption, so this encryption algorithm is also called a secret key algorithm or a single key algorithm. The security of a symmetric algorithm depends on the key. Leaking the key means that anyone can decrypt the messages they send or receive, so the confidentiality of the key is crucial to the security of communication.

The application accesses the symmetric algorithm device hardware through the symmetric device management interface provided by RT-Thread. The relevant interface is as follows:

function

describe

rt_hwcrypto_symmetric_create()

Create a symmetric encryption and decryption context

rt_hwcrypto_symmetric_destroy()

Release context

rt_hwcrypto_symmetric_crypt()

Encryption and decryption operations

rt_hwcrypto_symmetric_setkey()

Set encryption and decryption keys

rt_hwcrypto_symmetric_getkey()

Get encryption and decryption keys

rt_hwcrypto_symmetric_setiv()

Set the symmetric encryption and decryption initialization vector

rt_hwcrypto_symmetric_getiv()

Get the symmetric encryption and decryption initialization vector

rt_hwcrypto_symmetric_set_ivoff()

Set the symmetric encryption and decryption initialization vector offset value

rt_hwcrypto_symmetric_get_ivoff()

Get the symmetric encryption and decryption initialization vector offset value

rt_hwcrypto_symmetric_cpy()

Copy context

rt_hwcrypto_symmetric_reset()

Reset Context

rt_hwcrypto_symmetric_set_type()

Set the encryption and decryption type

The application creates a symmetric encryption and decryption context based on the handle of the symmetric encryption and decryption device, as shown below:

struct rt_hwcrypto_ctx *rt_hwcrypto_symmetric_create(struct rt_hwcrypto_device *device, hwcrypto_type type);copymistakeCopy Success

parameter

describe

device

Encryption and decryption device handle

type

Symmetric encryption and decryption algorithm type

return

——

NULL

fail

other

Device Object

Common types and subtypes of symmetric encryption and decryption algorithms are as follows

    /* symmetric Type */
    HWCRYPTO_TYPE_AES     = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16,  /**< AES */
    HWCRYPTO_TYPE_DES     = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16,  /**< DES */
    HWCRYPTO_TYPE_3DES    = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16,  /**< 3DES */
    HWCRYPTO_TYPE_RC4     = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16,  /**< RC4 */
    HWCRYPTO_TYPE_GCM     = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16,  /**< GCM */

    /* AES Subtype */
    HWCRYPTO_TYPE_AES_ECB = HWCRYPTO_TYPE_AES | (0x01 << 8),
    HWCRYPTO_TYPE_AES_CBC = HWCRYPTO_TYPE_AES | (0x02 << 8),
    HWCRYPTO_TYPE_AES_CFB = HWCRYPTO_TYPE_AES | (0x03 << 8),
    HWCRYPTO_TYPE_AES_CTR = HWCRYPTO_TYPE_AES | (0x04 << 8),
    HWCRYPTO_TYPE_AES_OFB = HWCRYPTO_TYPE_AES | (0x05 << 8),

    /* DES Subtype */
    HWCRYPTO_TYPE_DES_ECB = HWCRYPTO_TYPE_DES | (0x01 << 8),
    HWCRYPTO_TYPE_DES_CBC = HWCRYPTO_TYPE_DES | (0x02 << 8),

    /* 3DES Subtype */
    HWCRYPTO_TYPE_3DES_ECB = HWCRYPTO_TYPE_3DES | (0x01 << 8),
    HWCRYPTO_TYPE_3DES_CBC = HWCRYPTO_TYPE_3DES | (0x02 << 8),copymistakeCopy Success

Create an AES-CBC encryption as follows

    struct rt_hwcrypto_ctx *ctx;

    ctx = rt_hwcrypto_symmetric_create(rt_hwcrypto_dev_default(), HWCRYPTO_TYPE_AES_CBC);copymistakeCopy Success

The application deletes the context based on the symmetric encryption and decryption context and releases resources as shown below:

void rt_hwcrypto_symmetric_destroy(struct rt_hwcrypto_ctx *ctx);copymistakeCopy Success

parameter

describe

ctx

Context Handle

return

——

The application can output the final calculated value based on the context of symmetric encryption and decryption, encryption and decryption mode, input data and length, as shown below:

rt_err_t rt_hwcrypto_symmetric_crypt(struct rt_hwcrypto_ctx *ctx, hwcrypto_mode mode, rt_size_t length, const rt_uint8_t *in, rt_uint8_t *out);
copymistakeCopy Success

parameter

describe

ctx

Context Handle

mode

Encryption or decryption

length

Data length

in

Input Data

out

Output Data

return

——

RT_EOK

Calculation success

other

fail

The encryption or decryption modes are as follows

typedef enum
{
    HWCRYPTO_MODE_ENCRYPT = 0x1,        /**< Encryption operations */
    HWCRYPTO_MODE_DECRYPT = 0x2,        /**< Decryption operations */
    HWCRYPTO_MODE_UNKNOWN = 0x7fffffff, /**< Unknown */
} hwcrypto_mode;copymistakeCopy Success

The application sets the encryption and decryption keys according to the context, key and secret key, and length of symmetric encryption and decryption, as shown below:

rt_err_t rt_hwcrypto_symmetric_setkey(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *key, rt_uint32_t bitlen);copymistakeCopy Success

parameter

describe

ctx

Context Handle

key

Enter the key

Bitlen

Key length

return

——

RT_EOK

Set key successfully

other

fail

The application obtains the key length based on the context, key, and length of symmetric encryption and decryption, as shown below:

int rt_hwcrypto_symmetric_getkey(struct rt_hwcrypto_ctx *ctx, rt_uint8_t *key, rt_uint32_t bitlen);copymistakeCopy Success

parameter

describe

ctx

Target context

key

Key

Bitlen

Key length

return

——

int

Copy key length

other

fail

The application sets the symmetric encryption and decryption initialization vector according to the symmetric encryption and decryption context, initialization vector, and vector length, as shown below:

rt_err_t rt_hwcrypto_symmetric_setiv(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *iv, rt_size_t len);copymistakeCopy Success

parameter

describe

ctx

Context

iv

Initialization Vector

only

Length of the initialization vector

return

——

RT_EOK

Set up for success

other

fail

The application obtains the symmetric encryption and decryption initialization vector according to the symmetric encryption and decryption context, as shown below:

int rt_hwcrypto_symmetric_getiv(struct rt_hwcrypto_ctx *ctx, rt_uint8_t *iv, rt_size_t len);copymistakeCopy Success

parameter

describe

ctx

Context

iv

Will get the initialization vector

only

Length of the initialization vector

return

——

int

Get the length of success

other

fail

The application sets the offset value of the symmetric encryption and decryption initialization vector according to the context of symmetric encryption and decryption and the initialization vector offset value, as shown below:

void rt_hwcrypto_symmetric_set_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t iv_off);copymistakeCopy Success

parameter

describe

ctx

Context

iv_off

Initialization vector offset

return

——

The application obtains the offset value of the symmetric encryption and decryption initialization vector according to the context of symmetric encryption and decryption, as shown below:

void rt_hwcrypto_symmetric_get_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t *iv_off);copymistakeCopy Success

parameter

describe

ctx

Context

iv_off

Initialization vector offset pointer

return

——

The application copies the source symmetric encryption and decryption context to the destination context as shown below:

rt_err_t rt_hwcrypto_symmetric_cpy(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src);copymistakeCopy Success

parameter

describe

of the

Target context

src

Source context

return

——

RT_EOK

Set up for success

other

fail

The application resets the context based on the symmetric encryption and decryption context as follows:

void rt_hwcrypto_symmetric_reset(struct rt_hwcrypto_ctx *ctx);copymistakeCopy Success

parameter

describe

of the

Context

return

——

The application sets encryption or decryption based on the context of symmetric encryption and decryption, as shown below:

rt_err_t rt_hwcrypto_symmetric_set_type(struct rt_hwcrypto_ctx *ctx, hwcrypto_type type);copymistakeCopy Success

parameter

describe

ctx

Context

type

Encryption and decryption type

return

——

RT_EOK

Set up for success

other

fail

  • For common encryption and decryption types, refer to the type introduction in Creating Symmetric Encryption and Decryption Contexts.

AES-CBC is used for encryption. The application examples are as follows:

/* 加密密钥 */
static const rt_uint8_t key[16] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF};

static void hw_aes_cbc(const rt_uint8_t in[32], rt_uint8_t out[32], hwcrypto_mode mode);

int main(void)
{
    rt_uint8_t buf_in[32];
    rt_uint8_t buf_out[32];
    int i;

    /* 填充测试数据 */
    for (i = 0; i < sizeof(buf_in); i++)
    {
        buf_in[i] = (rt_uint8_t)i;
    }

    memset(buf_out, 0, sizeof(buf_out));
    /* 对测试数据进行加密 */
    hw_aes_cbc(buf_in, buf_out, HWCRYPTO_MODE_ENCRYPT);
}

static void hw_aes_cbc(const rt_uint8_t in[32], rt_uint8_t out[32], hwcrypto_mode mode)
{
    struct rt_hwcrypto_ctx *ctx;

    /* 创建一个 AES-CBC 模式的上下文 */
    ctx = rt_hwcrypto_symmetric_create(rt_hwcrypto_dev_default(), HWCRYPTO_TYPE_AES_CBC);
    if (ctx == RT_NULL)
    {
        LOG_E("create AES-CBC context err!");
        return;
    }
    /* 设置 AES-CBC 加密密钥 */
    rt_hwcrypto_symmetric_setkey(ctx, key, 128);
    /* 执行 AES-CBC 加密/解密 */
    rt_hwcrypto_symmetric_crypt(ctx, mode, 32, in, out);
    /* 删除上下文,释放资源 */
    rt_hwcrypto_symmetric_destroy(ctx);
}
copymistakeCopy Success

GCM message authentication can provide encryption and integrity verification of messages, and can also verify the authenticity of other attached messages.

The application accesses the GCM algorithm device hardware through the GCM device management interface provided by RT-Thread. The relevant interface is as follows:

function

describe

rt_hwcrypto_gcm_create()

Creating a Context

rt_hwcrypto_gcm_destroy()

Release context

rt_hwcrypto_gcm_start()

Passing in additional value

rt_hwcrypto_gcm_finish()

Generate a message authentication code

rt_hwcrypto_gcm_crypt()

Encryption and decryption

rt_hwcrypto_gcm_setkey()

Setting the key

rt_hwcrypto_gcm_getkey()

Get the key

rt_hwcrypto_gcm_setiv()

Setting the Initialization Vector

rt_hwcrypto_gcm_getiv()

Get the initialization vector

rt_hwcrypto_gcm_set_ivoff()

Set the initialization vector offset

rt_hwcrypto_gcm_get_ivoff()

Get the initialization vector offset

rt_hwcrypto_gcm_cpy()

Copy context

rt_hwcrypto_gcm_reset()

Reset Context

The application creates a symmetric encryption and decryption context based on the handle of the gcm message authentication, as shown below:

struct rt_hwcrypto_ctx *rt_hwcrypto_gcm_create(struct rt_hwcrypto_device *device,
                                               hwcrypto_type crypt_type);copymistakeCopy Success

parameter

describe

device

Encryption and decryption device handle

crypt_type

Encryption and decryption algorithm type

return

——

NULL

fail

other

Device Object

The common types of gcm are as follows

    /* symmetric Type */
    HWCRYPTO_TYPE_AES     = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16,  /**< AES */
    HWCRYPTO_TYPE_DES     = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16,  /**< DES */
    HWCRYPTO_TYPE_3DES    = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16,  /**< 3DES */
    HWCRYPTO_TYPE_RC4     = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16,  /**< RC4 */
    HWCRYPTO_TYPE_GCM     = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16,  /**< GCM */

    /* AES Subtype */
    HWCRYPTO_TYPE_AES_ECB = HWCRYPTO_TYPE_AES | (0x01 << 8),
    HWCRYPTO_TYPE_AES_CBC = HWCRYPTO_TYPE_AES | (0x02 << 8),
    HWCRYPTO_TYPE_AES_CFB = HWCRYPTO_TYPE_AES | (0x03 << 8),
    HWCRYPTO_TYPE_AES_CTR = HWCRYPTO_TYPE_AES | (0x04 << 8),
    HWCRYPTO_TYPE_AES_OFB = HWCRYPTO_TYPE_AES | (0x05 << 8),

    /* DES Subtype */
    HWCRYPTO_TYPE_DES_ECB = HWCRYPTO_TYPE_DES | (0x01 << 8),
    HWCRYPTO_TYPE_DES_CBC = HWCRYPTO_TYPE_DES | (0x02 << 8),

    /* 3DES Subtype */
    HWCRYPTO_TYPE_3DES_ECB = HWCRYPTO_TYPE_3DES | (0x01 << 8),
    HWCRYPTO_TYPE_3DES_CBC = HWCRYPTO_TYPE_3DES | (0x02 << 8),copymistakeCopy Success

The application deletes the context and releases resources based on the gcm context, as shown below:

void rt_hwcrypto_gcm_destroy(struct rt_hwcrypto_ctx *ctx);copymistakeCopy Success

parameter

describe

ctx

Context

return

——

The application passes in the initial value of the additional value for encryption according to the context of gcm, as shown below:

rt_err_t rt_hwcrypto_gcm_start(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *add,
                               rt_size_t add_len);copymistakeCopy Success

parameter

describe

ctx

Context

add

Additional Message

add_len

Additional message length

return

——

RT_EOK

success

other

fail

After encrypting the data according to the context of GCM, the application outputs the tag value and length as a verification of integrity and authenticity, as shown below:

rt_err_t rt_hwcrypto_gcm_finish(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *tag, rt_size_t tag_len);copymistakeCopy Success

parameter

describe

ctx

Context

tag

Message Authentication Code

tag_len

Message authentication code length

return

——

RT_EOK

success

other

fail

The application encrypts the data according to the context of GCM, encryption and decryption mode, data length and input data, and then outputs the data buffer as shown below:

rt_err_t rt_hwcrypto_gcm_crypt(struct rt_hwcrypto_ctx *ctx, hwcrypto_mode mode,
                               rt_size_t length, const rt_uint8_t *in, rt_uint8_t *out);copymistakeCopy Success

parameter

describe

ctx

Context

mode

Encryption and decryption mode

length

Input data length

in

Input Data

out

Output Data

return

——

RT_EOK

success

other

fail

The application sets the key according to the gcm context, encryption and decryption key and length, as shown below:

rt_err_t rt_hwcrypto_gcm_setkey(struct rt_hwcrypto_ctx *ctx,
                                const rt_uint8_t *key, rt_uint32_t bitlen);copymistakeCopy Success

parameter

describe

ctx

Context

key

Key

Bitlen

Key length

return

——

RT_EOK

success

other

fail

The application obtains the key based on the gcm context, encryption and decryption key and length, as shown below:

rt_err_t rt_hwcrypto_gcm_getkey(struct rt_hwcrypto_ctx *ctx,
                                rt_uint8_t *key, rt_uint32_t bitlen);copymistakeCopy Success

parameter

describe

ctx

Context

key

Key

Bitlen

Key length

return

——

RT_EOK

success

other

fail

The application sets the initialization vector according to the gcm context, initialization vector and length, as shown below:

rt_err_t rt_hwcrypto_gcm_setiv(struct rt_hwcrypto_ctx *ctx,
                               const rt_uint8_t *iv, rt_size_t len);copymistakeCopy Success

parameter

describe

ctx

Context

iv

Initialization Vector

only

Initialization vector length

return

——

RT_EOK

success

other

fail

The application obtains the initialization vector based on the gcm context, initialization vector and length, as shown below:

rt_err_t rt_hwcrypto_gcm_getiv(struct rt_hwcrypto_ctx *ctx,
                               rt_uint8_t *iv, rt_size_t len);copymistakeCopy Success

parameter

describe

ctx

Context

iv

Initialization Vector

only

Initialization vector length

return

——

RT_EOK

success

other

fail

The application sets the initialization vector offset according to the context of gcm, as shown below:

void rt_hwcrypto_gcm_set_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t iv_off);copymistakeCopy Success

parameter

describe

ctx

Context

iv_off

Initialization vector offset

return

——

The application obtains the initialization vector offset based on the gcm context and initialization vector offset, as shown below:

void rt_hwcrypto_gcm_get_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t iv_off);copymistakeCopy Success

parameter

describe

ctx

Context

iv_off

Initialization vector offset

return

——

The application copies the gcm context to the target context as follows:

rt_err_t rt_hwcrypto_gcm_cpy(struct rt_hwcrypto_ctx *des,
                             const struct rt_hwcrypto_ctx *src);copymistakeCopy Success

parameter

describe

of the

Target context

src

Source context

return

——

RT_EOK

success

other

fail

Cyclic Redundancy Check (CRC) is a hash function that generates a short fixed-bit check code based on network data packets or computer files. It is mainly used to detect or verify errors that may occur after data transmission or storage. It uses the principle of division and remainder for error detection.

The application accesses the CRC algorithm device hardware through the CRC device management interface provided by RT-Thread. The relevant interface is as follows:

function

describe

rt_hwcrypto_crc_create()

Create CRC context

rt_hwcrypto_crc_destroy()

Release context

rt_hwcrypto_crc_update()

Calculate a packet of data

rt_hwcrypto_crc_cfg()

Set context calculation data

The application creates a CRC context based on the handle of the CRC device as follows:

struct rt_hwcrypto_ctx *rt_hwcrypto_crc_create(struct rt_hwcrypto_device *device,
                                               hwcrypto_crc_mode mode);copymistakeCopy Success

parameter

describe

device

Device to be set up

mode

CRC calculation mode

return

——

NULL

fail

other

Device Object

The commonly used CRC calculation modes are as follows:

typedef enum
{
    HWCRYPTO_CRC_CUSTOM,        /**< Custom CRC mode */
    HWCRYPTO_CRC_CRC8,          /**< poly : 0x07 */
    HWCRYPTO_CRC_CRC16,         /**< poly : 0x8005 */
    HWCRYPTO_CRC_CRC32,         /**< poly : 0x04C11DB7 */
    HWCRYPTO_CRC_CCITT,         /**< poly : 0x1021 */
    HWCRYPTO_CRC_DNP,           /**< poly : 0x3D65 */
} hwcrypto_crc_mode;copymistakeCopy Success

These modes correspond to different calculation polynomials, as shown in the notes.

The application deletes the context according to the CRC context and releases the resources as follows:

void rt_hwcrypto_crc_destroy(struct rt_hwcrypto_ctx *ctx);copymistakeCopy Success

parameter

describe

ctx

Context

return

——

The application calculates the CRC calculation result based on the CRC context, input data and its length as follows:

rt_uint32_t rt_hwcrypto_crc_update(struct rt_hwcrypto_ctx *ctx,
                                   const rt_uint8_t *input, rt_size_t length);copymistakeCopy Success

parameter

describe

ctx

Context

input

Input Data

length

Input data length

return

——

uint32_t

Calculation results

0

fail

The application releases resources based on the CRC context and configuration information as follows:

void rt_hwcrypto_crc_cfg(struct rt_hwcrypto_ctx *ctx,
                         struct hwcrypto_crc_cfg *cfg);copymistakeCopy Success

parameter

describe

ctx

Context

cfg

Encryption and decryption configuration parameters

return

——

The CRC configuration structure is as follows

struct hwcrypto_crc_cfg
{
    rt_uint32_t last_val;   /**< Last CRC value cache */
    rt_uint32_t poly;       /**< CRC polynomial */
    rt_uint16_t width;      /**< CRC value width */
    rt_uint32_t xorout;     /**< Result XOR Value */
    rt_uint16_t flags;      /**< Input or output data reverse. CRC_FLAG_REFIN or CRC_FLAG_REFOUT */
};copymistakeCopy Success

Calculate the data checksum of 0 - 7 and implement the following configuration

    struct hwcrypto_crc_cfg cfg =
    {
        .last_val = 0xFFFFFFFF,
        .poly = 0x04C11DB7,
        .width = 32,
        .xorout = 0x00000000,
        .flags = 0,
    };copymistakeCopy Success

To obtain the checksum value, the specific procedure is as follows

int main(void)
{
    rt_uint8_t temp[] = {0,1,2,3,4,5,6,7};
    struct rt_hwcrypto_ctx *ctx;
    rt_uint32_t result = 0;
    struct hwcrypto_crc_cfg cfg =
    {
        .last_val = 0xFFFFFFFF,
        .poly = 0x04C11DB7,
        .width = 32,
        .xorout = 0x00000000,
        .flags = 0,
    };

    /* 创建设备的上下文 */
    ctx = rt_hwcrypto_crc_create(rt_hwcrypto_dev_default(), HWCRYPTO_CRC_CRC32);/* 设置 CRC 配置 */
    rt_hwcrypto_crc_cfg(ctx, &cfg);
    /* 输入数据,获取其 CRC 计算值 */
    result = rt_hwcrypto_crc_update(ctx, temp, sizeof(temp));
    /* 打印结果 */
    rt_kprintf("result: %x \n", result);
    /* 释放 ctx */
    rt_hwcrypto_crc_destroy(ctx);
}copymistakeCopy Success

The data generated by the Random Numeral Generator (RNG) has nothing to do with the previous numbers.

The application accesses the RNG algorithm device hardware through the RNG device management interface provided by RT-Thread. The relevant interface is as follows:

function

describe

rt_hwcrypto_rng_update()

Get the default device random number

The application generates random numbers according to the context of the RNG default device as follows:

rt_uint32_t rt_hwcrypto_rng_update(void);copymistakeCopy Success

parameter

describe

return

——

rt_uint32_t

Random numbers generated

other

fail

For example, to detect random number generation 1000,000 times and count the number of odd and even numbers generated, the code is as follows:

#include <hw_rng.h>

void hw_rng(void)
{
    rt_uint32_t result=0;
    int i, num0=0, num1 =0;
    const int max_test = 1000 * 1000;


    for (i = 0; i < max_test; i++)
    {
        result = rt_hwcrypto_rng_update();
        result%2 ? num1++ : num0++;
    }
    LOG_I(" num1: %d, num0: %d ",num1, num0);
}copymistakeCopy Success

Since the basic numeric data types provided by programming languages ​​have a limited range of values ​​and cannot satisfy large-scale high-precision numerical calculations, other methods are needed to achieve high-precision numerical calculations.

The application accesses the big number algorithm device hardware through the big number device management interface provided by RT-Thread. The relevant interface is as follows:

function

describe

rt_hwcrypto_bignum_default()

Get the default context

rt_hwcrypto_bignum_init()

Initialize a large number object

rt_hwcrypto_bignum_free()

Release the big numbers

rt_hwcrypto_bignum_get_len()

Get the length of a large number

rt_hwcrypto_bignum_export_bin()

Output binary data in big-endian mode

rt_hwcrypto_bignum_import_bin()

Input binary in big-endian mode

rt_hwcrypto_bignum_add()

Adding large numbers

rt_hwcrypto_bignum_sub()

Subtracting large numbers

rt_hwcrypto_bignum_mul()

Multiplying large numbers

rt_hwcrypto_bignum_mulmod

Modulo the product of large numbers

rt_hwcrypto_bignum_exptmod

Modulo large number exponentiation

The application obtains the default context based on the large number of device handles, as follows:

rt_err_t rt_hwcrypto_bignum_default(struct rt_hwcrypto_device *device);copymistakeCopy Success

parameter

describe

device

Device handle

return

——

RT_EOK

success

other

fail

The application initializes the big number object according to the big number context, as shown below:

void rt_hwcrypto_bignum_init(struct hw_bignum_mpi *n);copymistakeCopy Success

parameter

describe

n

Initialize a large number object

return

——

The structure of a large number object is as follows:

struct hw_bignum_mpi
{
    int sign;            /**< integer sign */
    rt_size_t total;     /**< total of limbs */
    rt_uint8_t *p;       /**< pointer to limbs */
};copymistakeCopy Success

The application releases a large number of objects as follows:

void rt_hwcrypto_bignum_free(struct hw_bignum_mpi *n);copymistakeCopy Success

parameter

describe

n

Large number objects

return

——

The application obtains the length of a large number as follows:

int rt_hwcrypto_bignum_get_len(const struct hw_bignum_mpi *n);copymistakeCopy Success

parameter

describe

n

The large number object whose length will be obtained

return

——

int

Returns the length of a large number

other

fail

The application outputs the binary number in big-endian mode according to the large number object and returns the copied length, as shown below:

int rt_hwcrypto_bignum_export_bin(struct hw_bignum_mpi *n, rt_uint8_t *buf, int len);copymistakeCopy Success

parameter

describe

n

Large number objects

buf

Data to be output

only

Data length

return

——

int

Returns the copy length

other

fail

The application inputs a binary number in big-endian mode according to the handle of the large number, as shown below:

rt_err_t rt_hwcrypto_bignum_import_bin(struct hw_bignum_mpi *n, rt_uint8_t *buf, int len);copymistakeCopy Success

parameter

describe

n

Large number objects

buf

Input Data

only

Data length

return

——

RT_EOK

success

other

fail

The application adds two large number objects and assigns the result to x, as shown below

rt_err_t rt_hwcrypto_bignum_add(struct hw_bignum_mpi *x,
                                const struct hw_bignum_mpi *a,
                                const struct hw_bignum_mpi *b);copymistakeCopy Success

parameter

describe

x

Output

a

Input Data

b

Input Data

return

——

RT_EOK

success

other

fail

The application subtracts two large number objects and assigns the result to x, as shown below

rt_err_t rt_hwcrypto_bignum_sub(struct hw_bignum_mpi *x,
                                const struct hw_bignum_mpi *a,
                                const struct hw_bignum_mpi *b);copymistakeCopy Success

parameter

describe

x

Output

a

Input Data

b

Input Data

return

——

RT_EOK

success

other

fail

The application multiplies two large number objects and assigns the result to x, as shown below

rt_err_t rt_hwcrypto_bignum_mul(struct hw_bignum_mpi *x,
                                const struct hw_bignum_mpi *a,
                                const struct hw_bignum_mpi *b);copymistakeCopy Success

parameter

describe

x

Output

a

Input Data

b

Input Data

return

——

RT_EOK

success

other

fail

The application multiplies the large number object modulo the product and assigns the result to x = a * b (mod c), as shown below

rt_err_t rt_hwcrypto_bignum_mulmod(struct hw_bignum_mpi *x,
                                   const struct hw_bignum_mpi *a,
                                   const struct hw_bignum_mpi *b,
                                   const struct hw_bignum_mpi *c);copymistakeCopy Success

parameter

describe

x

Output

a

Input Data

b

Input Data

c

Input Data

return

——

RT_EOK

success

other

fail

The application performs exponential modulo on the large number object and assigns the result to x = a ^ b (mod c), as shown below

rt_err_t rt_hwcrypto_bignum_exptmod(struct hw_bignum_mpi *x,
                                    const struct hw_bignum_mpi *a,
                                    const struct hw_bignum_mpi *b,
                                    const struct hw_bignum_mpi *c);copymistakeCopy Success

parameter

describe

x

Output

a

Input Data

b

Input Data

c

Input Data

return

——

RT_EOK

success

other

fail

Usually, the process of using hardware encryption and decryption can be roughly divided into four steps: the first step is to create a context of a specific encryption and decryption type; the second step is to configure the context, such as setting keys and other operations; the third step is to execute the corresponding function and obtain the processed result; the fourth step is to delete the context and release resources.

The following code first uses AES-CBC to encrypt the data, and then decrypts the encrypted data. After decryption, the MD5 and SHA1 hash algorithms are used to generate information summaries, and some log information is output at the same time (the specific implementation code of hardware encryption and decryption is below the main() function).


/* 加密密钥 */
static const rt_uint8_t key[16] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF};

int main(void)
{
    rt_uint8_t buf_in[32];
    rt_uint8_t buf_out[32];
    int i;

    /* 填充测试数据 */
    for (i = 0; i < sizeof(buf_in); i++)
    {
        buf_in[i] = (rt_uint8_t)i;
    }
    /* 打印填充的数据 */
    LOG_HEX("Data   ", 8, buf_in, sizeof(buf_in));

    memset(buf_out, 0, sizeof(buf_out));
    /* 对测试数据进行加密 */
    hw_aes_cbc(buf_in, buf_out, HWCRYPTO_MODE_ENCRYPT);

    /* 打印加密后的数据 */
    LOG_HEX("AES-enc", 8, buf_out, sizeof(buf_out));

    memset(buf_in, 0, sizeof(buf_in));
    /* 对加密数据进行解密 */
    hw_aes_cbc(buf_out, buf_in, HWCRYPTO_MODE_DECRYPT);

    /* 打印解密后的数据 */
    LOG_HEX("AES-dec", 8, buf_in, sizeof(buf_in));

    memset(buf_out, 0, sizeof(buf_out));
    /* 对测试数据进行 MD5 运算 */
    hw_hash(buf_in, buf_out, HWCRYPTO_TYPE_MD5);

    /* 打印 16 字节长度的 MD5 结果 */
    LOG_HEX("MD5    ", 8, buf_out, 16);

    memset(buf_out, 0, sizeof(buf_out));
    /* 对测试数据进行 SHA1 运算 */
    hw_hash(buf_in, buf_out, HWCRYPTO_TYPE_SHA1);

    /* 打印 20 字节长度的 SHA1 结果 */
    LOG_HEX("SHA1   ", 8, buf_out, 20);

    return 0;
}copymistakeCopy Success

1. AES-CBC encryption and decryption

static void hw_aes_cbc(const rt_uint8_t in[32], rt_uint8_t out[32], hwcrypto_mode mode)
{
    struct rt_hwcrypto_ctx *ctx;

    /* 创建一个 AES-CBC 模式的上下文 */
    ctx = rt_hwcrypto_symmetric_create(rt_hwcrypto_dev_default(), HWCRYPTO_TYPE_AES_CBC);
    if (ctx == RT_NULL)
    {
        LOG_E("create AES-CBC context err!");
        return;
    }
    /* 设置 AES-CBC 加密密钥 */
    rt_hwcrypto_symmetric_setkey(ctx, key, 128);
    /* 执行 AES-CBC 加密/解密 */
    rt_hwcrypto_symmetric_crypt(ctx, mode, 32, in, out);
    /* 删除上下文,释放资源 */
    rt_hwcrypto_symmetric_destroy(ctx);
}copymistakeCopy Success

2. HASH message summary

static void hw_hash(const rt_uint8_t in[32], rt_uint8_t out[32], hwcrypto_type type)
{
    struct rt_hwcrypto_ctx *ctx;

    /* 创建一个 SHA1/MD5 类型的上下文 */
    ctx = rt_hwcrypto_hash_create(rt_hwcrypto_dev_default(), type);
    if (ctx == RT_NULL)
    {
        LOG_E("create hash[%08x] context err!", type);
        return;
    }
    /* 将输入数据进行 hash 运算 */
    rt_hwcrypto_hash_update(ctx, in, 32);
    /* 获得运算结果 */
    rt_hwcrypto_hash_finish(ctx, out, 32);
    /* 删除上下文,释放资源 */
    rt_hwcrypto_hash_destroy(ctx);
}copymistakeCopy Success

After normal operation, the terminal output information is as follows:

 \ | /
- RT -     Thread Operating System
 / | \     4.0.1 build Jun  3 2019
 2006 - 2019 Copyright by rt-thread team
D/HEX Data   : 0000-0008: 00 01 02 03 04 05 06 07    ........
               0008-0010: 08 09 0A 0B 0C 0D 0E 0F    ........
               0010-0018: 10 11 12 13 14 15 16 17    ........
               0018-0020: 18 19 1A 1B 1C 1D 1E 1F    ........
D/HEX AES-enc: 0000-0008: 0A 94 0B B5 41 6E F0 45    ....An.E
               0008-0010: F1 C3 94 58 C6 53 EA 5A    ...X.S.Z
               0010-0018: 3C F4 56 B4 CA 48 8A A3    <.V..H..
               0018-0020: 83 C7 9C 98 B3 47 97 CB    .....G..
D/HEX AES-dec: 0000-0008: 00 01 02 03 04 05 06 07    ........
               0008-0010: 08 09 0A 0B 0C 0D 0E 0F    ........
               0010-0018: 10 11 12 13 14 15 16 17    ........
               0018-0020: 18 19 1A 1B 1C 1D 1E 1F    ........
D/HEX MD5    : 0000-0008: B4 FF CB 23 73 7C EC 31    ...#s|.1
               0008-0010: 5A 4A 4D 1A A2 A6 20 CE    ZJM... .
D/HEX SHA1   : 0000-0008: AE 5B D8 EF EA 53 22 C4    .[...S".
               0008-0010: D9 98 6D 06 68 0A 78 13    ..m.h.x.
               0010-0018: 92 F9 A6 42                ...BcopymistakeCopy Success

Last updated

Assoc. Prof. Wiroon Sriborrirux, Founder of Advance Innovation Center (AIC) and Bangsaen Design House (BDH), Electrical Engineering Department, Faculty of Engineering, Burapha University