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

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

mbedtls系列文章

Demo工程源码

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


文章目录


一、DH秘钥协商算法

DH是一种秘钥协商算法,使得通信双方在不安全通道交换共享参数,从而协商出一个会话秘钥。

DH秘钥协商的过程如下:

① 通信双方A和B确认共享参数;

② A生成随机秘钥x;
③ B生成随机秘钥y;
④ A计算共享秘钥;
⑤ B计算共享秘钥;

DH秘钥协商算法可以有效防止中间窃听者,但是无法方式中间拦截者。

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

1. 配置宏

使用DH秘钥协商功能需要提前开启伪随机数生成器(依赖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_DHM_C 开启DH秘钥协商模块

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

MBEDTLS_DHM_C

/** * \def MBEDTLS_DHM_C * * Enable the Diffie-Hellman-Merkle module. * * Module:  library/dhm.c * Caller:  library/ssl_cli.c *          library/ssl_srv.c * * This module is used by the following key exchanges: *      DHE-RSA, DHE-PSK * * \warning    Using DHE constitutes a security risk as it *             is not possible to validate custom DH parameters. *             If possible, it is recommended users should consider *             preferring other methods of key exchange. *             See dhm.h for more details. * */#define MBEDTLS_DHM_C

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

/** * @brief   Minimal configuration for DHM Function * @author  mculover666 * @date    2020/09/28*/#ifndef _MBEDTLS_CONFIG_DHM_H_#define _MBEDTLS_CONFIG_DHM_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_DHM_C#include "mbedtls/check_config.h"#endif /* _MBEDTLS_CONFIG_DHM_H_ */

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

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

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

#include "mbedtls/dhm.h"

① 初始化DH结构体:

/** * \brief          This function initializes the DHM context. * * \param ctx      The DHM context to initialize. */void mbedtls_dhm_init( mbedtls_dhm_context *ctx );

② 生成公开参数:

/** * \brief          This function creates a DHM key pair and exports *                 the raw public key in big-endian format. * * \note           The destination buffer is always fully written *                 so as to contain a big-endian representation of G^X mod P. *                 If it is larger than \c ctx->len, it is padded accordingly *                 with zero-bytes at the beginning. * * \param ctx      The DHM context to use. This must be initialized and *                 have the DHM parameters set. It may or may not already *                 have imported the peer's public key. * \param x_size   The private key size in Bytes. * \param output   The destination buffer. This must be a writable buffer of *                 size \p olen Bytes. * \param olen     The length of the destination buffer. This must be at least *                 equal to `ctx->len` (the size of \c P). * \param f_rng    The RNG function. 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 argument. * * \return         \c 0 on success. * \return         An \c MBEDTLS_ERR_DHM_XXX error code on failure. */int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size,                     unsigned char *output, size_t olen,                     int (*f_rng)(void *, unsigned char *, size_t),                     void *p_rng );

③ 读取公开参数:

/** * \brief          This function imports the raw public value of the peer. * * \note           In a TLS handshake, this is the how the server imports *                 the Client's public DHM key. * * \param ctx      The DHM context to use. This must be initialized and have *                 its DHM parameters set, e.g. via mbedtls_dhm_set_group(). *                 It may or may not already have generated its own private key. * \param input    The input buffer containing the \c G^Y value of the peer. *                 This must be a readable buffer of size \p ilen Bytes. * \param ilen     The size of the input buffer \p input in Bytes. * * \return         \c 0 on success. * \return         An \c MBEDTLS_ERR_DHM_XXX error code on failure. */int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx,                     const unsigned char *input, size_t ilen );

④ 计算共享秘钥:

/** * \brief          This function derives and exports the shared secret *                 \c (G^Y)^X mod \c P. * * \note           If \p f_rng is not \c NULL, it is used to blind the input as *                 a countermeasure against timing attacks. Blinding is used *                 only if our private key \c X is re-used, and not used *                 otherwise. We recommend always passing a non-NULL *                 \p f_rng argument. * * \param ctx           The DHM context to use. This must be initialized *                      and have its own private key generated and the peer's *                      public key imported. * \param output        The buffer to write the generated shared key to. This *                      must be a writable buffer of size \p output_size Bytes. * \param output_size   The size of the destination buffer. This must be at *                      least the size of \c ctx->len (the size of \c P). * \param olen          On exit, holds the actual number of Bytes written. * \param f_rng         The RNG function, for blinding purposes. This may *                      b \c NULL if blinding isn't needed. * \param p_rng         The RNG context. This may be \c NULL if \p f_rng *                      doesn't need a context argument. * * \return              \c 0 on success. * \return              An \c MBEDTLS_ERR_DHM_XXX error code on failure. */int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx,                     unsigned char *output, size_t output_size, size_t *olen,                     int (*f_rng)(void *, unsigned char *, size_t),                     void *p_rng );

