mbedtls | 06 - 非对称加密算法的配置与使用(RSA算法)
发布日期:2021-07-01 02:35:11 浏览次数:2 分类:技术文章

本文共 16321 字,大约阅读时间需要 54 分钟。

mbedtls系列文章

Demo工程源码

本工程基于STM32L41RCT6开发板,包含了本系列文章中所编写的所有Demo,持续更新……


文章目录


一、非对称加密算法——RSA

1. 对称加密算法和非对称加密算法

对称加密算法,比如AES算法,在发送端(加密)和接收端(解密)使用相同的一份秘钥,称为共享秘钥。

非对称加密算法,比如RSA算法,在加密使用公钥,而在解密时使用私钥

2. RSA算法

RSA算法是一种常用的非对称加密算法。

RSA算法主要包括三个过程:

  • 生成秘钥对
  • 使用公钥加密明文
  • 使用私钥解密密文

3. RSA加速技术

RSA算法在计算过程中存在较多的取模运算和幂运算,计算速度比对称加密算法要慢,所以不适合对大量数据进行加密和解密,在实际中常用于加密或解密小数据片段。

RSA公钥加密过程可使用短公开指数进行快速计算,而RSA私钥解密过程可使用中国剩余定理(CRT)进行加速执行。

4. RSA填充方法

RSA加密结果是确定的。当公钥确定的时候,一段明文总是会加密的到对应的密文,这样未免存在安全隐患。

实际使用RSA算法中需要包含填充方案,在计算之前会对明文进行随机注入,这样在公钥和明文相同的情况下,也不会生成相同的秘文。

常用的RSA填充方案有两种:RSAES-OAEP(推荐使用)和RSAES-PKCS1V1_5(较早、不推荐使用)。

二、RSA功能模块的配置与使用

1. 配置宏

使用RSA功能需要提前开启伪随机数生成器(依赖AES算法、SHA256算法、MD通用接口),其中伪随机数生成器的硬件适配移植实现已经讲述,请参考对应的第二篇博客,不再赘述。

综合上述,本实验中需要开启的宏如下表:

宏定义 功能
MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES 不使用默认熵源(如果已有、要屏蔽该宏)
MBEDTLS_NO_PLATFORM_ENTROPY 不使用系统内置熵源
MBEDTLS_AES_C 使用AES算法
MBEDTLS_ENTROPY_C 使能熵源模块
MBEDTLS_CTR_DRBG_C 使能随机数模块
MBEDTLS_SHA256_C 使能SHA256算法
MBEDTLS_MD_C 开启MD通用接口
MBEDTLS_AES_ROM_TABLES 使能预定义S盒(节约内存空间)
MBEDTLS_BIGNUM_C 开启大数运算
MBEDTLS_GENPRIME 开启生成素数
MBEDTLS_OID_C 开启OID数据结构模块
MBEDTLS_RSA_C 开启RSA算法
MBEDTLS_PKCS1_V21 开启PKCS#1 v2.1填充方案(OAEP)

下面补充几个第一次出现宏的定义。

MBEDTLS_BIGNUM_C

/** * \def MBEDTLS_BIGNUM_C * * Enable the multi-precision integer library. * * Module:  library/bignum.c * Caller:  library/dhm.c *          library/ecp.c *          library/ecdsa.c *          library/rsa.c *          library/rsa_internal.c *          library/ssl_tls.c * * This module is required for RSA, DHM and ECC (ECDH, ECDSA) support. */#define MBEDTLS_BIGNUM_C

MBEDTLS_GENPRIME

/** * \def MBEDTLS_GENPRIME * * Enable the prime-number generation code. * * Requires: MBEDTLS_BIGNUM_C */#define MBEDTLS_GENPRIME

MBEDTLS_OID_C

/** * \def MBEDTLS_OID_C * * Enable the OID database. * * Module:  library/oid.c * Caller:  library/asn1write.c *          library/pkcs5.c *          library/pkparse.c *          library/pkwrite.c *          library/rsa.c *          library/x509.c *          library/x509_create.c *          library/x509_crl.c *          library/x509_crt.c *          library/x509_csr.c *          library/x509write_crt.c *          library/x509write_csr.c * * This modules translates between OIDs and internal values. */#define MBEDTLS_OID_C

MBEDTLS_RSA_C

/** * \def MBEDTLS_RSA_C * * Enable the RSA public-key cryptosystem. * * Module:  library/rsa.c *          library/rsa_internal.c * Caller:  library/ssl_cli.c *          library/ssl_srv.c *          library/ssl_tls.c *          library/x509.c * * This module is used by the following key exchanges: *      RSA, DHE-RSA, ECDHE-RSA, RSA-PSK * * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C */#define MBEDTLS_RSA_C

