ECDH 算法概述(CNG 示例)

转自: https://docs.microsoft.com/zh-cn/previous-versions/visualstudio/visual-studio-2008/cc488016(v=vs.90)

ECDH全称是椭圆曲线迪菲-赫尔曼秘钥交换(Elliptic Curve Diffie–Hellman key Exchange),主要是用来在一个不安全的通道中建立起安全的共有加密资料,一般来说交换的都是私钥,这个密钥一般作为“对称加密”的密钥而被双方在后续数据传输中使用。

ECDH是建立在这样一个前提之上的,给定椭圆曲线上的一个点P,一个整数k,求Q=KP很容易;但是通过Q,P求解K很难。

通过椭圆曲线 Diffie-Hellman (ECDH) 密钥协商协议,两个用户可以创建共享的机密协议。他们可以在不安全的公共媒体上完成此操作,而不必事先交换任何私有信息。该共享机密协议通常用于派生密钥材料。对称算法(如高级加密标准 (AES) 算法)可以使用密钥材料对后续消息进行加密。

下一代加密技术 (CNG) 安全通信示例演示了 ECDH 和 AES 算法的 CNG 实现。Alice、Bob 和 Mallory 在创建 Communicator 对象时在其 Run 方法中创建了加密密钥。

ECDH 数学

ECDH 协议依赖两个公共参数:p 和 g。参数 p 是一个大的质数,参数 g 是一个小于 p 的整数。这两个参数通过不安全的线路进行交换。Alice 和 Bob 收到这两个公共参数后,选择私有整数。Alice 选择了 a,Bob 选择了 b。这些值称为私钥。

然后,Alice 和 Bob 使用公共参数及其私钥创建公钥。Alice 使用 (g^a) mod p,Bob 使用 (g^b) mod p。这些是非对称密钥,因为它们不匹配。

Alice 和 Bob 交换这些公钥,并使用它们计算共享的机密协议。虽然 Alice 和 Bob 不知道彼此的私钥,ECDH 数学也会保证 Alice 和 Bob 将计算出同一共享机密协议。

ECDH 数学
说明:

只有 a、b 和 g^ab = g^ba 保密。其他所有值都是公开的。

任何截获交换的人都能够复制 p、g 和两个公钥。但是,要在不知道 Alice 和 Bob 的私钥的情况下从四个公开共享值生成共享机密协议,在计算上是不可行的。

使用暴力(即尝试所有可能的密钥)对 ECDH 加密的消息进行解密的难度与离散对数问题属同一级别。不过,ECDH 算法使用较短的密钥即可达到相同程度的安全性,这是因为它依赖椭圆曲线而不是对数曲线。

ECDH 示例

下面的示例使用小整数来演示 ECDH 算法。

  1. Alice 和 Bob 同意使用质数 p 和基础整数 g:

    p = 83, g = 8

  2. Alice 选择机密整数 a = 9,然后向 Bob 发送 (g^a) mod p:

    (8^9) mod 83 = 5

  3. Bob 选择机密整数 b = 21,然后向 Alice 发送 (g^b) mod p:

    (8^21) mod 83 = 18

  4. Alice 计算 ( ( (g^b) mod p)^a) mod p:

    (18^9) mod 83 = 24

  5. Bob 计算 ( ( (g^a) mod p)^b) mod p:

    (5^21) mod 83 = 24

由于 g^(ab) = g^(ba),Alice 和 Bob 计算出相同的值 (24)。该值就是共享机密协议。Alice 和 Bob 使用这个值派生 AES 算法用来对其消息进行加密的密钥材料。

此示例使用值 24 生成共享机密协议。由于这是一个小的值,它生成的加密消息很容易被暴力攻击破坏。在实际情况中,p、g、a 和 b 是很大的数,需要计算机来生成相应的共享机密协议。

安全通信示例中使用的 CNG 类对复杂的数学进行了抽象,使您可以将精力集中在实现安全解决方案上,而不是考虑如何将大数相乘。

协议的限制

由于 ECDH 密钥交换协议不验证公钥发送者的身份,因此无法阻止中间人攻击。如果监听者 Mallory 截获了 Alice 的公钥,就可以替换为他自己的公钥,并将其发送给 Bob。Mallory 还可以截获 Bob 的公钥,替换为他自己的公钥,并将其发送给 Alice。这样,Mallory 就可以轻松地对 Alice 与 Bob 之间发送的任何消息进行解密。他可以更改消息,用他自己的密钥对消息重新加密,然后将消息发送给接收者。

为了解决此问题,Alice 和 Bob 可以在交换公钥之前使用数字签名对公钥进行签名。有两种方法可以实现此目的:

  • 使用安全的媒体(例如语音通信或可信载运商)在双方之间传输数字签名密钥。

  • 使用公共证书颁发机构 (CA) 向双方提供可信数字签名密钥。

