mbedtls | 08 - ECDH秘钥协商算法的配置与使用
发布日期:2021-07-01 02:35:12 浏览次数:2 分类:技术文章

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

mbedtls系列文章

Demo工程源码

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


文章目录


一、ECDH秘钥协商算法

ECDH是一种秘钥协商算法,使得通信双方在不安全通道交换共享参数,从而使用共享参数和自身私密参数计算出一个会话秘钥。

ECDH秘钥协商算法基于椭圆曲线密码系统(ECC),使用较短的秘钥长度可提供与RSA或DH算法同样的安全等级,秘钥长度为160-256bit的椭圆曲线算法,与1024-3072bit的非ECC算法安全强度相同

ECDH秘钥协商的过程如下:

① 通信双方选择共同的椭圆曲线方程、相同的大素数P、相同的生成元G;

② 通信方A生成一个随机数作为自己的私钥,通过椭圆曲线标量乘法得到公开参数(公钥);

③ 通信方B生成一个随机数作为自己的私钥,通过椭圆曲线标量乘法得到公开参数(公钥);

④ 通信双方交换公钥,和自己的私钥一起计算得到共同的会话秘钥。

二、ECDH秘钥协商功能的配置和使用

1. 配置宏

使用ECDH秘钥协商功能需要提前开启伪随机数生成器(依赖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_ECP_C 开启椭圆曲线基础运算
MBEDTLS_ECDH_C 开启椭圆曲线秘钥协商算法模块
MBEDTLS_ECP_DP_SECP256R1_ENABLED 选择secp256r1曲线参数

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

MBEDTLS_ECP_C

/** * \def MBEDTLS_ECP_C * * Enable the elliptic curve over GF(p) library. * * Module:  library/ecp.c * Caller:  library/ecdh.c *          library/ecdsa.c *          library/ecjpake.c * * Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED */#define MBEDTLS_ECP_C

MBEDTLS_ECDH_C

/** * \def MBEDTLS_ECDH_C * * Enable the elliptic curve Diffie-Hellman library. * * Module:  library/ecdh.c * Caller:  library/ssl_cli.c *          library/ssl_srv.c * * This module is used by the following key exchanges: *      ECDHE-ECDSA, ECDHE-RSA, DHE-PSK * * Requires: MBEDTLS_ECP_C */#define MBEDTLS_ECDH_C

MBEDTLS_ECP_DP_SECP256R1_ENABLED(至少开启一种)

/** * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED * * MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve * module.  By default all supported curves are enabled. * * Comment macros to disable the curve and functions for it *///#define MBEDTLS_ECP_DP_SECP192R1_ENABLED//#define MBEDTLS_ECP_DP_SECP224R1_ENABLED#define MBEDTLS_ECP_DP_SECP256R1_ENABLED//#define MBEDTLS_ECP_DP_SECP384R1_ENABLED//#define MBEDTLS_ECP_DP_SECP521R1_ENABLED//#define MBEDTLS_ECP_DP_SECP192K1_ENABLED//#define MBEDTLS_ECP_DP_SECP224K1_ENABLED//#define MBEDTLS_ECP_DP_SECP256K1_ENABLED//#define MBEDTLS_ECP_DP_BP256R1_ENABLED//#define MBEDTLS_ECP_DP_BP384R1_ENABLED//#define MBEDTLS_ECP_DP_BP512R1_ENABLED//#define MBEDTLS_ECP_DP_CURVE25519_ENABLED//#define MBEDTLS_ECP_DP_CURVE448_ENABLED

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

/** * @brief   Minimal configuration for ECDH Function * @author  mculover666 * @date    2020/09/30*/#ifndef _MBEDTLS_CONFIG_ECDH_H_#define _MBEDTLS_CONFIG_ECDH_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_ECP_C#define MBEDTLS_ECDH_C#define MBEDTLS_ECP_DP_SECP256R1_ENABLED#include "mbedtls/check_config.h"#endif /* _MBEDTLS_CONFIG_ECDH_H_ */

2. ECDH秘钥协商功能API说明

① 初始化椭圆曲线群结构体

/** * \brief           This function initializes an ECP group context *                  without loading any domain parameters. * * \note            After this function is called, domain parameters *                  for various ECP groups can be loaded through the *                  mbedtls_ecp_group_load() or mbedtls_ecp_tls_read_group() *                  functions. */void mbedtls_ecp_group_init( mbedtls_ecp_group *grp );

② 初始化椭圆曲线点结构体:

/** * \brief           This function initializes an ECP group context *                  without loading any domain parameters. * * \note            After this function is called, domain parameters *                  for various ECP groups can be loaded through the *                  mbedtls_ecp_group_load() or mbedtls_ecp_tls_read_group() *                  functions. */void mbedtls_ecp_group_init( mbedtls_ecp_group *grp );

③ 加载椭圆曲线:

/** * \brief           This function sets up an ECP group context *                  from a standardized set of domain parameters. * * \note            The index should be a value of the NamedCurve enum, *                  as defined in RFC-4492: Elliptic Curve Cryptography *                  (ECC) Cipher Suites for Transport Layer Security (TLS), *                  usually in the form of an \c MBEDTLS_ECP_DP_XXX macro. * * \param grp       The group context to setup. This must be initialized. * \param id        The identifier of the domain parameter set to load. * * \return          \c 0 on success. * \return          #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if \p id doesn't *                  correspond to a known group. * \return          Another negative error code on other kinds of failure. */int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id );