MBEDTLS_PKCS1_V21

/** * \def MBEDTLS_PKCS1_V21 * * Enable support for PKCS#1 v2.1 encoding. * * Requires: MBEDTLS_MD_C, MBEDTLS_RSA_C * * This enables support for RSAES-OAEP and RSASSA-PSS operations. */#define MBEDTLS_PKCS1_V21

编辑针对本实验的配置文件mbedtls_config_rsa.h

/** * @brief   Minimal configuration for RSA Function * @author  mculover666 * @date    2020/09/27*/#ifndef _MBEDTLS_CONFIG_RSA_H_#define _MBEDTLS_CONFIG_RSA_H_/* System support */#define MBEDTLS_HAVE_ASM//#define MBEDTLS_HAVE_TIME/* mbed feature support */#define MBEDTLS_ENTROPY_HARDWARE_ALT//#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES#define MBEDTLS_NO_PLATFORM_ENTROPY/* mbed modules */#define MBEDTLS_AES_C#define MBEDTLS_AES_ROM_TABLES#define MBEDTLS_CTR_DRBG_C#define MBEDTLS_ENTROPY_C#define MBEDTLS_SHA256_C#define MBEDTLS_MD_C#define MBEDTLS_BIGNUM_C#define MBEDTLS_GENPRIME#define MBEDTLS_OID_C#define MBEDTLS_RSA_C#define MBEDTLS_PKCS1_V21#include "mbedtls/check_config.h"#endif /* _MBEDTLS_CONFIG_RSA_H_ */

在MDK配置mbedtls使用该配置文件:

2. RSA功能模块API说明

使用该功能模块需要包含头文件:

#include "mbedtls/rsa.h"

① 初始化RSA结构体:

/** * \brief          This function initializes an RSA context. * * \note           Set padding to #MBEDTLS_RSA_PKCS_V21 for the RSAES-OAEP *                 encryption scheme and the RSASSA-PSS signature scheme. * * \note           The \p hash_id parameter is ignored when using *                 #MBEDTLS_RSA_PKCS_V15 padding. * * \note           The choice of padding mode is strictly enforced for private key *                 operations, since there might be security concerns in *                 mixing padding modes. For public key operations it is *                 a default value, which can be overridden by calling specific *                 \c rsa_rsaes_xxx or \c rsa_rsassa_xxx functions. * * \note           The hash selected in \p hash_id is always used for OEAP *                 encryption. For PSS signatures, it is always used for *                 making signatures, but can be overridden for verifying them. *                 If set to #MBEDTLS_MD_NONE, it is always overridden. * * \param ctx      The RSA context to initialize. This must not be \c NULL. * \param padding  The padding mode to use. This must be either *                 #MBEDTLS_RSA_PKCS_V15 or #MBEDTLS_RSA_PKCS_V21. * \param hash_id  The hash identifier of ::mbedtls_md_type_t type, if *                 \p padding is #MBEDTLS_RSA_PKCS_V21. It is unused *                 otherwise. */void mbedtls_rsa_init( mbedtls_rsa_context *ctx,                       int padding,                       int hash_id );

② RSA生成秘钥对:

/** * \brief          This function generates an RSA keypair. * * \note           mbedtls_rsa_init() must be called before this function, *                 to set up the RSA context. * * \param ctx      The initialized RSA context used to hold the key. * \param f_rng    The RNG function to be used for key generation. *                 This must not be \c NULL. * \param p_rng    The RNG context to be passed to \p f_rng. *                 This may be \c NULL if \p f_rng doesn't need a context. * \param nbits    The size of the public key in bits. * \param exponent The public exponent to use. For example, \c 65537. *                 This must be odd and greater than \c 1. * * \return         \c 0 on success. * \return         An \c MBEDTLS_ERR_RSA_XXX error code on failure. */int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx,                         int (*f_rng)(void *, unsigned char *, size_t),                         void *p_rng,                         unsigned int nbits, int exponent );

③ RSA加密操作,通过参数指定公钥加密:

/** * \brief          This function adds the message padding, then performs an RSA *                 operation. * *                 It is the generic wrapper for performing a PKCS#1 encryption *                 operation using the \p mode from the context. * * \deprecated     It is deprecated and discouraged to call this function *                 in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library *                 are likely to remove the \p mode argument and have it *                 implicitly set to #MBEDTLS_RSA_PUBLIC. * * \note           Alternative implementations of RSA need not support *                 mode being set to #MBEDTLS_RSA_PRIVATE and might instead *                 return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. * * \param ctx      The initialized RSA context to use. * \param f_rng    The RNG to use. It is mandatory for PKCS#1 v2.1 padding *                 encoding, and for PKCS#1 v1.5 padding encoding when used *                 with \p mode set to #MBEDTLS_RSA_PUBLIC. For PKCS#1 v1.5 *                 padding encoding and \p mode set to #MBEDTLS_RSA_PRIVATE, *                 it is used for blinding and should be provided in this *                 case; see mbedtls_rsa_private() for more. * \param p_rng    The RNG context to be passed to \p f_rng. May be *                 \c NULL if \p f_rng is \c NULL or if \p f_rng doesn't *                 need a context argument. * \param mode     The mode of operation. This must be either *                 #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE (deprecated). * \param ilen     The length of the plaintext in Bytes. * \param input    The input data to encrypt. This must be a readable *                 buffer of size \p ilen Bytes. It may be \c NULL if *                 `ilen == 0`. * \param output   The output buffer. This must be a writable buffer *                 of length \c ctx->len Bytes. For example, \c 256 Bytes *                 for an 2048-bit RSA modulus. * * \return         \c 0 on success. * \return         An \c MBEDTLS_ERR_RSA_XXX error code on failure. */int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx,                       int (*f_rng)(void *, unsigned char *, size_t),                       void *p_rng,                       int mode, size_t ilen,                       const unsigned char *input,                       unsigned char *output );

④ RSA解密操作,通过指定私钥解密:

/** * \brief          This function performs an RSA operation, then removes the *                 message padding. * *                 It is the generic wrapper for performing a PKCS#1 decryption *                 operation using the \p mode from the context. * * \note           The output buffer length \c output_max_len should be *                 as large as the size \p ctx->len of \p ctx->N (for example, *                 128 Bytes if RSA-1024 is used) to be able to hold an *                 arbitrary decrypted message. If it is not large enough to *                 hold the decryption of the particular ciphertext provided, *                 the function returns \c MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. * * \deprecated     It is deprecated and discouraged to call this function *                 in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library *                 are likely to remove the \p mode argument and have it *                 implicitly set to #MBEDTLS_RSA_PRIVATE. * * \note           Alternative implementations of RSA need not support *                 mode being set to #MBEDTLS_RSA_PUBLIC and might instead *                 return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. * * \param ctx      The initialized RSA context to use. * \param f_rng    The RNG function. If \p mode is #MBEDTLS_RSA_PRIVATE, *                 this is used for blinding and should be provided; see *                 mbedtls_rsa_private() for more. If \p mode is *                 #MBEDTLS_RSA_PUBLIC, it is ignored. * \param p_rng    The RNG context to be passed to \p f_rng. This may be *                 \c NULL if \p f_rng is \c NULL or doesn't need a context. * \param mode     The mode of operation. This must be either *                 #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated). * \param olen     The address at which to store the length of *                 the plaintext. This must not be \c NULL. * \param input    The ciphertext buffer. This must be a readable buffer *                 of length \c ctx->len Bytes. For example, \c 256 Bytes *                 for an 2048-bit RSA modulus. * \param output   The buffer used to hold the plaintext. This must *                 be a writable buffer of length \p output_max_len Bytes. * \param output_max_len The length in Bytes of the output buffer \p output. * * \return         \c 0 on success. * \return         An \c MBEDTLS_ERR_RSA_XXX error code on failure. */int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx,                       int (*f_rng)(void *, unsigned char *, size_t),                       void *p_rng,                       int mode, size_t *olen,                       const unsigned char *input,                       unsigned char *output,                       size_t output_max_len );

⑤ 释放RSA结构体:

/** * \brief          This function frees the components of an RSA key. * * \param ctx      The RSA context to free. May be \c NULL, in which case *                 this function is a no-op. If it is not \c NULL, it must *                 point to an initialized RSA context. */void mbedtls_rsa_free( mbedtls_rsa_context *ctx );

3. 编写测试函数

新建文件mbedtls_rsa_test.c,编写以下测试内容:

