mbedtls学习(8)ECDH密钥协商

ECDH密钥协商

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

常用有限域上的椭圆曲线

椭圆曲线由以下参数组成
T=(p,a,b,G,n,h)

  • p 有限域中的大素数,长度一般224比特、256比特、384比特
  • a 整数,椭圆方程系数
  • b整数,椭圆方程系数
  • G,椭圆曲线上某点,生成元
  • n,为一个素数,表示椭圆曲线的阶
  • h,余因数
    其中G包含Gx和Gy 2个参数,非压缩模式以04开始,压缩模式以03开始,实际以非压缩模式
    通过模数p和系数a,b构成椭圆曲线方程
    y^2=x^3+ax+b mod p
    TLS支持很多椭圆曲线,常用的有2个secp256r1和secp284r1

secp256r1
大素数p长度256比特(32字节)

p=FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
a=FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC
b=5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B
生成源G(Gx,Gy)
Gx=6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296
Gy=4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5
椭圆曲线的阶n
n=FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551

secp384r1
大素数p长度384比特(48字节)

省略。。。
ECDH密钥协商步骤

其实和DH思想一样,只不过这是基于椭圆曲线离散对数上实现的。

  • ECDH共享参数
    Alice和Bob进行ECDH密钥协商之前双方要有共同的ECDH共享参数即必须选择相同的椭圆曲线方程、大素数p、生成源G,实际中这些椭圆曲线已经被相关组织标准,比如上边的secp256r1、secp384r1,通过这个双方就确定了这些共享参数

  • ECHD密钥协商
    1.Alice选择一个比椭圆曲线阶小的随机数dA作为私密参数,计算QA=dA G=(xA,yA)发送给Bob
    2.Bob选择一个比椭圆曲线阶小的随机数dB作为私密参数,计算QB=dB G=(xB,yB)发送给Alice
    3.Bob收到QA并计算得到共享密钥参数KB=dB QA=dB(dA G)
    4.Alice收到QB并计算得到共享密钥参数KA=dA QB=dA(dB G)
    根据椭圆曲线结合律dB(dA G) = dA(dB G) = (xQ,yQ),即获得共享密钥KA=KB,KA和KB是一个坐标点,所以共享密钥可以是xQ,yQ两部分也可以是xQ单一部分,若共享曲线是secp256r1,则xQ,yQ长度均256比特,如共享曲线是secp384r1,则xQ,yQ长度均384比特
    如下图
    在这里插入图片描述

mbedtls椭圆曲线模块
  • ecp.c/ecp.h 椭圆曲线基本操作
  • ecp_curves.c 椭圆曲线定义
  • ecdh.c/ecdh.h 椭圆曲线密钥协商
  • ecdsa.c/ecdsa.h 椭圆曲线数据签名

mbedtls所支持的椭圆曲线可以通过config.h 中下面这些宏使能或者关闭,这些宏是ecp_curves.c中条件的编译

/**
 * \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
mbedtls ECHDH例子

先要打开这些宏,这个例子还是想DH协商那样通过共享内存来模拟网络交换共享参数。

#define MBEDTLS_AES_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_ECP_C            开启椭圆曲线基础运算
#define MBEDTLS_ECDH_C           开启椭圆曲线密钥协商
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED 选择secp256r1曲线参数
#define MBEDTLS_AES_ROM_TABLES
#include <stdio.h>
#include <string.h>
#include <stdint.h>

#include "mbedtls/ecdh.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/platform.h"

#define assert_exit(cond, ret) \
    do { if (!(cond)) { \
        printf("  !. assert: failed [line: %d, error: -0x%04X]\n", __LINE__, -ret); \
        goto cleanup; \
    } } while (0)
/*
static int entropy_source(void *data, uint8_t *output, size_t len, size_t *olen)
{
    uint32_t seed;
    seed = sys_rand32_get();
    if (len > sizeof(seed)) {
        len = sizeof(seed);
    }
    memcpy(output, &seed, len);
    *olen = len;
    return 0;
}*/

static void dump_buf(char *info, uint8_t *buf, uint32_t len)
{
    mbedtls_printf("%s", info);
    for (int i = 0; i < len; i++) {
        mbedtls_printf("%s%02X%s", i % 16 == 0 ? "\n     ":" ", 
                        buf[i], i == len - 1 ? "\n":"");
    }
}