④ 生成公开参数:

/** * \brief           This function generates an ECDH keypair on an elliptic *                  curve. * *                  This function performs the first of two core computations *                  implemented during the ECDH key exchange. The second core *                  computation is performed by mbedtls_ecdh_compute_shared(). * * \see             ecp.h * * \param grp       The ECP group to use. This must be initialized and have *                  domain parameters loaded, for example through *                  mbedtls_ecp_load() or mbedtls_ecp_tls_read_group(). * \param d         The destination MPI (private key). *                  This must be initialized. * \param Q         The destination point (public key). *                  This must be initialized. * \param f_rng     The RNG function to use. This must not be \c NULL. * \param p_rng     The RNG context to be passed to \p f_rng. This may be *                  \c NULL in case \p f_rng doesn't need a context argument. * * \return          \c 0 on success. * \return          Another \c MBEDTLS_ERR_ECP_XXX or *                  \c MBEDTLS_MPI_XXX error code on failure. */int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q,                     int (*f_rng)(void *, unsigned char *, size_t),                     void *p_rng );

⑤ 计算共享秘钥:

/** * \brief           This function computes the shared secret. * *                  This function performs the second of two core computations *                  implemented during the ECDH key exchange. The first core *                  computation is performed by mbedtls_ecdh_gen_public(). * * \see             ecp.h * * \note            If \p f_rng is not NULL, it is used to implement *                  countermeasures against side-channel attacks. *                  For more information, see mbedtls_ecp_mul(). * * \param grp       The ECP group to use. This must be initialized and have *                  domain parameters loaded, for example through *                  mbedtls_ecp_load() or mbedtls_ecp_tls_read_group(). * \param z         The destination MPI (shared secret). *                  This must be initialized. * \param Q         The public key from another party. *                  This must be initialized. * \param d         Our secret exponent (private key). *                  This must be initialized. * \param f_rng     The RNG function. This may be \c NULL if randomization *                  of intermediate results during the ECP computations is *                  not needed (discouraged). See the documentation of *                  mbedtls_ecp_mul() for more. * \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 argument. * * \return          \c 0 on success. * \return          Another \c MBEDTLS_ERR_ECP_XXX or *                  \c MBEDTLS_MPI_XXX error code on failure. */int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z,                         const mbedtls_ecp_point *Q, const mbedtls_mpi *d,                         int (*f_rng)(void *, unsigned char *, size_t),                         void *p_rng );

⑥ 释放椭圆曲线群结构体:

/** * \brief           This function frees the components of an ECP group. * * \param grp       The group to free. This may be \c NULL, in which *                  case this function returns immediately. If it is not *                  \c NULL, it must point to an initialized ECP group. */void mbedtls_ecp_group_free( mbedtls_ecp_group *grp );

⑦ 释放椭圆曲线点结构体:

/** * \brief           This function frees the components of a point. * * \param pt        The point to free. */void mbedtls_ecp_point_free( mbedtls_ecp_point *pt );

⑧ 错误码(ECP计算部分)

/* * ECP error codes */#define MBEDTLS_ERR_ECP_BAD_INPUT_DATA                    -0x4F80  /**< Bad input parameters to function. */#define MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL                  -0x4F00  /**< The buffer is too small to write to. */#define MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE               -0x4E80  /**< The requested feature is not available, for example, the requested curve is not supported. */#define MBEDTLS_ERR_ECP_VERIFY_FAILED                     -0x4E00  /**< The signature is not valid. */#define MBEDTLS_ERR_ECP_ALLOC_FAILED                      -0x4D80  /**< Memory allocation failed. */#define MBEDTLS_ERR_ECP_RANDOM_FAILED                     -0x4D00  /**< Generation of random value, such as ephemeral key, failed. */#define MBEDTLS_ERR_ECP_INVALID_KEY                       -0x4C80  /**< Invalid private or public key. */#define MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH                  -0x4C00  /**< The buffer contains a valid signature followed by more data. *//* MBEDTLS_ERR_ECP_HW_ACCEL_FAILED is deprecated and should not be used. */#define MBEDTLS_ERR_ECP_HW_ACCEL_FAILED                   -0x4B80  /**< The ECP hardware accelerator failed. */#define MBEDTLS_ERR_ECP_IN_PROGRESS                       -0x4B00  /**< Operation in progress, call again with the same parameters to continue. */

3. 编写测试函数

新建测试文件mbedtls_ecdh_test.c,编写以下测试内容,其中服务器和客户端之间直接通信,没有采用网络通信:

/** * @brief   EDCH Function demo * @author  mculover666 * @date    2020/09/30*/#if !defined(MBEDTLS_CONFIG_FILE)#include "mbedtls/config.h"#else#include MBEDTLS_CONFIG_FILE#endif#if defined(MBEDTLS_ECDH_C)#include 
#include "string.h"#include "mbedtls/entropy.h"#include "mbedtls/ctr_drbg.h"#include "mbedtls/ecdh.h"#define GENERATOR "2"#define T_P "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695" \ "A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617A"\ "D3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935"\ "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797A"\ "BC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4"\ "AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61"\ "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005"\ "C58EF1837D1683B2C6F34A26C1B2EFFA886B423861285C97FFFFFFFFFFFFFFFF"uint8_t buf[65];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" : ""); }}int mbedtls_ecdh_test(void){
int ret; size_t olen; const char *pers = "ecdh_test"; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ecp_point client_pub, server_pub; mbedtls_ecp_group grp; mbedtls_mpi client_secret, server_secret; mbedtls_mpi client_pri, server_pri; /* 1. init structure */ mbedtls_entropy_init(&entropy); mbedtls_ctr_drbg_init(&ctr_drbg); mbedtls_mpi_init(&client_secret); mbedtls_mpi_init(&server_secret); mbedtls_mpi_init(&client_pri); mbedtls_mpi_init(&server_pri); mbedtls_ecp_group_init(&grp); mbedtls_ecp_point_init(&client_pub); mbedtls_ecp_point_init(&server_pub); /* 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. select ecp group SECP256R1 */ printf("\n . Select ecp group SECP256R1..."); ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1); if(ret != 0) {
printf( " failed\n ! mbedtls_ecp_group_load returned %d(-0x%04x)\n", ret, -ret); goto exit; } printf("ok\r\n"); /* 4. Client generate public parameter */ printf("\n . Client Generate public parameter..."); ret = mbedtls_ecdh_gen_public(&grp, &client_pri, &client_pub, mbedtls_ctr_drbg_random, &ctr_drbg); if(ret != 0) {
printf( " failed\n ! mbedtls_ecdh_gen_public returned %d(-0x%04x)\n", ret, -ret); goto exit; } printf( " ok\n" ); /* show public parameter */ mbedtls_ecp_point_write_binary(&grp, &client_pub, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, buf, sizeof(buf)); dump_buf(buf, olen); /* 5. Client generate public parameter */ printf("\n . Server Generate public parameter..."); ret = mbedtls_ecdh_gen_public(&grp, &server_pri, &server_pub, mbedtls_ctr_drbg_random, &ctr_drbg); if(ret != 0) {
printf( " failed\n ! mbedtls_ecdh_gen_public returned %d(-0x%04x)\n", ret, -ret); goto exit; } printf( " ok\n" ); /* show public parameter */ mbedtls_ecp_point_write_binary(&grp, &server_pub, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, buf, sizeof(buf)); dump_buf(buf, olen); /* 6. Calc shared secret */ printf("\n . Client Calc shared secret..."); ret = mbedtls_ecdh_compute_shared(&grp, &client_secret, &server_pub, &client_pri, mbedtls_ctr_drbg_random, &ctr_drbg); if(ret != 0) {
printf( " failed\n ! mbedtls_ecdh_compute_shared returned %d(-0x%04x)\n", ret, -ret); goto exit; } printf( " ok\n" ); /* show public parameter */ mbedtls_mpi_write_binary(&client_secret, buf, sizeof(buf)); dump_buf(buf, olen); /* 7. Server Calc shared secret */ printf("\n . Server Calc shared secret..."); ret = mbedtls_ecdh_compute_shared(&grp, &server_secret, &client_pub, &server_pri, mbedtls_ctr_drbg_random, &ctr_drbg); if(ret != 0) {
printf( " failed\n ! mbedtls_ecdh_compute_shared returned %d(-0x%04x)\n", ret, -ret); goto exit; } printf( " ok\n" ); /* show public parameter */ mbedtls_mpi_write_binary(&server_secret, buf, sizeof(buf)); dump_buf(buf, olen); /* 8. mpi compare */ ret = mbedtls_mpi_cmp_mpi(&server_secret, &client_secret); printf("compare result: %d\r\n", ret); exit: /* 10. release structure */ mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); mbedtls_mpi_free(&client_secret); mbedtls_mpi_free(&server_secret); mbedtls_mpi_free(&client_pri); mbedtls_mpi_free(&server_pri); mbedtls_ecp_group_free(&grp); mbedtls_ecp_point_free(&client_pub); mbedtls_ecp_point_free(&server_pub); return ret;}#endif /* MBEDTLS_DHM_C */

4. 调用测试函数

在 main.c 中声明:

extern int mbedtls_ecdh_test(void);

在 main 函数中调用此测试函数:

/* 7. ecdh test */mbedtls_ecdh_test();

编译、下载、在串口助手查看结果:

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

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

上一篇:mbedtls | 09 - 数字签名算法的配置与使用(RSA数字签名算法、ECDSA数字签名算法)
下一篇:mbedtls | 07 - DH秘钥协商算法的配置与使用

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月28日 06时36分03秒