CryptGenRandom在调用循环时给出相同的值

时间:2013-06-04 06:26:58

标签: c++ c windows visual-c++

抱歉,我不能为此使用单独的类,我尝试构建以下代码并在循环中从外侧调用时获得相同的输出。

unsigned int crypt_rand()
{
    HCRYPTPROV hProvider = 0;
    const DWORD dwLength = sizeof(unsigned int);
    unsigned int pbBuffer[dwLength] = {};

    if (!::CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
        return 1;
    if (!::CryptGenRandom(hProvider, sizeof(unsigned int), reinterpret_cast<PBYTE>(&pbBuffer)))
    {
        ::CryptReleaseContext(hProvider, 0);
        return 1;
    }
    if (!::CryptReleaseContext(hProvider, 0))
        return 1;
    return (unsigned int)pbBuffer;

}                                      

如果我从循环调用此函数每次都获得相同的输出。这是我在这个方法中可以像输入一样给出的任何东西。你能帮我解决这个问题吗?

for (DWORD i = 0; i < 5; ++i)
    {
        rand_no = crypt_rand();
        std::cout << "windows::"<<i<<"::"<<rand_no<< std::endl;
    }

输出

windows::0::4519964
windows::1::4519964
windows::2::4519964
windows::3::4519964
windows::4::4519964

3 个答案:

答案 0 :(得分:4)

使用强制转换(reinterpret_castreturn语句中的一个)隐藏了一些重要的编译器错误,这些错误可以让您首先正确编写此代码。

尽可能避免使用强制转换,而是修改类型。

CryptGenRandom期待

BYTE *pbBuffer

参数。传递一个指向BYTE 数组的指针,而不是其他任何东西(你传递一个指向int数组的指针。)

在您的退货声明中,您要将地址转换为unsigned int。您需要获取BYTE数组并将其包含的转换为int(您可以在线找到该示例,或者您可以通过坐换和添加自己创建一个)。你现在正在做的可能是一遍又一遍地输出相同的地址(或部分地址)。

澄清一下,将数组定义为

BYTE pbBuffer[dwLength] = {};

并将您的功能称为

::CryptGenRandom(hProvider, dwLength, pbBuffer)

避免使用强制转换,尤其是C样式转换,并阅读有关数组的内容。在C ++中,当传递给函数时,数组会衰减到指向数组第一个元素的指针。如果您有一个BYTE数组,它将衰减为BYTE*,即函数的预期类型。

答案 1 :(得分:0)

问题出在return (unsigned int)pbBuffer;这里你只是每次都得到pbBUffer的地址。如果pbBuffer是一个数组,函数crypt_rand返回unsigned int那么它应该是返回时数组的元素。

您需要在编译期间启用警告。这些可能的错误必须作为警告。

答案 2 :(得分:0)

你想要一个无符号整数的随机数吗? 只需将BYTE缓冲区的内容强制转换为unsigned int

即可

怎么样:

unsigned int crypt_rand()
{
    HCRYPTPROV hProvider = 0;
    const DWORD dwLength = sizeof(unsigned int);
    BYTE buffer[dwLength];

    if (!::CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
        return 1;
    if (!::CryptGenRandom(hProvider, sizeof(buffer), &buffer))
    {
        ::CryptReleaseContext(hProvider, 0);
        return 1;
    }
    if (!::CryptReleaseContext(hProvider, 0))
        return 1;
    return *(unsigned int*)buffer;
}