2014-03-03 148 views
0

我試圖使用橢圓曲線密碼。我需要兩個相同的東西的實現,一個是Java,一個是C。我使用兩個密鑰對測試它們,這兩個密鑰對使用曲線secp256k1生成。當我在Java中生成派生祕密時,我總是從OpenSSL獲得的數字中得到不同的數字。由BouncyCastle Java API和OpenSSL生成的ECDH機密不同

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代碼是相同的,但我不」不明白爲什麼派生的祕密是不同的。我錯過了什麼嗎?

感謝

+0

「當我在Java中生成派生祕密時,我總是從我從OpenSSL獲得的數字獲得不​​同的數字。」 - 你的意思是什麼?協議的每次執行是否導致不同的祕密?或者,OpenSSL客戶端和BC客戶端之間的協議執行沒有達到共享密鑰? – jww

回答

2
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不存在。

OpenSSL wiki在Elliptic Curve Diffie-Hellman上有一個例子。我將在下面複製/粘貼它以避免僅鏈接的答案,但我相信它是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的得到一個不同的數字。

協議的每次運行都會產生不同的結果。這是因爲每一方都會爲協議的每次運行選擇一個隨機值。也就是說,ag^a對於每次運行都是隨機的和不同的,所以公鑰A = g^a對於每次運行都是不同的。

如果一切工作正常,你永遠不會看到各方使用相同的值,或一方重用過去的價值。獨立執行決不會產生相同的結果。它的OpenSSL↔OpenSSL,OpenSSL↔Java或Java↔Java並不重要。他們總會產生不同的結果。

相關問題