⑤ 释放DH结构体:

/** * \brief          This function frees and clears the components *                 of a DHM context. * * \param ctx      The DHM context to free and clear. This 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 DHM context. */void mbedtls_dhm_free( mbedtls_dhm_context *ctx );

⑥ 错误码:

#define MBEDTLS_ERR_DHM_BAD_INPUT_DATA                    -0x3080  /**< Bad input parameters. */#define MBEDTLS_ERR_DHM_READ_PARAMS_FAILED                -0x3100  /**< Reading of the DHM parameters failed. */#define MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED                -0x3180  /**< Making of the DHM parameters failed. */#define MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED                -0x3200  /**< Reading of the public values failed. */#define MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED                -0x3280  /**< Making of the public value failed. */#define MBEDTLS_ERR_DHM_CALC_SECRET_FAILED                -0x3300  /**< Calculation of the DHM secret failed. */#define MBEDTLS_ERR_DHM_INVALID_FORMAT                    -0x3380  /**< The ASN.1 data is not formatted correctly. */#define MBEDTLS_ERR_DHM_ALLOC_FAILED                      -0x3400  /**< Allocation of memory failed. */#define MBEDTLS_ERR_DHM_FILE_IO_ERROR                     -0x3480  /**< Read or write of file failed. *//* MBEDTLS_ERR_DHM_HW_ACCEL_FAILED is deprecated and should not be used. */#define MBEDTLS_ERR_DHM_HW_ACCEL_FAILED                   -0x3500  /**< DHM hardware accelerator failed. */#define MBEDTLS_ERR_DHM_SET_GROUP_FAILED                  -0x3580  /**< Setting the modulus and generator failed. */

3. 编写测试函数

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

/** * @brief   DHM Function demo * @author  mculover666 * @date    2020/09/28*/#if !defined(MBEDTLS_CONFIG_FILE)#include "mbedtls/config.h"#else#include MBEDTLS_CONFIG_FILE#endif#if defined(MBEDTLS_DHM_C)#include 
#include "string.h"#include "mbedtls/entropy.h"#include "mbedtls/ctr_drbg.h"#include "mbedtls/dhm.h"#define GENERATOR "2"#define T_P "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695" \ "A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617A"\ "D3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935"\ "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797A"\ "BC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4"\ "AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61"\ "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005"\ "C58EF1837D1683B2C6F34A26C1B2EFFA886B423861285C97FFFFFFFFFFFFFFFF"uint8_t server_pub[256];uint8_t client_pub[256];uint8_t server_secret[256];uint8_t client_secret[256];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_dhm_test(void){
int ret; size_t olen; const char *pers = "dhm_test"; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_dhm_context dhm_server, dhm_client; /* 1. init structure */ mbedtls_entropy_init(&entropy); mbedtls_ctr_drbg_init(&ctr_drbg); mbedtls_dhm_init(&dhm_server); mbedtls_dhm_init(&dhm_client); /* 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. genetate 2048 bit prime(G, P) */ printf("\n . Genetate 2048 bit prime(G, P)..."); mbedtls_mpi_read_string(&dhm_server.P, 16, T_P); mbedtls_mpi_read_string(&dhm_server.G, 10, GENERATOR); dhm_server.len = mbedtls_mpi_size(&dhm_server.P); mbedtls_mpi_read_string(&dhm_client.P, 16, T_P); mbedtls_mpi_read_string(&dhm_client.G, 10, GENERATOR); dhm_client.len = mbedtls_mpi_size(&dhm_client.P); printf("ok\r\n"); /* 4. Server create a DHM key pair */ printf("\n . Server creates a DHM key pair..."); ret = mbedtls_dhm_make_public(&dhm_server, 256, server_pub, sizeof(server_pub), mbedtls_ctr_drbg_random, &ctr_drbg); if(ret != 0) {
printf( " failed\n ! mbedtls_dhm_make_public returned %d(-0x%04x)\n", ret, -ret); goto exit; } printf( " ok\n" ); dump_buf(server_pub, sizeof(server_pub)); /* 5. Client creates a DHM key pair */ printf("\n . Client create a DHM key pair..."); ret = mbedtls_dhm_make_public(&dhm_client, 256, client_pub, sizeof(client_pub), mbedtls_ctr_drbg_random, &ctr_drbg); if(ret != 0) {
printf( " failed\n ! mbedtls_dhm_make_public returned %d(-0x%04x)\n", ret, -ret); goto exit; } printf( " ok\n" ); dump_buf(client_pub, sizeof(client_pub)); /* 6. Server Read public key pair */ printf("\n . Server Read public key pair..."); ret = mbedtls_dhm_read_public(&dhm_server, client_pub, sizeof(client_pub)); if(ret != 0) {
printf( " failed\n ! mbedtls_dhm_read_public returned %d(-0x%04x)\n", ret, -ret); goto exit; } printf( " ok\n" ); /* 7. Client Read public key pair */ printf("\n . Client Read public key pair..."); ret = mbedtls_dhm_read_public(&dhm_client, server_pub, sizeof(server_pub)); if(ret != 0) {
printf( " failed\n ! mbedtls_dhm_read_public returned %d(-0x%04x)\n", ret, -ret); goto exit; } printf( " ok\n" ); /* 8. calc the shared secret */ printf("\n . Server calc the shared secret..."); ret = mbedtls_dhm_calc_secret(&dhm_server, server_secret, sizeof(server_secret), &olen, mbedtls_ctr_drbg_random, &ctr_drbg); if(ret != 0) {
printf( " failed\n ! mbedtls_dhm_calc_secret returned %d(-0x%04x)\n", ret, -ret); goto exit; } printf( " ok\n" ); dump_buf(server_secret, sizeof(server_secret)); /* 9. calc the shared secret */ printf("\n . Client calc the shared secret..."); ret = mbedtls_dhm_calc_secret(&dhm_client, client_secret, sizeof(client_secret), &olen, mbedtls_ctr_drbg_random, &ctr_drbg); if(ret != 0) {
printf( " failed\n ! mbedtls_dhm_calc_secret returned %d(-0x%04x)\n", ret, -ret); goto exit; } printf( " ok\n" ); dump_buf(client_secret, sizeof(client_secret)); exit: /* 10. release structure */ mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); mbedtls_dhm_free(&dhm_server); mbedtls_dhm_free(&dhm_client); return ret;}#endif /* MBEDTLS_DHM_C */

