2016-01-22 99 views
1

我剛開始研究cryptopp庫。我有一個圖像緩衝區,我想用一些密鑰加密,然後解密但面臨問題,解密和原始圖像不一樣。 我不知道加密或不加密的天氣問題,有人可以幫我解決這個問題。使用解密後的圖像與原始圖像不一樣

Qt Creator的

代碼:

AutoSeededRandomPool prng; 

SecByteBlock key(AES::DEFAULT_KEYLENGTH); 
prng.GenerateBlock(key, key.size()); 

byte ctr[ AES::BLOCKSIZE ]; 
prng.GenerateBlock(ctr, sizeof(ctr)); 

string cipher, encoded, recovered; 

QFile file("original.png"); 
if(!file.open(QIODevice::ReadOnly)){ 
    cout << "could not open the file"<< endl; 
} 

QByteArray buffer = file.readAll(); 

qDebug()<<"buffer length"<<buffer.length(); 

file.close(); 

try 
{ 
    CTR_Mode<AES>::Encryption e; 
    e.SetKeyWithIV((byte*)key.data(), key.size(), ctr); 

    StringSource ss1(buffer, true, 
         new StreamTransformationFilter(e, 
                 new StringSink(cipher) 
                ) 
        ); 

} 
catch(CryptoPP::Exception& e) 
{ 
    cerr << e.what() << endl; 
    exit(1); 
} 

qDebug()<<"cipher length "<<cipher.length(); 

try 
{ 
    CTR_Mode<AES>::Decryption d; 
    d.SetKeyWithIV((byte*)key.data(), key.size(), ctr); 
    StringSource ss3(cipher, true, 
         new StreamTransformationFilter(d, 
                 new StringSink(recovered) 
                ) 
        ); 

} 
catch(CryptoPP::Exception& e) 
{ 
    cerr << e.what() << endl; 
    exit(1); 
} 

qDebug()<<"recovered length "<<recovered.length(); 
QFile ouput("recovered.png"); 
if(ouput.open(QIODevice::WriteOnly)){ 
    ouput.write(recovered.data(), recovered.size()); 
    ouput.close(); 
} 

響應:

buffer length 538770 
cipher length 8 
recovered length 8 

爲什麼我的密碼長度只有8。

+0

