BCrypt как превратить байты в дескриптор ключа

У меня есть массив байтов, который должен быть закрытым ключом, который я использую для декодирования сообщения, закодированного открытым ключом.

BCryptDecrypt использует тип BCRYPT_KEY_HANDLE в качестве ключа, используемого для дешифрования сообщения. Как преобразовать закрытый ключ в дескриптор ключа?

1 ответ

У меня была похожая проблема. Вам нужен ключ (как поток байтов), но вам также необходимо знать дополнительную информацию (например, используемый алгоритм и т. Д.).

Если мы предположим, что ключ был экспортирован с использованием BCryptExportKey (который экспортирует ключ И специальный заголовок CNG), то вы можете загрузить ключ следующим образом:

BCRYPT_KEY_HANDLE ImportKey(BYTE* pbKey, ULONG uLength)
{
    if(uLength < sizeof(BCRYPT_KEY_BLOB))
        return nullptr;

    const wchar_t*  wszAlgorithm;
    bool bPublic;
    switch(reinterpret_cast<BCRYPT_KEY_BLOB*>(pbKey)->Magic)
    {
    case BCRYPT_RSAPUBLIC_MAGIC:
    case BCRYPT_RSAPRIVATE_MAGIC:
    case BCRYPT_RSAFULLPRIVATE_MAGIC:
        if(uLength < sizeof(BCRYPT_RSAKEY_BLOB))
            return nullptr;
        wszAlgorithm = BCRYPT_RSA_ALGORITHM;
        bPublic = (reinterpret_cast<BCRYPT_KEY_BLOB*>(pbKey)->Magic == BCRYPT_RSAPUBLIC_MAGIC);
        break;
    case BCRYPT_ECDH_PUBLIC_P256_MAGIC:
    case BCRYPT_ECDH_PRIVATE_P256_MAGIC:
        wszAlgorithm = BCRYPT_ECDH_P256_ALGORITHM;
        bPublic = (reinterpret_cast<BCRYPT_KEY_BLOB*>(pbKey)->Magic == BCRYPT_ECDH_PUBLIC_P256_MAGIC);
        break;
    case BCRYPT_ECDH_PUBLIC_P384_MAGIC:
    case BCRYPT_ECDH_PRIVATE_P384_MAGIC:
        wszAlgorithm = BCRYPT_ECDH_P384_ALGORITHM;
        bPublic = (reinterpret_cast<BCRYPT_KEY_BLOB*>(pbKey)->Magic == BCRYPT_ECDH_PUBLIC_P384_MAGIC);
        break;
    case BCRYPT_ECDH_PUBLIC_P521_MAGIC:
    case BCRYPT_ECDH_PRIVATE_P521_MAGIC:
        wszAlgorithm = BCRYPT_ECDH_P521_ALGORITHM;
        bPublic = (reinterpret_cast<BCRYPT_KEY_BLOB*>(pbKey)->Magic == BCRYPT_ECDH_PUBLIC_P521_MAGIC);
        break;
    case BCRYPT_ECDSA_PUBLIC_P256_MAGIC:
    case BCRYPT_ECDSA_PRIVATE_P256_MAGIC:
        wszAlgorithm = BCRYPT_ECDSA_P256_ALGORITHM;
        bPublic = (reinterpret_cast<BCRYPT_KEY_BLOB*>(pbKey)->Magic == BCRYPT_ECDSA_PUBLIC_P256_MAGIC);
        break;
    case BCRYPT_ECDSA_PUBLIC_P384_MAGIC:
    case BCRYPT_ECDSA_PRIVATE_P384_MAGIC:
        wszAlgorithm = BCRYPT_ECDSA_P384_ALGORITHM;
        bPublic = (reinterpret_cast<BCRYPT_KEY_BLOB*>(pbKey)->Magic == BCRYPT_ECDSA_PUBLIC_P384_MAGIC);
        break;
    case BCRYPT_ECDSA_PUBLIC_P521_MAGIC:
    case BCRYPT_ECDSA_PRIVATE_P521_MAGIC:
        wszAlgorithm = BCRYPT_ECDSA_P521_ALGORITHM;
        bPublic = (reinterpret_cast<BCRYPT_KEY_BLOB*>(pbKey)->Magic == BCRYPT_ECDSA_PUBLIC_P521_MAGIC);
        break;
    case BCRYPT_DH_PUBLIC_MAGIC:
    case BCRYPT_DH_PRIVATE_MAGIC:
        if(uLength < sizeof(BCRYPT_DH_KEY_BLOB))
            return nullptr;
        wszAlgorithm = BCRYPT_DH_ALGORITHM;
        bPublic = (reinterpret_cast<BCRYPT_KEY_BLOB*>(pbKey)->Magic == BCRYPT_DH_PUBLIC_MAGIC);
        break;
    case BCRYPT_DSA_PUBLIC_MAGIC:
    case BCRYPT_DSA_PRIVATE_MAGIC:
    case BCRYPT_DSA_PUBLIC_MAGIC_V2:
    case BCRYPT_DSA_PRIVATE_MAGIC_V2:
        if(uLength < sizeof(BCRYPT_DSA_KEY_BLOB))
            return nullptr;
        wszAlgorithm = BCRYPT_DSA_ALGORITHM;
        bPublic = (reinterpret_cast<BCRYPT_KEY_BLOB*>(pbKey)->Magic == BCRYPT_DSA_PUBLIC_MAGIC) || (reinterpret_cast<BCRYPT_KEY_BLOB*>(pbKey)->Magic == BCRYPT_DSA_PUBLIC_MAGIC_V2);
        break;
    default:
        return nullptr;
    }

    // Query provider (I recommend to use RAII here for the case of exceptions; I omit that in this example here)
    BCRYPT_ALG_HANDLE hAlgorithm;
    NTSTATUS ntResult = BCryptOpenAlgorithmProvider(&hAlgorithm, wszAlgorithm, MS_PRIMITIVE_PROVIDER, 0);
    if(!BCRYPT_SUCCESS(ntResult))
        return nullptr;

    // Import key
    BCRYPT_KEY_HANDLE hKey;
    ntResult = BCryptImportKeyPair(hAlgorithm, nullptr, bPublic ? BCRYPT_PUBLIC_KEY_BLOB : BCRYPT_PRIVATE_KEY_BLOB, &hKey, pbKey, uLength, 0);
    BCryptCloseAlgorithmProvider(hAlgorithm, 0);        // Close in each case
    if(!BCRYPT_SUCCESS(ntResult))
        return nullptr;

    return hKey;
}

Как вы можете видеть, эта примерная функция ожидает, что поток байтов имеет заголовок CNG. Если ваш поток байтов ключа имеет этот заголовок, то вы загружаете ключ с помощью этой функции. В противном случае вам нужно создать такой заголовок.

Другие вопросы по тегам