2013-06-03 35 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:哪個代碼?你能向我們展示*完全*你所說的以及如何? –

相關問題