4. 测试结果

在 mian.c 中声明此测试函数:

extern int mbedtls_dhm_test(void);

然后在main函数中调用测试函数:

/* 6. dh test */mbedtls_dhm_test();

因为本实验内存消耗较大,需要加大堆空间:

编译、下载、测试结果如下。

① 服务端生成的公开参数:

② 客户端生成的公开参数(可以看到与服务端的公开参数不同):
③ 服务端计算共享秘钥:
④ 客户端计算共享秘钥(可以看到与服务端相同):
接收精彩文章及资源推送,请订阅我的微信公众号:『mculover666』

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

上一篇:mbedtls | 08 - ECDH秘钥协商算法的配置与使用
下一篇:mbedtls | 06 - 非对称加密算法的配置与使用(RSA算法)

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2024年04月25日 13时45分01秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

Scala学习第十天 Scala单例对象、伴生对象实战详解 2019-05-03
Scala学习第十一天 Scala中的apply实战详解 2019-05-03
Scala学习第七天 Scala类的属性和对象私有字段实战详解 2019-05-03
Scala学习第六天 Map、Tuple、Zip实战解析 2019-05-03
Scala学习第四天 Scala的For与Function进阶实战、Lazy的使用 2019-05-03
Scala学习第三天 Tuple、Array、May与文件操作入门实战 2019-05-03
Scala学习第二天 Scala函数定义、流程控制、异常处理 2019-05-03
Scala学习第五天 Scala数组操作实战详解 2019-05-03
基于key-value的存储系统Redis 2019-05-03
Scala学习第十二天 Scala中的继承:超类的构造、重写字段、重写方法代码实战 2019-05-03
Scala学习第十三天 抽象类、抽象字段、抽象方法 2019-05-03
Scala学习第十四天 Scala中作为接口的trait、在对象中混入trait代码实战 2019-05-03
Scala学习第十五天 Scala多重继承、多重继承构造器执行顺序及AOP实现 2019-05-03
Scala学习第十六天 包的定义、包对象、包的引用、包的隐式引用代码实战 2019-05-03
Scala学习第十七天 包、类、对象、成员、伴生类、伴生对象访问权限实战彻底详解 2019-05-03
Scala学习第十八天 文件的读取、写入、控制台输入操作代码实战 2019-05-03
Scala学习第十九天 正则表达式、与模式匹配结合的的Reg代码实战 2019-05-03
剑指offer:栈的压入、弹出序列(java) 2019-05-03
剑指offer:往上到下打印二叉树(java) 2019-05-03
剑指offer:二叉搜索树的后序遍历序列(java) 2019-05-03