ECDH算法与mbedTLS

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

当然,算法的具体实现并不追加研究,这里主要研究的是应用。

mbedTLS官网:Mbed TLS - Trusted Firmware

DH密钥交换原理

  • 通信双方选择共同的 椭圆曲线方程、相同的 大素数P、相同的 生成元G
  • 通信方 A 生成一个随机数 a1 作为自己的私钥,通过椭圆曲线标量乘法得到公钥 b1
  • 通信方 B 生成一个随机数 a2 作为自己的私钥,通过椭圆曲线标量乘法得到公钥 b2
  • 通信双方 交换公钥,得到 对方的公钥自己的私钥 ,然后一起计算得到共同的 会话秘钥

假设 Alice 与 Bob 要在一条不安全的线路上交换秘钥,而且交换的秘钥又不能被中间人知晓,怎么弄?

首先,双方事先约定使用 ECDH 秘钥交换算法,此时,双方已知 ECDH 算法里的一个大素数P,这个P可以看做是一个算法中的常量。P的复杂度决定了密钥的破解复杂度;

其中,还有一个生成元G用来辅助整个秘钥交换,这个G一般就是2或者5,当双方知道G和P之后就开始ECDH交换秘钥的过程。

在业务上,就是双方通过P2P或者信令服务器转发,来实现ECDH交换;

// 假设
int P = 82;
int G = 5;

既然 Alice 知道了共用参数 P 和 G,同时,也很轻松的生成了私有整数 dA 作为私钥。

// Alice生成随机数a作为私钥
int a = 9;

一般来说,公钥用来加密,私钥用来解密。

公钥直接给对方来加密数据,拿到密文后私钥解密查看内容正确性,这个时候若 Alice 直接通过连接告诉 Bob 自己的私钥 a 很明显风险很大。这个时候,Alice 则需要利用 P、G、a 通过公式A = G^a mod P 生成 A 作为公钥传递给 Bob。

A = (G^a) mod P

// 计算公钥
int A = (G^a)%P = (5^9)%82 = 12;

然后,Bob 收到来自 Alice 发来的 P、G、A,知道了 Alice 的公钥 A。此时,Bob 也生成一个自己的私钥 b,然后通过公式 B = G^b mod P 生成自己公钥 B。在发送自己的公钥 B 前,Bob 通过 Kb = A^b mod P 生成 Kb 作为公共秘钥,但这K并不发送给 Alice,只会将生成的公钥 B 发给 Alice。

// Bob生成随机数b作为私钥
int b = 38;
int B = (G^b)%P = (5^38)%82 = 35;

Kb = (A^b) mod P

// 公共密钥
int Kb = (A^b)%P = (12^38)%82 = 42;

最后,Alice 收到 Bob 发来的公钥 B 以后,同样通过 K = B^a mod P 生成公共秘钥 K,这样 Alice 和 Bob 就通过不传递私钥a和b完成了对公共秘钥K的协商。

Ka = (B^a) mod P

// 公共密钥
int Ka = (B^a)%P = (35^9)%82 = 42;

注意,Bob的私钥不能等于Alice的公钥,否则最后算出来的K都是0;

结合ECC椭圆曲线算法

ECDH密钥协商算法是ECC算法和DH密钥交换原理结合使用,用于密钥磋商。交换双方可以在不共享任何秘密的情况下协商出一个密钥。

ECC是建立在基于椭圆曲线的离散对数问题上的密码体制,给定椭圆曲线上的一个点P,一个整数k,求解Q=kP很容易;给定一个点P、Q,知道Q=kP,求整数k则是一个难题。因此ECDH的难点就在于K的求解上。这也是它安全性能进一步提高的表现。

椭圆曲线由以下参数组成,但具体的算法事实上可以变化:

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

算法举例:

于是我们通过运算后得到:

Alice’s 私钥(随机数): 0xe32868331fa8ef0138de0de85478346aec5e3912b6029ae71691c384237a3eeb 
Alice’s 公钥(由Alice的随机数乘上基点): 0x86b1aa5120f079594348c67647679e7ac4c365b2c01330db782b0ba611c1d677 0x5f4376a23eed633657a90f385ba21068ed7e29859a7fab09e953cc5b3e89beba 

Bob’s 私钥(随机数): 0xcef147652aa90162e1fff9cf07f2605ea05529ca215a04350a98ecc24aa34342 
Bob’s公钥(由Bob的随机数乘上基点): 0x4034127647bb7fdab7f1526c7d10be8b28174e2bba35b06ffd8a26fc2c20134a 0x9e773199edc1ea792b150270ea3317689286c9fe239dd5b9c5cfd9e81b4b632 

双方得到的共享密钥: 0x3e2ffbc3aa8a2836c1689e55cd169ba638b58a3a18803fcf7de153525b28c3cd 0x43ca148c92af58ebdb525542488a4fe6397809200fe8c61b41a105449507083

库模块

mbedtls椭圆曲线模块

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

mbedtls所支持的椭圆曲线可以通过 config.h 中下面这些宏使能或者关闭:

这些宏支撑 ECHDH 的条件编译:

#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 
#define MBEDTLS_AES_ROM_TABLES

这些宏支撑 ecp_curves.c 的条件编译:

#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

DEMO代码

#include <stdio.h>
#include "string.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/ecdh.h"

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;
}

SECP256K1

以下内容摘自《有效密码学标准》:

椭圆曲线在Fp上的主参数与 Koblitz 曲线 secp256k1 相关联,secp256k1由六元组 T = (p,a,b,G,n,h) 定义,其中有限域 Fp 定义为:

  • p= FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F
  • = 2256– 232 – 29 – 28 – 27 – 26 – 24 – 1

曲线 E: y2 = x3+ax+b 在 Fp 上定义为:

  • a= 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
  • b= 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000007

压缩形式的基点G为:

  • G= 02 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798

未压缩的形式是:

  • G= 04 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798 483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8

最后G的阶n和辅因子是:

  • n= FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141
  • h= 01

猜你喜欢

转载自blog.csdn.net/davidsguo008/article/details/129500395