***'字符串鍵= 「7D9BB722DA2DC8674E08C3D44AAE976F」;'*** - 你可能需要一個二進制串;不是一個ASCII字符串。對於Crypto ++,請參閱Crypto ++ wiki上的[HexDecoder](https://www.cryptopp.com/wiki/HexDecoder)。我不確定QT提供的服務。 – jww

回答

1

我發現與QByteArray緩衝區的問題。我只是轉換爲std :: string它的工作。

QByteArray buffer = file.readAll(); 

// string 
std::string stdString(buffer.data(), buffer.length()); 

//used stdString instead of buffer in pipeline 
StringSource ss1(stdString, true, 
           new StreamTransformationFilter(e, 
                   new StringSink(cipher) 
                  ) 
          ); 
+0

通過使用不同的*** StringSource構造函數,可以避免多餘的副本進入*** std :: string ***。使用需要'byte *'和'size'的那個。另請參閱Crypto ++ wiki上的[StringSource](https://www.cryptopp.com/wiki/StringSource)。你想使用的構造函數是第四個。 – jww

1

在你的代碼要轉換的文件內容爲Base64, 對其進行加密,解密,並將其保存到一個文件中(這樣就節省了PNG文件爲Base64)

你應該加密的原始文件數據(而不是Base64編碼的)。

編輯:編輯後,我不知道什麼失敗。請嘗試以下功能,這對我很有用。使用FileSourceFileSink,但應該相應地使用StringSource和StringSink。

bool encryptdecrypt(const std::string& filename) 
{ 
    std::string key = "7D9BB722DA2DC8674E08C3D44AAE976F"; 
    byte ctr[ CryptoPP::AES::BLOCKSIZE ]; 
    std::string cipher; 

    try 
    { 
     CryptoPP::CTR_Mode<CryptoPP::AES>::Encryption e; 
     e.SetKeyWithIV((byte*)key.data(), key.size(), ctr); 

     CryptoPP::FileSource(filename.c_str(), true, 
      new CryptoPP::StreamTransformationFilter(e, 
       new CryptoPP::StringSink(cipher) 
      ) 
     ); 

    } 
    catch(CryptoPP::Exception& e) 
    { 
     std::cerr << e.what() << std::endl; 
     return false; 
    } 

    try 
    { 
     CryptoPP::CTR_Mode<CryptoPP::AES>::Decryption d; 
     d.SetKeyWithIV((byte*)key.data(), key.size(), ctr); 
     CryptoPP::StringSource(cipher, true, 
      new CryptoPP::StreamTransformationFilter(d, 
       new CryptoPP::FileSink(("decrypted_" + filename).c_str()) 
      ) 
     ); 

    } 
    catch(CryptoPP::Exception& e) 
    { 
     std::cerr << e.what() << std::endl; 
     return false; 
    } 
    return true; 
} 
+1

您還應該考慮使用[PBKDF2](https://en.wikipedia.org/wiki/PBKDF2)進行重點拉伸。你也可以看看Crypto ++的一些Crypto ++功能的封裝器[LimeCrypt](https://github.com/jahnf/lime-crypt)的代碼。 – Jahn

+0

我剛更新了代碼。我仍然沒有獲得原始圖像。我甚至不能打開recover.png它說圖像加載失敗 – Jeggu

+0

我更新了我的答案與一個工作的例子,因爲我看不到你的代碼中的錯誤後,你的編輯了。如果這對你有用,你可以試試。 – Jahn

2
QFile ouput("recovered.png"); 
if(ouput.open(QIODevice::WriteOnly)){ 
    ouput.write(recovered.c_str()); 
    ouput.close(); 
} 

讓我扔雷在鍋....你是治療二進制數據爲C字符串,這意味着讀/寫停在第一個NULL字符。您應該使用帶有指針和大小的重載。也許是這樣的:

ouput.write(recovered.data(), recovered.size()); 

(後代碼編輯)

QByteArray buffer = file.readAll(); 
... 
StringSource ss1(buffer, true, ...); 

這可能不是產生預期的結果。也許你應該嘗試:

QByteArray buffer = file.readAll(); 
... 
StringSource ss1(buffer.data(), buffer.size(), true, ...); 

以上StringSource過載,有指針大小,是你應該在這種情況下的首選項。它的設計準確的情況下,它節省了額外的副本buffer

你甚至可以使用FileSourceFileSink`與加密+集成::

FileSource ifile("original.png", true, 
        new StreamTransformationFilter(e, 
         new StringSink(cipher) 
        ) 
       ); 

此外,Barmak是正確的約:

在你的情況下,你稱它爲ctr,但它是s eems未初始化...

雖然未初始化,但同樣的[未知]值用於加密和解密,所以問題沒有顯示出它的頭。它會在稍後顯示,就像在一臺機器上加密並在另一臺機器上解密一樣。

您應該按照Barmak的建議進行初始化。也許是這樣的:

byte ctr[16]; 
OS_GenerateRandomBlock(false, ctr, sizeof(ctr)); 

OS_GenerateRandomBlockRandomNumberGenerator上加密+維基討論。


您通常可以在明文中將計數器發送給消息,因爲它通常被視爲公共值。但它確實取決於您的安全模型。

一定要從不以計數器模式重用安全上下文。每條消息必須在唯一的安全上下文中進行加密。安全上下文是012對。


還可以打印與計數器:

byte ctr[16]; 
OS_GenerateRandomBlock(false, ctr, sizeof(ctr)); 

HexEncoder encoder(new FileSink(cout)); 

cout << "Counter: "; 
encoder.Put(ctr, sizeof(ctr)); 
encoder.MessageEnd(); 
cout << endl; 

上面的代碼只是己編碼的原始字節數組然後ND打印它stdout


(評論)string key = "7D9BB722DA2DC8674E08C3D44AAE976F"; - 你可能需要一個二進制串;不是一個ASCII字符串。對於Crypto ++,請參閱Crypto ++ wiki上的HexDecoder。我不確定QT提供的服務。

因爲這裏有更多的空間......這是你可以做的事情之一:

string key, encodedKey = "7D9BB722DA2DC8674E08C3D44AAE976F"; 
StringSource ss(encodedKey, true, new HexDecoder(key)); 

後的語句執行,字符串key將二進制數據。

+0

感謝您的回覆。我做了改變,因爲你仍然沒有工作。現在我正在顯示緩衝區,密碼,已恢復數據的長度 – Jeggu