-1

我尝试使用 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 位随机数,不足以设置我在代码中使用的睡眠调用的值。

4

2 回答 2

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)
于 2013-06-03T16:51:33.380 回答
2

嗯,它只给出 3 位数字,因为你只需要一个字节并将其转换为 anunsigned int当你这样做:static_cast<unsigned int>(pbBuffer[0])并且 a BYTE(即 an 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泄漏问题。让我们创建一个classwhichHCRYPTPROV作为成员,以及一个operator()which 将用于生成新数字。

像这样的东西:

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
    }
}
于 2013-06-03T16:51:19.970 回答