当我传入私钥和对等密钥的字节缓冲区时,OpenSSL ECDH无法正常工作

时间:2014-09-13 21:22:49

标签: openssl

我一直在努力让ecdh通过传入字节键缓冲区来处理openssl 用于私钥和对等密钥。在线查看,我可以看到如果键,如何做ecdh 在ecdh函数中生成。我没想到的是与评论有关 在示例代码中,“假设pkey,peerkey已经设置好了”。 (我不 我认为我正在正确地设置它们.--我是openssl的新手,可能也是 我缺少的一些基本内容。)我已经生成了两对公共/私人 密钥使用包含的generateAsymmetricKeyPair()函数。然后我硬编码这些值 所以我可以为每个测试都有相同的值。 (请注意,有一个前置的0x04值 在公钥上进行压缩)。我发现的是我没有任何错误 但每次调用函数时,我得到的ecdh值都不同。 (我会 预计会得到相同的结果,即使它是错误的。)我的代码包含在内,如果有的话 可以提醒我我做错了什么,非常感谢。

    int32_t generateAsymmetricKeyPair(
        int32_t keySizeBits,
        unsigned char* publicKeyData,
        unsigned char* privateKeyData,
        unsigned char* keyIdData)
{
    EC_KEY                  *ecKey          = EC_KEY_new();
    EC_POINT                *ecPoint        = NULL;
    const EC_POINT          *ecPoint2       = NULL;
    EC_GROUP                *ecGroup        = NULL;
    point_conversion_form_t form            = POINT_CONVERSION_UNCOMPRESSED;
    int32_t                 asn1_flag       = OPENSSL_EC_NAMED_CURVE;
    int32_t                 sizePrvKeyBytes = 0;
    int32_t                 sizePubKeyBytes = 0;

    switch(keySizeBits)
    {
        case 256:
            ecGroup = EC_GROUP_new_by_curve_name(OBJ_sn2nid("prime256v1"));
            break;
        case 384:
            ecGroup = EC_GROUP_new_by_curve_name(OBJ_sn2nid("secp384r1"));
            break;
        case 521:
            ecGroup = EC_GROUP_new_by_curve_name(OBJ_sn2nid("secp521r1"));
            break;
        default:
            return 0;
    }

    sizePrvKeyBytes = keySizeBits / 8 + (((keySizeBits % 8) > 0 ) ? 1 : 0);
    sizePubKeyBytes = sizePrvKeyBytes * 2 + 1;

    EC_GROUP_set_asn1_flag(ecGroup, asn1_flag);
    EC_GROUP_set_point_conversion_form(ecGroup, form);
    EC_KEY_set_group(ecKey, ecGroup);

    ecPoint = EC_POINT_new(ecGroup);

    if(EC_KEY_generate_key(ecKey))
    {
        const BIGNUM *bn;

        /* Get Private Key */
        bn = EC_KEY_get0_private_key(ecKey);
        BN_bn2bin(bn, privateKeyData);

        /* Get Public Key */
        ecPoint2 = EC_KEY_get0_public_key(ecKey);
        EC_POINT_point2oct(EC_KEY_get0_group(ecKey),
                ecPoint2,
                POINT_CONVERSION_UNCOMPRESSED,
                publicKeyData,
                sizePubKeyBytes,
                NULL);

        /* Calculate keyId, Ignore format byte[0] */
        SHA1(publicKeyData + 1, sizePubKeyBytes - 1, keyIdData);
    }
    else
    {
        return 0;
    }
    return 1;
}