/** * @brief   RSA Function demo * @author  mculover666 * @date    2020/09/27*/#if !defined(MBEDTLS_CONFIG_FILE)#include "mbedtls/config.h"#else#include MBEDTLS_CONFIG_FILE#endif#if defined(MBEDTLS_RSA_C)#include 
#include "string.h"#include "mbedtls/entropy.h"#include "mbedtls/ctr_drbg.h"#include "mbedtls/rsa.h"char buf[516];static void dump_rsa_key(mbedtls_rsa_context *ctx){
size_t olen; printf("\n +++++++++++++++++ rsa keypair +++++++++++++++++\n\n"); mbedtls_mpi_write_string(&ctx->N , 16, buf, sizeof(buf), &olen); printf("N: %s\n", buf); mbedtls_mpi_write_string(&ctx->E , 16, buf, sizeof(buf), &olen); printf("E: %s\n", buf); mbedtls_mpi_write_string(&ctx->D , 16, buf, sizeof(buf), &olen); printf("D: %s\n", buf); mbedtls_mpi_write_string(&ctx->P , 16, buf, sizeof(buf), &olen); printf("P: %s\n", buf); mbedtls_mpi_write_string(&ctx->Q , 16, buf, sizeof(buf), &olen); printf("Q: %s\n", buf); mbedtls_mpi_write_string(&ctx->DP, 16, buf, sizeof(buf), &olen); printf("DP: %s\n", buf); mbedtls_mpi_write_string(&ctx->DQ, 16, buf, sizeof(buf), &olen); printf("DQ: %s\n", buf); mbedtls_mpi_write_string(&ctx->QP, 16, buf, sizeof(buf), &olen); printf("QP: %s\n", buf); printf("\n +++++++++++++++++ rsa keypair +++++++++++++++++\n\n");}static void dump_buf(uint8_t *buf, uint32_t len){
int i; for (i = 0; i < len; i++) {
printf("%s%02X%s", i % 16 == 0 ? "\r\n\t" : " ", buf[i], i == len - 1 ? "\r\n" : ""); }}uint8_t output_buf[2048/8];int mbedtls_rsa_test(void){
int ret; size_t olen; const char* msg = "HelloWorld"; uint8_t decrypt_buf[20]; const char *pers = "rsa_test"; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_rsa_context ctx; /* 1. init structure */ mbedtls_entropy_init(&entropy); mbedtls_ctr_drbg_init(&ctr_drbg); mbedtls_rsa_init(&ctx, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256); /* 2. update seed with we own interface ported */ printf( "\n . Seeding the random number generator..." ); ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) pers, strlen(pers)); if(ret != 0) {
printf( " failed\n ! mbedtls_ctr_drbg_seed returned %d(-0x%04x)\n", ret, -ret); goto exit; } printf( " ok\n" ); /* 3. generate an RSA keypair */ printf( "\n . Generate RSA keypair..." ); ret = mbedtls_rsa_gen_key(&ctx, mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537); if(ret != 0) {
printf( " failed\n ! mbedtls_rsa_gen_key returned %d(-0x%04x)\n", ret, -ret); goto exit; } printf( " ok\n" ); /* shwo RSA keypair */ dump_rsa_key(&ctx); /* 4. encrypt */ printf( "\n . RSA pkcs1 encrypt..." ); ret = mbedtls_rsa_pkcs1_encrypt(&ctx, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, strlen(msg), (uint8_t *)msg, output_buf); if(ret != 0) {
printf( " failed\n ! mbedtls_rsa_pkcs1_encrypt returned %d(-0x%04x)\n", ret, -ret); goto exit; } printf( " ok\n" ); /* show encrypt result */ dump_buf(output_buf, sizeof(output_buf)); /* 5. decrypt */ printf( "\n . RSA pkcs1 decrypt..." ); ret = mbedtls_rsa_pkcs1_decrypt(&ctx, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PRIVATE, &olen, output_buf, decrypt_buf, sizeof(decrypt_buf)); if(ret != 0) {
printf( " failed\n ! mbedtls_rsa_pkcs1_decrypt returned %d(-0x%04x)\n", ret, -ret); goto exit; } printf( " ok\n" ); /* show decrypt result */ decrypt_buf[olen] = '\0'; printf("decrypt result:[%s]\r\n", decrypt_buf); exit: /* 5. release structure */ mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); mbedtls_rsa_free(&ctx); return ret;}#endif /* MBEDTLS_RSA_C */

4. 测试结果

在 main.c 中声明该测试函数:

extern int mbedtls_rsa_test(void);

然后在main函数中调用:

/* 5. rsa test */mbedtls_rsa_test();

5. 堆内存空间的设置

特别注意:

mbedtls RSA算法中的生成秘钥对比较占用空间,再加上RSA算法计算过程涉及到大数运算,所以RSA算法对内存的消耗比较大。

mbedtls使用的是动态内存,从堆空间中分配,所以要在STM32启动文件中将堆空间设置的大一点:

6. 测试结果

编译、下载到开发板中,可以看到:

① 秘钥对生成结果(花费大概5min左右,主控芯片STM32L431主频为80Mhz):

② 使用公钥加密结果(因为RSA算法中的特性,所以同一份程序,同一份明文,每次重新运行生成的密文也不同):

③ 使用私钥解密结果:

接收精彩文章及资源推送,请订阅我的微信公众号:『mculover666』

转载地址:https://mculover666.blog.csdn.net/article/details/108814108 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:mbedtls | 07 - DH秘钥协商算法的配置与使用
下一篇:mbedtls | 05 - 消息认证码的配置与使用(HMAC算法、GCM算法)

发表评论

最新留言

关注你微信了!
[***.104.42.241]2024年04月23日 14时12分28秒