CryptGenRandom输出与rand()调用不同

CryptGenRandom output not getting same as rand() call

本文关键字:调用 输出 rand CryptGenRandom      更新时间:2023-10-16

我尝试使用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

and CryptGenRandom() call is giving

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

谁能帮助我得到相同的输出是给rand()调用使用CryptGenRandom?CryptGenRandom()只给出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)

嗯,它只给出3位数字,因为当你这样做时,你只取一个字节并将其转换为unsigned int: static_cast<unsigned int>(pbBuffer[0])BYTE(即unsigned char)只能适合0到255之间的值。

你可以稍微改变一下你的方法:

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的可能结果,并且还会泄漏HCRYPTPROV,因为它只在函数内部可用,一旦分配就没有办法释放它。

我们可以将其扩展为返回truefalse,并通过调用者的引用接受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;
    }
};

现在我们没有泄漏,我们可以很容易地生成随机数并可靠地确定操作是否成功或失败。我们可以这样使用它:

MYPRNG prng;
unsigned int rval;
for(int i = 0; i < 10; i++)
{ // try to get 10 random numbers!
    if(!prng(rval))
    {
        // FAILED TO GENERATE A NEW RANDOM NUMBER!
    }
    else
    {
        // A new random number is now in rval. Use it
    }
}