void deriveSharedSecret(
        unsigned char* pKey,
        unsigned char* peerKey,
        unsigned char* &secretKey,
        size_t* secretLen,
        int32_t privKeySize)
{
    bool                    grpForEc        = true;
    EVP_PKEY_CTX            *sharedCtx;
    EC_KEY                  *ecPrivKey      = NULL;
    EC_KEY                  *ecPeerKey      = NULL;
    EVP_PKEY                *evpPrivKey     = EVP_PKEY_new();
    EVP_PKEY                *evpPeerKey     = EVP_PKEY_new();
    BIGNUM                  *privBN         = BN_new();
    EC_POINT                *ecPubKey       = NULL;
    EC_POINT                *point          = NULL;
    BN_CTX                  *ctx            = BN_CTX_new();
    int32_t                 curve           = -1;
    int32_t                 peerKeySize     = -1;

    // One way of setting up EC key
    EC_GROUP                *ecGroup        = NULL;
    point_conversion_form_t form            = POINT_CONVERSION_UNCOMPRESSED;
    int32_t                 asn1_flag       = OPENSSL_EC_NAMED_CURVE;

    // Initialize output so that a return will result to NULL key and zero
    // length if error condition.
    *secretLen = 0;
    secretKey = NULL;

    // Create EC priv Key
    switch(privKeySize)
    {
        case 32:
            curve = NID_X9_62_prime256v1;
            break;
        case 48:
            curve = NID_secp384r1;
            break;
        case 66:
            curve = NID_secp521r1;
            break;
        default:
            return;
    }
    peerKeySize = (2 * privKeySize + 1); // Add one for compression byte

    try {
        if(NULL == (ecGroup = EC_GROUP_new_by_curve_name(curve))) {throw ossl_error();}
        EC_GROUP_set_asn1_flag(ecGroup, asn1_flag);
        EC_GROUP_set_point_conversion_form(ecGroup, form);
        if(NULL == (ecPrivKey = EC_KEY_new())) {throw ossl_error();}
        if(NULL == (ecPeerKey = EC_KEY_new())) {throw ossl_error();}
        if(1 != (EC_KEY_set_group(ecPrivKey, ecGroup))) {throw ossl_error();}
        if(1 != (EC_KEY_set_group(ecPeerKey, ecGroup))) {throw ossl_error();}

        /* PRIVATE KEY SETUP */
        // Convert to BIGNUM for private key conversion
        if(NULL == (BN_bin2bn(pKey, (privKeySize * 8), privBN))) {throw ossl_error();}

        // Convert private key to EC_KEY
        if(1 != (EC_KEY_set_private_key(ecPrivKey, privBN))) {throw ossl_error();}

        // Set the public key from the private key
        if(NULL == (ecPubKey = EC_POINT_new(EC_KEY_get0_group(ecPrivKey)))) {throw ossl_error();}
        if(1 != (EC_POINT_mul(EC_KEY_get0_group(ecPrivKey), ecPubKey,
                EC_KEY_get0_private_key(ecPrivKey), NULL, NULL, NULL))) {throw ossl_error();}
        if(1 != (EC_KEY_set_public_key(ecPrivKey, ecPubKey))) {throw ossl_error();}

        // Set the key in EVP_PKEY to ecPrivKey
        evpPrivKey = EVP_PKEY_new();
        if(1 != (EVP_PKEY_set1_EC_KEY(evpPrivKey, ecPrivKey))) {throw ossl_error();}

        /* PUBLIC PEER KEY SETUP */
        if(NULL == (point = EC_POINT_new(EC_KEY_get0_group(ecPeerKey)))) {throw ossl_error();}
        if(1 != (EC_POINT_oct2point(EC_KEY_get0_group(ecPeerKey), point, peerKey,
                peerKeySize, ctx))) {throw ossl_error();}

        if(1 != (EC_KEY_set_public_key(ecPeerKey, point))) {throw ossl_error();}

        // Set the key in EVP_PKEY to ecPeerKey
        if(1 != (EVP_PKEY_set1_EC_KEY(evpPeerKey, ecPeerKey))) {throw ossl_error();}

        /* SHARED SECRET SETUP */
        if(NULL == (sharedCtx = EVP_PKEY_CTX_new(evpPrivKey, NULL))) {throw ossl_error();}

        // Initialize
        if(1 != (EVP_PKEY_derive_init(sharedCtx))) {throw ossl_error();}

        // Provide the peer (public) key
        if(1 != (EVP_PKEY_derive_set_peer(sharedCtx, evpPeerKey))){throw ossl_error();}

        // Determine the buffer length for shared secret
        if((1 != EVP_PKEY_derive(sharedCtx, NULL, secretLen))) {throw ossl_error();}

        // Generate the shared secret buffer
        if(NULL == (secretKey = reinterpret_cast<unsigned char *>(OPENSSL_malloc(*secretLen))))
                {throw ossl_error();}

        // Derive the shared secret
        if(1 != (EVP_PKEY_derive(sharedCtx, secretKey, secretLen))) {throw ossl_error();}
    } catch(ossl_error& ex) {
        *secretLen = 0;
        secretKey = NULL;

        if(NULL != ecPrivKey) { EC_KEY_free(ecPrivKey); }
        if(NULL != ecPeerKey) { EC_KEY_free(ecPeerKey); }
        if(NULL != ecPubKey) { EC_POINT_free(ecPubKey); }
        if(NULL != point) { EC_POINT_free(point); }
        if(NULL != sharedCtx) { EVP_PKEY_CTX_free(sharedCtx); }
        if(NULL != evpPrivKey) { EVP_PKEY_free(evpPrivKey); }
        if(NULL != evpPeerKey) { EVP_PKEY_free(evpPeerKey); }
        if(NULL != ctx) { BN_CTX_free(ctx); }
        if(NULL != privBN) { BN_free(privBN); }

        return;
    }
    EC_KEY_free(ecPrivKey);
    EC_KEY_free(ecPeerKey);
    EC_POINT_free(ecPubKey);
    EC_POINT_free(point);
    EVP_PKEY_CTX_free(sharedCtx);
    EVP_PKEY_free(evpPrivKey);
    EVP_PKEY_free(evpPeerKey);
    BN_CTX_free(ctx);
    BN_free(privBN);

}

