3

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

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

4

4 回答 4

3

从 Windows 10 开始,您可以BCryptDeriveKey()使用BCRYPT_KDF_RAW_SECRET.

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

注意 1:bcrypt.h 表示此格式适用于“WINBLUE”,如果我理解正确,它将是 Windows 8.1,但我收到了 STATUS_NOT_SUPPORTED 用于在 Windows 8.1 和 Windows Server 2012 R2 上使用此 KDF 类型。但是,这适用于 Windows 10。)

注意 2:我发现使用这种 KDF 类型返回的数据是小端(BCrypt 中的其他所有东西都是大端)。因此,要在大端世界中使用该值,您需要对数据进行字节翻转。

于 2019-05-30T12:52:06.747 回答
1

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

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),我在我的生产代码中验证了它。如前所述,数组将被反转,您将需要反转字节数组以获取秘密。

于 2019-10-14T23:24:13.747 回答
0

一旦你得到你的BCRYPT_SECRET_HANDLE,你就可以BCryptDeriveKey用来获取实际的对称加密密钥。

于 2016-11-12T12:24:50.740 回答
-2

调用后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。如果是这样,则不复制密钥,但是将复制的字节数写入第六个参数给出的地址。这允许我们分配适当数量的空间,然后再次调用该函数,这次传入分配的缓冲区的地址。

于 2016-11-13T03:15:22.873 回答