2

我需要生成EC Diffie Hellman密钥对。我正在使用secp256r1命名曲线和OpenSSL。这是我与我至今:生成EC Diffie-Hellman公钥和私钥对

unsigned char *ecdh(size_t *secret_len) 
{ 
    EVP_PKEY_CTX *pctx, *kctx; 
    EVP_PKEY_CTX *ctx; 
    unsigned char *secret; 
    EVP_PKEY *pkey = NULL, *peerkey, *params = NULL; 
    /* NB: assumes pkey, peerkey have been already set up */ 

    /* Create the context for parameter generation */ 
    if(NULL == (pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))) 
     printf("Error in EC key generation\n"); 

    /* Initialise the parameter generation */ 
    if(1 != EVP_PKEY_paramgen_init(pctx)) 
     printf("Error in EC key generation\n"); 

    /* 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)) 
     printf("Error in EC key generation\n"); 

    /* Create the parameter object params */ 
    if (!EVP_PKEY_paramgen(pctx, &params)) 
     printf("Error in EC key generation\n"); 

    /* Create the context for the key generation */ 
    if(NULL == (kctx = EVP_PKEY_CTX_new(params, NULL))) 
     printf("Error in EC key generation\n"); 

    /* Generate the key */ 
    if(1 != EVP_PKEY_keygen_init(kctx)) 
     printf("Error in EC key generation\n"); 

    if (1 != EVP_PKEY_keygen(kctx, &pkey)) 
     printf("Error in EC key generation\n"); 

    /* 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))) 
     printf("Error in EC key generation\n"); 

    /* Initialise */ 
    if(1 != EVP_PKEY_derive_init(ctx)) 
     printf("Error in EC key generation\n"); 

    /* Provide the peer public key */ 
    if(1 != EVP_PKEY_derive_set_peer(ctx, peerkey)) 
     printf("Error in EC key generation\n"); 

    /* Determine buffer length for shared secret */ 
    if(1 != EVP_PKEY_derive(ctx, NULL, secret_len)) 
     printf("Error in EC key generation\n"); 

    /* Create the buffer */ 
    if(NULL == (secret = OPENSSL_malloc(*secret_len))) 
     printf("Error in EC key generation\n"); 

    /* Derive the shared secret */ 
    if(1 != (EVP_PKEY_derive(ctx, secret, secret_len))) 
     printf("Error in EC key generation\n"); 

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

我要指出的是此功能工作,我需要第二方的公钥EVP_KEY对象。我有这个公钥在一个字节数组,也是它的长度。我如何将其转换为所需的类型?而且我也找不到OpenSSL中的secp256r1曲线,但是在做了一些研究之后,我使用了代码中的那个曲线。这是对的吗?

谢谢!

+0

我不是OpenSSL的专家,但有一件事我要提醒你的就是实现自己的密码可能是危险的。例如,你不应该只是拿出你收到的任何密钥,并相信它属于你打算与之通信的一方:这会让你服从[中间人攻击者](http://en.wikipedia)。组织/维基/人在这方面的-middle_attack)。所以需要有某种类型的密钥属于声明它的人。 – TheGreatContini

+0

实际上现在我发现密钥带有一个签名(TLS中的服务器密钥交换记录就是我所说的),所以安全问题很好,我想:)我无法提取公钥从签名 –

+0

你的公钥是什么样的?这个答案是否适用? http://stackoverflow.com/questions/2918923/evp-pkey-from-char-buffer-in-x509-pkcs7 – ChiaraHsieh

回答

1

对等体的公钥是曲线上的一个点。从crypto\ec\ec_lcl.h

struct ec_key_st { 
    int version; 

    EC_GROUP *group; 

    EC_POINT *pub_key; 
    BIGNUM *priv_key; 

    unsigned int enc_flag; 
    point_conversion_form_t conv_form; 

    int  references; 
    int flags; 

    EC_EXTRA_DATA *method_data; 
} /* EC_KEY */; 

相信你需要调用EC_POINT_newc_lcl.h是一家私营头,所以您将无法访问结构)。

幸运的是,有很多的函数来处理它们。从EC_POINT_new(3)文档:

EC_POINTs可以转化为与来自各种外部 表示。支持的表示形式是八位字符串,BIGNUMs 和十六进制。外部表示的格式是由point_conversion_form描述的 。有关point_conversion_form的描述,请参阅EC_GROUP_copy(3) 。八位字节字符串与关联的缓冲区长度一起存储在一个 缓冲区中。通过将点转换为八位字节字符串并且然后将该八位字节字符串转换为BIGNUM整数来计算保存在 BIGNUM中的点。在 十六进制格式点存储在一个NULL结尾的字符串 其中每个字符可打印值0-9或A-F(或 A-F)中的一个。

另见EC_POINT_set_affine_coordinates_GFpEC_POINT_set_affine_coordinates_GF2mEC_KEY_set_public_key

$ grep -R EC_KEY_set_public_key * 
crypto/ec/ec.h:int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub); 
... 

你可以看到如何在Elliptic Curve Cryptography设置OpenSSL的维基点的例子。