int main ()
{
    int32_t         keySizeBits     = 384;
    int32_t         keySize         = keySizeBits / 8;
    unsigned char   privateKeyData[keySize];
    unsigned char   publicKeyData[keySize * 2 + 1];
    unsigned char   keyIdData[keySize];
    unsigned char   privateKeyData2[keySize];
    unsigned char   publicKeyData2[keySize * 2 + 1];
    unsigned char   keyIdData2[keySize];
    unsigned char* sharedSecret = new unsigned char[keySize];
    unsigned char* sharedSecret2 = new unsigned char[keySize];
    size_t          secretLen       = 0;
    size_t          secretLen2      = 0;

    unsigned char _privateKeyData[] = {
            0x5d, 0xf0, 0x0d, 0x0f, 0x47, 0x1b, 0x3c, 0x11, 0xb7, 0x5d,
            0x12, 0x90, 0xff, 0x91, 0x93, 0xe6, 0xba, 0xd0, 0x75, 0xf9,
            0xe3, 0x48, 0xa2, 0x09, 0x85, 0x05, 0xe1, 0x0a, 0xf2, 0xfd,
            0xad, 0x9a, 0xf7, 0x98, 0xa3, 0xb3, 0x5f, 0x23, 0x80, 0xf2,
            0x05, 0x73, 0xeb, 0x73, 0x85, 0x0c, 0x1b, 0x3e
    };

    unsigned char _publicKeyData[] = {
            0x04, 0x9b, 0x6e, 0x53, 0x33, 0x4f, 0x87, 0x18, 0x45, 0xee,
            0x17, 0x9a, 0xbe, 0xa6, 0x41, 0xe1, 0xf0, 0xb2, 0x52, 0x9f,
            0xe5, 0x22, 0x67, 0x80, 0x64, 0x3b, 0x1b, 0x34, 0x8e, 0xa5,
            0x01, 0x2a, 0x06, 0xe4, 0xaa, 0xd2, 0xea, 0x29, 0x0a, 0xf5,
            0xa0, 0x80, 0x49, 0x1f, 0xa9, 0x4a, 0x30, 0x91, 0xd7, 0x59,
            0x27, 0x9c, 0xa8, 0x9b, 0x18, 0x76, 0xe4, 0xd6, 0x27, 0x93,
            0x0a, 0x6f, 0x01, 0x4d, 0x7d, 0x72, 0xb5, 0x78, 0x91, 0x8f,
            0x30, 0x9b, 0xe2, 0x55, 0x3f, 0xfa, 0x13, 0x3c, 0x52, 0x1b,
            0x5f, 0x56, 0xf7, 0x24, 0x3b, 0x54, 0x19, 0x0b, 0x61, 0x28,
            0x54, 0x72, 0x04, 0xd5, 0xb8, 0x0a, 0x76
    };


    unsigned char _privateKeyData2[] = {
            0x50, 0x96, 0xce, 0x89, 0xb3, 0x17, 0xbf, 0x63, 0x3d, 0x05,
            0x95, 0x82, 0x99, 0xc5, 0xd1, 0x75, 0x0d, 0x21, 0x23, 0x38,
            0xd6, 0x5e, 0x2a, 0xc6, 0x11, 0x09, 0xb4, 0xb0, 0x07, 0x18,
            0x0d, 0xa4, 0xb5, 0x2c, 0xf3, 0x96, 0x0d, 0x9c, 0x6e, 0xad,
            0x7c, 0x14, 0x7f, 0x5b, 0xcd, 0xfd, 0x33, 0xce
    };


    unsigned char _publicKeyData2[] = {
            0x04, 0x29, 0x00, 0x8a, 0xe7, 0xe2, 0x81, 0xab, 0xf2, 0xf4,
            0x2e, 0x1b, 0xb3, 0x73, 0xb4, 0xfd, 0xc6, 0x7e, 0x5e, 0x02,
            0x61, 0x25, 0x65, 0x6d, 0x5e, 0x44, 0xc9, 0x66, 0x21, 0x83,
            0x10, 0xea, 0xdc, 0x36, 0xa9, 0x7d, 0x1a, 0x55, 0xf0, 0x27,
            0xa5, 0x6f, 0x71, 0x36, 0x70, 0x57, 0xf7, 0x9f, 0x3b, 0x58,
            0x78, 0x3a, 0x14, 0x42, 0x58, 0x13, 0xf6, 0xef, 0xcb, 0x55,
            0xe2, 0xaa, 0x50, 0x95, 0x20, 0xa7, 0x29, 0x9c, 0x78, 0x94,
            0x9e, 0xe8, 0x81, 0x5a, 0x8e, 0x6e, 0x45, 0xd8, 0xd1, 0xae,
            0x1b, 0x51, 0x80, 0xcf, 0xce, 0x0c, 0x06, 0xab, 0x7d, 0xca,
            0xa3, 0xff, 0x4e, 0x65, 0x97, 0xb8, 0xd6
    };

    memset(privateKeyData, 0, keySize);
    memset(publicKeyData, 0, keySize * 2 + 1);
    memset(privateKeyData2, 0, keySize);
    memset(publicKeyData2, 0, keySize * 2 + 1);
    memset(sharedSecret, 0, keySize);
    memset(sharedSecret2, 0, keySize);
    memcpy(privateKeyData, _privateKeyData, keySize);
    memcpy(publicKeyData, _publicKeyData, keySize * 2 + 1);
    memcpy(privateKeyData2, _privateKeyData2, keySize);
    memcpy(publicKeyData2, _publicKeyData2, keySize * 2 + 1);

    deriveSharedSecret(privateKeyData, publicKeyData2,
            reinterpret_cast<unsigned char * &>(sharedSecret), &secretLen, keySizeBits / 8);
    deriveSharedSecret(privateKeyData2, publicKeyData,
            reinterpret_cast<unsigned char * &>(sharedSecret2), &secretLen2, keySizeBits / 8);

    OPENSSL_free(sharedSecret);
    OPENSSL_free(sharedSecret2);

    cout << "Out of Main" << endl;

    return 0;
}

1 个答案:

答案 0 :(得分:0)

问题在于我向BN_bin2bn提供了不正确的尺寸。我无意中将字节转换为位(乘以8),并将参数更改为私钥大小,导致共享密钥正确。此外,我发现没有必要从私钥设置公钥,因为 set_private_key 函数已经这样做了,尽管这样做并没有引起我的问​​题。此外,如果有人想使用此代码作为参考,最好不要让公钥在传入时包含编码字符;编码应该可以动态完成。