2013-06-03 33 views
-1

我尝试使用CryptGenRandom()调用创建随机数以避免加密攻击。 我试着运行打印rand调用和CryptGenRandom()调用的follwing代码。CryptGenRandom输出与rand()调用相同

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? CryptGenRandom()只给出3个数字的随机数字,这些数字不足以设置我在代码中使用的睡眠呼叫的值。

+2

严...... **否**。 'CryptGenRandom'是一个密码安全的PRNG。如果你可以让它产生一个特定的序列,这将是一个**巨大的问题。 'CryptGenRandom'的输出有什么问题? –

+5

它只给出3位整数输出_因为你只使用第一个BYTE_。尝试'* static_cast (pbBuffer)'并比较... – Useless

+0

我试图改变BYTE,但它不工作。你能帮我解决这个问题吗? – user1488334

回答

3

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

static_cast<unsigned int>(pbBuffer[0]) 

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

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

const DWORD dwLength = sizeof(unsigned int); 

而这一点,使用的所有字节pBuffer

*static_cast<unsigned int*>(pbBuffer) 
+0

如果我想这样做,它显示以下错误:错误C2664:'CryptGenRandom':不能将参数3从'unsigned int [4]'转换为'BYTE *' 指向的类型是无关的;转换需要reinterpret_cast,C风格转换 或函数风格转换 – user1488334

+2

@DrewDorman:该指针转换不安全,缓冲区可能无法正确对齐'unsigned int'。 –

+1

@MooingDuck另外,这不会解决原始代码的另一个(小问题):当一个人会这样做时,调用'CryptGenRandom'5次(生成4个字节)。 –

2

嗯,这只是给3位数字,因为你正在服用只有一个字节,并将其转换为unsigned int当你这样做:static_cast<unsigned int>(pbBuffer[0])和​​(即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 
    } 
} 
+0

任何人都可以帮助我获得完整的数字,而不是一个字节。如果我尝试打印这样的错误,我发布上面。 – user1488334

+0

我试图建立以下代码,并从循环外侧调用时获得相同的输出。 – user1488334

+0

@ user1488334:哪个代码?你能向我们展示*完全*你所说的以及如何? –

相关问题