int main(void)
{
    int ret = 0;
    size_t olen;
    char buf[65];
    mbedtls_ecp_group grp;
    mbedtls_mpi cli_secret, srv_secret;
    mbedtls_mpi cli_pri, srv_pri;
    mbedtls_ecp_point cli_pub, srv_pub;
    mbedtls_entropy_context entropy;
    mbedtls_ctr_drbg_context ctr_drbg;
    uint8_t *pers = "simple_ecdh";

    mbedtls_mpi_init(&cli_pri); //
    mbedtls_mpi_init(&srv_pri);
    mbedtls_mpi_init(&cli_secret); 
    mbedtls_mpi_init(&srv_secret);
    mbedtls_ecp_group_init(&grp); //初始化椭圆曲线群结构体
    mbedtls_ecp_point_init(&cli_pub); //初始化椭圆曲线点结构体 cli
    mbedtls_ecp_point_init(&srv_pub);//初始化椭圆曲线点结构体 srv
    mbedtls_entropy_init(&entropy); //初始化熵结构体
    mbedtls_ctr_drbg_init(&ctr_drbg);//初始化随机数结构体
/*
    mbedtls_entropy_add_source(&entropy, entropy_source, NULL,
                       MBEDTLS_ENTROPY_MAX_GATHER, MBEDTLS_ENTROPY_SOURCE_STRONG);*/
    mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, 
                                (const uint8_t *) pers, strlen(pers));
    mbedtls_printf("\n  . setup rng ... ok\n");

    //加载椭圆曲线,选择SECP256R1
    ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1);
    mbedtls_printf("\n  . select ecp group SECP256R1 ... ok\n");
    //cli生成公开参数
    ret = mbedtls_ecdh_gen_public(&grp,    //椭圆曲线结构体
    							  &cli_pri,//输出cli私密参数d
    							  &cli_pub,//输出cli公开参数Q
                                  mbedtls_ctr_drbg_random, &ctr_drbg);
    assert_exit(ret == 0, ret);
    mbedtls_ecp_point_write_binary(&grp, &cli_pub, //把cli的公开参数到处到buf中
                            MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, buf, sizeof(buf));
    dump_buf("  1. ecdh client generate public parameter:", buf, olen);

	//srv生成公开参数
    ret = mbedtls_ecdh_gen_public(&grp,    //椭圆曲线结构体
    							  &srv_pri,//输出srv私密参数d
    							  &srv_pub,//输出srv公开参数Q
                                  mbedtls_ctr_drbg_random, &ctr_drbg);
    assert_exit(ret == 0, ret);
    mbedtls_ecp_point_write_binary(&grp, &srv_pub, //把srv的公开参数导出到buf中
                            MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, buf, sizeof(buf));
    dump_buf("  2. ecdh server generate public parameter:", buf, olen);
    //cli计算共享密钥
    ret = mbedtls_ecdh_compute_shared(&grp,    //椭圆曲线结构体
                                      &cli_secret, //cli计算出的共享密钥
                                      &srv_pub, //输入srv公开参数Q
                                      &cli_pri, //输入cli本身的私密参数d
                                      mbedtls_ctr_drbg_random, &ctr_drbg);
    assert_exit(ret == 0, ret);
	//把cli计算出的共享密钥导出buf中
    mbedtls_mpi_write_binary(&cli_secret, buf, mbedtls_mpi_size(&cli_secret));
    dump_buf("  3. ecdh client generate secret:", buf, mbedtls_mpi_size(&cli_secret));

	//srv计算共享密钥
    ret = mbedtls_ecdh_compute_shared(&grp,   //椭圆曲线结构体
                                      &srv_secret, //srv计算出的共享密钥
                                      &cli_pub, //输入cli公开参数Q
                                      &srv_pri, //输入srv本身的私密参数d
                                      mbedtls_ctr_drbg_random, &ctr_drbg);
    assert_exit(ret == 0, ret);
	//把srv计算出的共享密钥导出buf中
    mbedtls_mpi_write_binary(&srv_secret, buf, mbedtls_mpi_size(&srv_secret));
    dump_buf("  4. ecdh server generate secret:", buf, mbedtls_mpi_size(&srv_secret));

    //比较2个大数是否相等
    ret = mbedtls_mpi_cmp_mpi(&cli_secret, &srv_secret);
    assert_exit(ret == 0, ret);
    mbedtls_printf("  5. ecdh checking secrets ... ok\n");

cleanup:
    mbedtls_mpi_free(&cli_pri); 
    mbedtls_mpi_free(&srv_pri);
    mbedtls_mpi_free(&cli_secret); 
    mbedtls_mpi_free(&srv_secret);
    mbedtls_ecp_group_free(&grp);
    mbedtls_ecp_point_free(&cli_pub); 
    mbedtls_ecp_point_free(&srv_pub);
    mbedtls_entropy_free(&entropy); 
    mbedtls_ctr_drbg_free(&ctr_drbg);

    return 0;
}

运行结果

  . setup rng ... ok

  . select ecp group SECP256R1 ... ok
  1. ecdh client generate public parameter:
     04 D8 CC C3 43 FF 96 03 2A AB DD 1D 42 D3 D2 6E
     ED 31 08 EB 6D 6E D3 1E F0 E8 5A 8B 8E E3 2B D6
     02 B9 B3 AA 8F CF 99 EA 6E F5 3A 0B 04 34 4F 00
     6D B4 28 29 0E DF 1B 2B 38 E7 34 A7 E5 AD B4 6B
     1D
  2. ecdh server generate public parameter:
     04 5C C6 24 F1 61 E5 B2 B8 F1 45 73 3E 99 F8 1B
     DB 95 13 5E 9D 59 BA DA 7F 78 01 AC C8 3C FD 7E
     2F 27 04 18 B0 29 7F 9E C0 BF 86 78 CF 49 1C 98
     0B 03 75 B0 43 D0 36 F7 90 CF 54 49 8C F6 97 6D
     AF
  3. ecdh client generate secret:
     04 92 C4 4B 51 39 17 18 FB 6C 92 15 16 10 E6 D6
     B5 E4 CF 45 97 36 6C 12 22 E7 6E 83 02 C7 11 D9
  4. ecdh server generate secret:
     04 92 C4 4B 51 39 17 18 FB 6C 92 15 16 10 E6 D6
     B5 E4 CF 45 97 36 6C 12 22 E7 6E 83 02 C7 11 D9
  5. ecdh checking secrets ... ok

从运行结果看出

  • 模拟服务器和客户端均产生了不同的椭圆曲线公钥
  • 服务器和客户端公钥均采用非压缩模式,因为均以04开头
  • 双方采用secp256r1,所以生成公钥长度都为65字节,包括1字节压缩提示,32字节x坐标,32字节y坐标
  • 最终双方获得相同的共享密钥,共享密钥仅包括x坐标,所以长度是32字节
  • 3
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值