CryptGenRandom输出与rand()调用不一样

时间:2013-06-03 16:45:40

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

我尝试使用CryptGenRandom()调用创建随机数,以避免加密攻击。 我试图运行以下代码来打印rand调用和CryptGenRandom()调用。

    HCRYPTPROV hProvider = 0;

    const DWORD dwLength = 5;

    BYTE pbBuffer[dwLength] = {};

    if (!::CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL,  CRYPT_VERIFYCONTEXT|CRYPT_SILENT))

    return 1;

    srand((unsigned)time (0));
    for(int i=0; i<10; ++i)
        cout<<"rand()::"<<i<<":"<<rand()<<endl;

    for (DWORD i = 0; i < dwLength; ++i)
    {
        if (!::CryptGenRandom(hProvider, dwLength, pbBuffer))
        {
            ::CryptReleaseContext(hProvider, 0);
            return 1;
        }
     std::cout << "windows::"<<i<<"::"<<static_cast<unsigned int>(pbBuffer[0])<< std::endl;
    }

    if (!::CryptReleaseContext(hProvider, 0))
    return 1;

但是rand()来电的输出是

rand()::0:9754
rand()::1:526
rand()::2:29162
rand()::3:10461
rand()::4:31585
rand()::5:15594
rand()::6:12157
rand()::7:19178
rand()::8:5413
rand()::9:16157

CryptGenRandom()来电正在

windows::0::167
windows::1::138
windows::2::197
windows::3::101
windows::4::44

任何人都可以帮我获得使用CryptGenRandom进行rand()调用的相同输出吗? CryptGenRandom()只提供3位数的随机数,这些数字不足以设置我在我的代码中使用的睡眠调用值。

2 个答案:

答案 0 :(得分:3)

问题是你在这里使用pBuffer[0]

 static_cast<unsigned int>(pbBuffer[0])

正如您的代码所示,pBuffer[0]是一个BYTE。这就是为什么你没有得到大于255的值。

如果你想要任何可表示的unsigned int,你会想要这个。

const DWORD dwLength = sizeof(unsigned int);

这就是使用pBuffer中的所有字节。

 *static_cast<unsigned int*>(pbBuffer)

答案 1 :(得分:2)

嗯,它只提供3位数字,因为您只需要一个字节并在执行此操作时将其转换为unsigned intstatic_cast<unsigned int>(pbBuffer[0])BYTE(即{{1} 1}})只能适应0到255之间的值。

您可以稍微改变一下方法:

unsigned char

此函数将在失败时返回unsigned int MyGoodRand() { // We make this a static so we don't have // to initialize it all the time because // that is expensive. static HCRYPTPROV hProvider = 0; if(hProvider == NULL) { if(!::CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) return 0; } unsigned int randval = 0; if (!::CryptGenRandom(hProvider, sizeof(unsigned int), static_cast<PBYTE>(&randval))) randval = 0; // Failure! return randval; } ,这是一个问题,因为0也是0的可能结果,并且还会泄漏CryptGenRandom,因为它仅在函数内部可用且一旦分配,就没有办法释放它。

我们可以对其进行扩充,以相应地返回HCRYPTPROVtrue,并通过其调用者的引用接受false,但这不会解决randval泄漏问题。我们改为将HCRYPTPROV作为成员class以及HCRYPTPROV来生成新数字。

这样的事情:

operator()

现在我们没有泄漏,我们可以轻松生成随机数,并确定操作是否成功可靠。我们可以像这样使用它:

class MYPRNG
{
private:
    HCRYPTPROV hProvider;

    // declare but not define a private copy constructor to
    // prevent copy-construction of this object. If you're
    // using C++11 you can use the =delete syntax instead.
    MYPRNG(const MYPRNG &o) = delete; 

    // Same with the default assignment operator.
    MYPRNG& operator=(const MYPRNG& o)

public:
    MYPRNG()
        : hProvider(NULL)
    {
        if(!::CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, 
                                  CRYPT_VERIFYCONTEXT|CRYPT_SILENT))
            hProvider = NULL; // ensure that it's NULL
    }

    ~MYPRNG()
    {
        if(hProvider)
            CryptReleaseContext(hProvider, 0);
    }

    bool operator()(unsigned int &randval)
    { 
        if(hProvider == NULL)
            return false;

        if (!::CryptGenRandom(hProvider, 
                              sizeof(unsigned int), 
                              static_cast<PBYTE>(&randval)))
            return false;

        return true;
    }
};