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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
路过,博主的博客真漂亮。。
[***.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