在这两种情况下,都必须使用外部身份验证方案来验证公钥发送者的身份。CNG 示例演示了当未对密钥发送者进行身份验证时会发生的情况。编写该示例旨在启用一个安全漏洞。

对称和非对称密钥

非对称系统(例如 ECDH)非常慢。因此,在对大的消息进行加密时不使用它们,而是使用速度快很多倍的对称系统(例如 AES)。

典型的加密解决方案使用非对称系统派生对称共享机密协议。然后使用该共享机密协议来派生对称算法用来对消息进行加密的密钥材料。

CNG 安全通信示例对此行为进行了建模,如下所述:

  • 它使用非对称算法,即 ECDH 算法的 CNG 实现(ECDiffieHellmanCng 类)来派生对称加密密钥(共享机密协议)。

  • 然后,CNG ECDiffieHellmanCng.DeriveKeyMaterial 方法使用此密钥派生密钥材料。对称 AES 算法的 CNG 实现(Aes 类)使用该密钥材料对消息进行加密。

请参见

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是SM2 ECDH算法生成共享密钥的C++代码示例: ```c++ #include <openssl/ec.h> #include <openssl/ecdh.h> #include <openssl/err.h> void generate_SM2_ECDH_key(EC_KEY **ec_key) { // Generate an EC key using the SM2 curve *ec_key = EC_KEY_new_by_curve_name(NID_sm2); if (*ec_key == NULL) { // Handle error ERR_print_errors_fp(stderr); return; } // Generate the public and private keys if (!EC_KEY_generate_key(*ec_key)) { // Handle error ERR_print_errors_fp(stderr); EC_KEY_free(*ec_key); *ec_key = NULL; return; } } EC_KEY *load_SM2_ECDH_public_key(const char *public_key_file) { // Load the public key from file BIO *bio = BIO_new(BIO_s_file()); if (BIO_read_filename(bio, public_key_file) <= 0) { // Handle error BIO_free_all(bio); return NULL; } EC_KEY *ec_key = PEM_read_bio_EC_PUBKEY(bio, NULL, NULL, NULL); if (ec_key == NULL) { // Handle error ERR_print_errors_fp(stderr); BIO_free_all(bio); return NULL; } BIO_free_all(bio); return ec_key; } int generate_SM2_ECDH_shared_key(const EC_KEY *priv_key, const EC_KEY *pub_key, unsigned char *shared_key, size_t *shared_key_len) { // Create a new ECDH context ECDH_CTX *ctx = ECDH_CTX_new(priv_key); if (ctx == NULL) { // Handle error ERR_print_errors_fp(stderr); return 0; } // Compute the shared key int result = ECDH_compute_key(shared_key, *shared_key_len, EC_KEY_get0_public_key(pub_key), ctx); if (result <= 0) { // Handle error ERR_print_errors_fp(stderr); ECDH_CTX_free(ctx); return 0; } *shared_key_len = result; // Clean up ECDH_CTX_free(ctx); return 1; } int main() { // Generate a new key pair EC_KEY *priv_key = NULL; generate_SM2_ECDH_key(&priv_key); // Load the public key of the other party EC_KEY *pub_key = load_SM2_ECDH_public_key("other_party_public_key.pem"); if (pub_key == NULL) { // Handle error EC_KEY_free(priv_key); return 1; } // Allocate memory for the shared key size_t shared_key_len = EC_GROUP_get_degree(EC_KEY_get0_group(priv_key)) / 8 + 1; unsigned char *shared_key = (unsigned char *)malloc(shared_key_len); if (shared_key == NULL) { // Handle error EC_KEY_free(priv_key); EC_KEY_free(pub_key); return 1; } // Generate the shared key if (!generate_SM2_ECDH_shared_key(priv_key, pub_key, shared_key, &shared_key_len)) { // Handle error free(shared_key); EC_KEY_free(priv_key); EC_KEY_free(pub_key); return 1; } // Print the shared key for (size_t i = 0; i < shared_key_len; i++) { printf("%02X", shared_key[i]); } printf("\n"); // Clean up free(shared_key); EC_KEY_free(priv_key); EC_KEY_free(pub_key); return 0; } ``` 上述代码中,`generate_SM2_ECDH_key()`函数用于生成SM2 ECDH密钥对,`load_SM2_ECDH_public_key()`函数用于从文件中加载SM2 ECDH公钥,`generate_SM2_ECDH_shared_key()`函数用于生成共享密钥。在`main()`函数中,首先生成一个密钥对,然后从文件中加载另一方的公钥,最后生成共享密钥并打印输出。需要注意的是,这里生成的共享密钥是一个二进制数据,输出时需要将其转换为十六进制字符串。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值