BouncyCastle Java API和OpenSSL生成的ECDH机密不同 [英] ECDH secrets generated by BouncyCastle Java API and by OpenSSL are different

查看:780
本文介绍了BouncyCastle Java API和OpenSSL生成的ECDH机密不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用椭圆曲线加密.我需要同一件事的两种实现,一种在Java中,一种在C中.我正在使用通过曲线 secp256k1 生成的两对密钥对它们进行测试.当我用Java生成派生秘密时,我总是得到与OpenSSL不同的数字.

I'm trying to make use of elliptic curve crypto. I need two implementations of the same thing, one in Java and one in C. I'm testing them using two key pairs which were generated using the curve secp256k1. When I generate the derived secret in Java I always get a different number from what I get from OpenSSL.

Java代码:

/* privateKey and peerPublicKey are generated with the following parameters */
ECParameterSpec paramSpec = ECNamedCurveTable.getParameterSpec("secp256k1");
/* ... */
Provider BC = new BouncyCastleProvider();
KeyAgreement agr = KeyAgreement.getInstance("ECDH", BC);
agr.init(privateKey);
agr.doPhase(peerPublicKey, true);
byte[] secret = agr.generateSecret();

C代码

/* pkey and peerkey are generated using EC_KEY_new_by_curve_name(NID_secp256k1) */
/* and than wrapped in an EVP_PKEY */
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
uint8_t *secret = NULL;
size_t secret_len;
EVP_PKEY_derive_init(ctx);
EVP_PKEY_derive_set_peer(ctx, peerkey);
EVP_PKEY_derive(ctx, NULL, &secret_len);
secret = malloc(secret_len);
EVP_PKEY_derive(ctx, secret, &secret_len);

我确定密钥是有效的,并且在C和Java代码中它们都是相同的,但是我不明白为什么派生的秘密不同.我想念什么吗?

I'm sure that the keys are valid and that they are the same both in C and in Java code, but I don't understand why the derived secret is different. Am I missing something?

谢谢

推荐答案

EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
uint8_t *secret = NULL;
size_t secret_len;
EVP_PKEY_derive_init(ctx);
EVP_PKEY_derive_set_peer(ctx, peerkey);
EVP_PKEY_derive(ctx, NULL, &secret_len);
secret = malloc(secret_len);
EVP_PKEY_derive(ctx, secret, &secret_len);

此代码似乎缺少几个步骤.例如,EVP_PKEY_paramgen_init不存在.

This code looks like its missing a few steps. For example, EVP_PKEY_paramgen_init is not present.

OpenSSL Wiki在椭圆曲线Diffie-Hellman 中有一个示例.我将在下面复制/粘贴它,以避免仅链接的答案,但是我相信这是Matt Caswell的工作.

The OpenSSL wiki has an example at Elliptic Curve Diffie-Hellman. I'm going to copy/paste it below to avoid the link-only answer, but I believe its the work of Matt Caswell.

EVP_PKEY_CTX *pctx, *kctx;
EVP_PKEY_CTX *ctx;
unsigned char *secret;
EVP_PKEY *pkey = NULL, *peerkey, *params = NULL;

/* Create the context for parameter generation */
if(NULL == (pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))) handleErrors();

/* Initialise the parameter generation */
if(1 != EVP_PKEY_paramgen_init(pctx)) handleErrors();

/* We're going to use the ANSI X9.62 Prime 256v1 curve */
if(1 != EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1)) handleErrors();

/* Create the parameter object params */
if (!EVP_PKEY_paramgen(pctx, &params)) handleErrors();

/* Create the context for the key generation */
if(NULL == (kctx = EVP_PKEY_CTX_new(params, NULL))) handleErrors();

/* Generate the key */
if(1 != EVP_PKEY_keygen_init(kctx)) handleErrors();
if (1 != EVP_PKEY_keygen(kctx, &pkey)) handleErrors();

/* Get the peer's public key, and provide the peer with our public key -
 * how this is done will be specific to your circumstances */
peerkey = get_peerkey(pkey);

/* Create the context for the shared secret derivation */
if(NULL == (ctx = EVP_PKEY_CTX_new(pkey, NULL))) handleErrors();

/* Initialise */
if(1 != EVP_PKEY_derive_init(ctx)) handleErrors();

/* Provide the peer public key */
if(1 != EVP_PKEY_derive_set_peer(ctx, peerkey)) handleErrors();

/* Determine buffer length for shared secret */
if(1 != EVP_PKEY_derive(ctx, NULL, secret_len)) handleErrors();

/* Create the buffer */
if(NULL == (secret = OPENSSL_malloc(*secret_len))) handleErrors();

/* Derive the shared secret */
if(1 != (EVP_PKEY_derive(ctx, secret, secret_len))) handleErrors();

EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(peerkey);
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(kctx);
EVP_PKEY_free(params);
EVP_PKEY_CTX_free(pctx);

/* Never use a derived secret directly. Typically it is passed
 * through some hash function to produce a key */
return secret;


当我用Java生成派生秘密时,我总是得到与OpenSSL不同的数字.

When I generate the derived secret in Java I always get a different number from what I get from OpenSSL.

每次运行该协议都会产生不同的结果.这是因为各方为协议的每次运行都选择了一个随机值.也就是说,g^a中的a是随机的,并且每次运行都不同,因此公钥A = g^a每次运行都不同.

Each run of the protocol will produce different results. That's because each party picks a random value for each run of the protocol. That is, the a in g^a is random and different for each run, so the public key A = g^a is different for each run.

如果一切正常,您将永远不会看到各方使用相同的值,也不会看到一方重用过去的值.独立执行永远不会产生相同的结果.它的OpenSSL↔OpenSSL,OpenSSL↔Java或Java↔Java都没有关系.他们总是会产生不同的结果.

If everything is working correctly, you'll never see the parties use the same values, or one party to reuse a past value. Independent executions will never produce the same result. It does not matter if its OpenSSL ↔ OpenSSL, OpenSSL ↔ Java, or Java ↔ Java. They will always produce different results.

这篇关于BouncyCastle Java API和OpenSSL生成的ECDH机密不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