Exporting shared secret as BYTE array from BCRYPT_SECRET_HANDLE

亡梦爱人 提交于 2019-12-10 22:17:02

问题


I'm implementing ECDHE using crypto next generation APIs (CNG). I generate public and private keys successfully. For pre-shared key, I use BCryptSecretAgreement API, which returns me the pre-shared key secret handle (BCRYPT_SECRET_HANDLE).

How can I export the pre-shared key as BYTE array from the BCRYPT_SECRET_HANDLE?


回答1:


Starting with Windows 10, you can call BCryptDeriveKey() with BCRYPT_KDF_RAW_SECRET.

The resulting key data is the raw secret.

Note 1: bcrypt.h indicates that this format works for "WINBLUE", which would be Windows 8.1, if I understand correctly, but I received STATUS_NOT_SUPPORTED for the use of this KDF type on both Windows 8.1 and Windows Server 2012 R2. This works, however, on Windows 10.)

Note2: I found the data returned using this KDF type to be little-endian (where everything else in BCrypt is big-endian). So, to use the value in an otherwise big-endian world, you need to byte-flip the data.




回答2:


Once you got your BCRYPT_SECRET_HANDLE, you use BCryptDeriveKey to obtain the actual symmetric encryption key.




回答3:


I needed to do the following, and here is an excerpt from my code which does the critical items, you will need to import the private and public keys before this segment

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

As a side note, if you use NCrypt, this will work also (NCryptDeriveKey), I verified it on my production code. As it was stated earlier, the array will be reversed, and you will need to reverse the array of bytes to get the secret.




回答4:


After calling BCryptSecretAgreement, You need to use the BCryptDeriveKey function to retrieve the shared secret.

This can be done as follows:

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

For the second parameter, the constant BCRYPT_KDF_HASH says to use a hash as the key derivation function. The hash to use can be specified in the third parameter. In this example, the third parameter is NULL, so it uses SHA1 by default.

Also, the fourth parameter, which is a pointer to the buffer to receive the key, can be NULL. If so, the key is not copied however the number of bytes that would be copied are written to the address given by the sixth parameter. This allows us to allocate the proper amount of space then call the function again, this time passing in the address of the allocated buffer.



来源:https://stackoverflow.com/questions/38115602/exporting-shared-secret-as-byte-array-from-bcrypt-secret-handle

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!