BCryptGenRandom STATUS_INVALID_HANDLE

BCryptGenRandom STATUS_INVALID_HANDLE

我正在尝试在 Windows 中生成加密安全号码。我有以下代码:

#ifndef w64crypt
#define w64crypt
#include <windows.h>
#include <bcrypt.h>
unsigned long getSeed(ULONG buffer_size){ 
    NTSTATUS status=0;
    ULONG flags=0;
    PUCHAR c_seed;
    BCRYPT_ALG_HANDLE handle;
    status=BCryptOpenAlgorithmProvider(
            &handle,BCRYPT_RNG_ALGORITHM,NULL,0
    );
    if(!BCRYPT_SUCCESS(status)){
            cout << "BCryptOpenAlgorithmProvider";
            printf("%X",status);
    }
    status=BCryptGenRandom(
            handle,c_seed,128,0
    );
    if(!BCRYPT_SUCCESS(status)){
            cout << "Error in BCryptGenRandom";
            printf("%X",status);
    }
    status=BCryptCloseAlgorithmProvider(
            handle,0
    );
    if(!BCRYPT_SUCCESS(status)){
            cout << "BCryptCloseAlgorithmProvider";
            printf("%X",status);
    }
    unsigned long seedNo=(unsigned long)c_seed;
    return seedNo;
}
#endif

当我运行这个时,我得到Error in BCryptGenRandom C0000008,也就是STATUS_INVALID_HANDLE。这是文档要求的内容:

https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptopenalgorithmprovider

NTSTATUS BCryptOpenAlgorithmProvider(
  BCRYPT_ALG_HANDLE *phAlgorithm,
  LPCWSTR           pszAlgId,
  LPCWSTR           pszImplementation,
  ULONG             dwFlags
);

https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom

NTSTATUS BCryptGenRandom(
  BCRYPT_ALG_HANDLE hAlgorithm,
  PUCHAR            pbBuffer,
  ULONG             cbBuffer,
  ULONG             dwFlags
);

上面的link也说明了pszAlgId必须是:

The handle of an algorithm provider created by using the BCryptOpenAlgorithmProvider function. The algorithm that was specified when the provider was created must support the random number generator interface.

看着https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-identifiersBCRYPT_RNG_ALGORITHM是我的理想人选。

我正在使用 mingw-w64 进行编译,从 Ubuntu 18.04.

进行交叉编译

为什么我会收到这个 NTSTATUS

我知道我来晚了,但希望这对遇到同样问题的人有所帮助。

文档中没有提及,但您可以使用预定义的 pseudo-handles 之一用于常用算法。这是一个例子

unsigned int GenAESKey(char* keyb) {
NTSTATUS s;
/*BCRYPT_ALG_HANDLE algh;
s = BCryptOpenAlgorithmProvider(&algh, BCRYPT_RNG_ALGORITHM, MS_PLATFORM_CRYPTO_PROVIDER, 0);
if (s != STATUS_SUCCESS)
    return (unsigned int)s;*/
s = BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (PUCHAR)keyb, CABINET_AES_KEY_S, 0);
if (s != STATUS_SUCCESS)
    return (unsigned int)s;
return 0;

可以看到所有预定义的列表pseudo-handleshere

这为我解决了:

unsigned long getSeed(int size){
    BCRYPT_ALG_HANDLE handle;
    int Buffer;
    PUCHAR bPointer=(PUCHAR)&Buffer;
    if(!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(
            &handle,BCRYPT_RNG_ALGORITHM,NULL,0
    ))){
            std::cout << "BCryptOpenAlgorithmProvider failure\n";
    }
    NTSTATUS status=BCRYPT_SUCCESS(BCryptGenRandom(
            &handle,bPointer,sizeof(Buffer),0
    ));
    if(!BCRYPT_SUCCESS(status)){
            printf("%X",status);
            std::cout << "Error in BCryptGenRandom";
    }
    BCryptCloseAlgorithmProvider(
            handle,0
    );
    return static_cast<int>(reinterpret_cast<intptr_t>(bPointer));
}

原始代码在调用 BCryptGenRandom 时声称缓冲区为 128 字节,但事实并非如此。原始代码中名为 c_seed 的缓冲区是一个野指针,最有可能的大小为 8。

在这种情况下,c_seed,现在别名为 bPointer,不再是狂野的 - 它指向 int Buffer。此缓冲区的大小正在使用 sizeof 宏传递给函数,因此尽管它的大小可能为 8,但它可以适应我使用的 cross-compiler 需要的任何目标架构。