2017-08-02 167 views
1

我試圖加密(後解密)在CBC模式中使用AES文件和加密++庫存儲與密文加密+ CBC AES加密IV

這裏就是我已經做了:

using namespace CryptoPP; 
AutoSeededRandomPool rnd; 

//generating the key and iv 
SecByteBlock key(AES::MAX_KEYLENGTH); 
rnd.GenerateBlock(key, key.size()); 
byte iv[AES::BLOCKSIZE]; 
rnd.GenerateBlock(iv, AES::BLOCKSIZE); 

要加密的文件,我在二進制模式下打開它,並轉儲內容的字符串:

std::ifstream fin(file_path, std::ios::binary); 
if (!fin) 
{ 
    std::cout << "error"; 
} 
std::ostringstream ostrm; 
ostrm << fin.rdbuf(); 
std::string plaintext(ostrm.str()); 
fin.close(); 

然後,我使用加密密鑰此字符串和IV以前生成的:

std::string ciphertext; 

AES::Encryption aesEncryption(key, CryptoPP::AES::MAX_KEYLENGTH); 
CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv); 

StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(ciphertext)); 
stfEncryptor.Put(reinterpret_cast<const unsigned char*>(plaintext.c_str()), plaintext.length() + 1); 
stfEncryptor.MessageEnd(); 

現在,我想寫的加密字符串到一個文件,並存儲IV用它,因爲IV不需要保密的,理想的開頭或密文的末尾

這裏談到的問題:IV是一個字節數組和密文是一個字符串,我需要到兩個中的一個轉換爲另一種類型,或可我只是做:

std::ofstream fdout(file_path2, std::ios::binary); 
if (!fdout) 
{ 
    std::cout << "error"; 
} 
fdout << iv; 
fdout << ciphertext; 
fdout.close(); 

的時候我會嘗試解密這個文件,我如何分別提取iv和密文? IV是16字節長,但在這裏我完全失去了,我不知道該怎麼做。

+0

有沒有預先製作的原始幹這個的,你在這個LIB?沒有?然後小心並閱讀base64編碼。 – sascha

+0

我沒有看到任何在維基上做的事情。我可以用base64編碼iv(這是一個字節[])到一個字符串,但是解碼過程更復雜,因爲它將編碼的字符串轉換爲解碼的字符串,我想恢復我的字節數組:) :) – EinderJam

回答

0

StringSink具有下列文件:

StringSink用作用於在流水線範例字符串數據的目的地。 數據可以是二進制或ASCII。

所以,雖然它是一個字符串,它在內部是一個octet-或字節串。所以是的,你可以用這種方式保存IV和密文。

但可以肯定的是,只需將結果長度與IV大小(16字節)和密文大小進行比較即可。如果它是平等的,那麼你應該沒問題。

1

存儲與密文加密+ CBC AES加密

一些正在使用的代碼的IV是有點不尋常給我。我會挑選一些東西,並向您展示Crypto ++的一些方法。

在開始之前,請查看Crypto ++ wiki上的PipelinesPumping Data。請記住,數據從源流向宿。數據之間遇到轉換數據的過濾器。


std::ifstream fin(file_path, std::ios::binary); 
if (!fin) 
{ 
    std::cout << "error"; 
} 
std::ostringstream ostrm; 
ostrm << fin.rdbuf(); 
std::string plaintext(ostrm.str()); 
fin.close(); 

甲加密++ FileSource有一個構造採用一個std::istream。你可以做如下的事情。另請參閱Crypto ++ wiki上的FileSource

std::ifstream fin(file_path, std::ios::binary); 
FileSource source(fin, true /*pump all*/, NULLPTR); 
... 

AES::Encryption aesEncryption(key, CryptoPP::AES::MAX_KEYLENGTH); 
CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv); 

ExternalCipher都爲FIPS DLL。您可以在不使用DLL的情況下使用它們,但它們存在於DLL中。通常你用:

CBC_Mode<AES>::Encryption encryptor; 

