本文共 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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!