从BCRYPT_SECRET_HANDLE导出共享密钥作为BYTE数组

时间:2016-06-30 06:37:24

标签: c++ c tls1.2 cng ecdhe

我正在使用加密下一代API(CNG)实现ECDHE。我成功生成公钥和私钥。对于预共享密钥,我使用 BCryptSecretAgreement API,它返回预共享密钥保密句柄(BCRYPT_SECRET_HANDLE)。

如何从BCRYPT_SECRET_HANDLE中将预共享密钥导出为BYTE数组?

4 个答案:

答案 0 :(得分:0)

获得BCRYPT_SECRET_HANDLE后,使用BCryptDeriveKey获取实际的对称加密密钥。

答案 1 :(得分:0)

从Windows 8.1开始,您可以使用BCryptDeriveKey()来调用BCRYPT_KDF_RAW_SECRET

生成的密钥数据是原始机密。

答案 2 :(得分:0)

我需要执行以下操作,这是我的代码的摘录,其中摘录了一些关键项目,您需要在此段之前导入私钥和公钥。

DWORD bCryptStatus;
BCRYPT_SECRET_HANDLE secretHandle = NULL;
BCRYPT_KEY_HANDLE privateKeyHandle= NULL;
BCRYPT_KEY_HANDLE importedPublicKey = NULL;
BYTE *agreedSecret = NULL;
DWORD agreedSecretLength = 0;

//Import your keys here

//Generate the secret from the imported keys
bCryptStatus= BCryptSecretAgreement(privateKeyHandle, importedPublicKey, &secretHandle, 0);

//Now get the raw value of the secret agreement and copy it into an array
bCryptStatus= BCryptDeriveKey(
    secretHandle,          // Secret agreement handle
    BCRYPT_KDF_RAW_SECRET, // Key derivation function (null terminated unicode string)
    NULL,                  // KDF parameters
    NULL,                  // Buffer that recieves the derived key 
    0,                     // Length of the buffer
    &agreedSecretLength,   // Number of bytes copied to the buffer
    0);                    // Flags

    agreedSecret = (PBYTE)MALLOC(agreedSecretLength);

if (NULL != agreedSecret)
{
    _nCryptError = BCryptDeriveKey(
    secretHandle,          // Secret agreement handle
    BCRYPT_KDF_RAW_SECRET, // Key derivation function (null terminated unicode string)
    NULL,                  // KDF parameters
    agreedSecret,          // Buffer that recieves the derived key 
    agreedSecretLength,    // Length of the buffer
    &agreedSecretLength,   // Number of bytes copied to the buffer
    0);                    // Flags
}

//Free all the objects and the array when you are done, otherwise you will get memory leaks
if (NULL != importedPublicKey)
{
    BCryptDestroyKey(importedPublicKey);
}

if (NULL != privateKeyHandle)
{
    BCryptDestroyKey(privateKeyHandle);
}

if (NULL != secretHandle)
{
    BCryptDestroySecret(secretHandle);
}

if (NULL != agreedSecret)
{
    FREE(agreedSecret);
}

请注意,如果您使用NCrypt,这也将起作用(NCryptDeriveKey),我在生产代码中对其进行了验证。 如前所述,该数组将被反转,您将需要反转字节数组以获取机密。

答案 3 :(得分:-1)

调用BCryptSecretAgreement后,您需要使用BCryptDeriveKey函数来检索共享密钥。

这可以按如下方式完成:

// generates an ECDH shared secret from a public key and a private key
int get_ECDH_key(BCRYPT_KEY_HANDLE pubkey, BCRYPT_KEY_HANDLE privkey, unsigned char **key,
                 unsigned int *keylen)
{
    SECURITY_STATUS sstatus;
    BCRYPT_SECRET_HANDLE secret;
    int _len;

    // creates the shared secret, stored in a BCRYPT_SECRET_HANDLE 
    sstatus = BCryptSecretAgreement(privkey, pubkey, &secret, 0);
    if (!BCRYPT_SUCCESS(sstatus)) {
        printf("BCryptSecretAgreement failed with status %d", sstatus);
        return 0;
    }

    // find out how much space is needed before retrieving the shared secret
    sstatus = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, NULL, NULL, 0, &_len, 0);
    if (!BCRYPT_SUCCESS(sstatus)) {
        printf("BCryptDeriveKey failed with status %d", sstatus);
        return 0;
    }

    // allocate space for the shared secret
    *key = malloc(_len);
    if (*key == NULL) {
        perror("malloc failed");
        exit(1);
    }

    // retrieve the shared secret
    sstatus = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, NULL, *key, _len,
                              keylen, 0 );
    if (!BCRYPT_SUCCESS(sstatus)) {
        printf("BCryptDeriveKey failed with status %d", sstatus);
        return 0;
    }
    return 1;
}

对于第二个参数,常量BCRYPT_KDF_HASH表示使用哈希作为密钥派生函数。要使用的哈希值可以在第三个参数中指定。在此示例中,第三个参数为NULL,因此默认情况下使用SHA1。

此外,第四个参数,即指向接收密钥的缓冲区的指针,可以为NULL。如果是,则不复制密钥,但是将复制的字节数写入第六个参数给出的地址。这允许我们分配适当的空间量然后再次调用该函数,这次传入分配的缓冲区的地址。