而且,通常要避免保密,只模式。通常,您希望使用Authenticated Encryption操作模式。它提供了機密性和真實性

Crypto ++提供了CCM,EAX和GCM認證的加密操作模式。 OCB和EAX是非常好的選擇。 EAX模式記錄在Crypto ++ wiki上的EAX Mode。 OCB目前不可用。我們正準備辦理入住手續。


現在,我想寫的加密字符串到一個文件,並存儲IV用它,因爲IV不需要保密的,理想的開頭或結尾部分密文

使用類似下面的內容。我沒有編譯它,所以你需要修正錯別字。

AutoSeededRandomPool prng; 
SecByteBlock key(AES::MAXIMUM_KEYLENGTH), iv(AES::BLOCKSIZE); 

RandomNumberSource rs1(prng, AES::MAXIMUM_KEYLENGTH, new ArraySink(key, key.size())); 
RandomNumberSource rs2(prng, AES::BLOCKSIZE, new ArraySink(iv, iv.size())); 

HexEncoder encoder(new FileSink(std::cout)); 

std::cout << "Key: "; 
encoder.Put(key, key.size()); 
encoder.MessageEnd(); 
std::cout << std::endl; 

std::cout << "IV: "; 
encoder.Put(iv, iv.size()); 
encoder.MessageEnd(); 
std::cout << std::endl; 

EAX<AES>::Encryption encryptor; 
encryptor.SetKeyWithIV(key, key.size(), iv, iv.size()); 

// Plaintext message 
std::string message; 

// Output file 
FileSink file("message.enc"); 

// Source wrappers 
ArraySource as(iv, iv.size(), true, 
    new Redirector(file)); 

// Source wrapper 
StringSource ss(message, true, 
    new StreamTransformationFilter(encryptor, 
     new Redirector(file))); 

的時候我會嘗試解密該文件,我怎麼能提取單獨的IV和密文?

使用類似下面的內容。

// Key is from previous example. It cannot change 
SecByteBlock key(AES::MAXIMUM_KEYLENGTH), iv(AES::BLOCKSIZE);  
FileSource fs("message.enc", false /* DO NOT Pump All */); 

// Attach new filter 
ArraySink as(iv, iv.size()); 
fs.Attach(new Redirector(as)); 
fs.Pump(AES::BLOCKSIZE); // Pump first 16 bytes 

EAX<AES>::Decryption decryptor; 
decryptor.SetKeyWithIV(key, key.size(), iv, iv.size()); 

// Detach previously attached filter, attach new filter 
ByteQueue queue; 
fs.Detach(new StreamTransformationFilter(decryptor, new Redirector(queue))); 
fs.PumpAll(); // Pump remainder of bytes 

加密數據將在ByteQueue。它不是而是提供了C++類似於迭代器的功能,如指針和大小。爲了讓數據出ByteQueue你將其傳送或複製到另一個過濾器或水槽:

SecByteBlock block(queue.MaxRetrievable()); 
ArraySink sink(block, block.size()); 
queue.TransferTo(sink); 

你可以將數據從ByteQueue,並把它放在一個std::string有:

std::string recovered; 
StringSink sink(recovered); 
queue.TransferTo(sink); 

而且可以打印IV從文件恢復:

HexEncoder encoder(new FileSink(std::cout)); 

std::cout << "IV: "; 
encoder.Put(iv, iv.size()); 
encoder.MessageEnd(); 
std::cout << std::endl; 
+0

謝謝!有一些我不明白:用這個 FileSource源(fin,true/* pump all * /,NULLPTR); ,你在哪裏存儲文件內容?我還得到了一個「fin:multiples initialisations with your ifstream/filesource example – EinderJam

+0

@Einder - 提出一個新問題並顯示你的代碼,我需要看看你在做什麼,並且顯示完整的錯誤信息 – jww

+0

我得到了錯誤修正(fin是我之前用來讀取明文的名字),但是我的問題仍然存在 – EinderJam