2017-07-19 43 views
1

我正在嘗試將AES密鑰寫入文件,稍後再讀取它。我正在使用Crypto ++庫,並且AES密鑰被初始化如下。以下,byteunsigned char的類型定義。如何在文件中讀寫AES密鑰?

byte key[CryptoPP::AES::MAX_KEYLENGTH] 

密鑰長度爲32個字節。我嘗試它被寫入到這個文件:

FILE* file = fopen("C:\\key", "wb"); 
fwrite(key, 1, sizeof(key), file); 
fclose(file); 

而且使用恢復它:

FILE* read_file = fopen("C:\\key", "rb"); 
fseek(read_file, 0, SEEK_END); 
long int size = ftell(read_file); 
fclose(read_file); 

read_file = fopen("C:\\key", "rb"); 
unsigned char * in = (unsigned char *)malloc(size); 
byte readed_key = fread(in, sizeof(unsigned char), size, read_file); 
fclose(read_file); 
if (key == readed_key) 
{ 
    cout << "this is the right key !"; 
} 
free(in); 

不過,我得到一個錯誤信息:

不兼容的操作數類型:字節*和字節。

我不明白爲什麼,因爲readed_keykeybyte而不是byte*初始化。


我看着AES的加密+維基,關鍵是如下產生。我想通了,我只是創建密鑰(不產生它):

SecByteBlock key(0x00, AES::MAX_KEYLENGTH); 
rnd.GenerateBlock(key, key.size()); 

有了,我不能用

std::vector<byte> key(32); 
rnd.GenerateBlock(key, key.size()); 

因爲rnd.Generateblock不能轉換std::vector<byte> into byte*

這是讓我發瘋......

+0

您應該避免'FILE *';並堅持使用C++並使用'ifstream'。或者,使用Crypto ++ ['FileSource'](https://www.cryptopp.com/wiki/FileSource)。另請參閱Crypto ++ wiki上的[std :: byte](https://www.cryptopp.com/wiki/Std::byte)和[Issue 442,Test C++ 17字節更改(來自各個項目的幹運行)]( https://github.com/weidai11/cryptopp/issues/442)在問題跟蹤。 'byte'正準備轉換到'CryptoPP :: byte'。 – jww

+0

[如何將二進制文件讀入無符號字符向量](https://stackoverflow.com/q/15138353),[將文件加載到向量](https://stackoverflow.com/ q/7241871),[將文件讀入std :: vector的有效方法?](https://stackoverflow.com/q/4761529/608639),[正​​確讀取和寫入std :: vector到文件中使用迭代器](https://stackoverflow.com/q/36506297),[正確讀取和寫入std :: vector到文件中](https://stackoverflow.com/q/12372531),[如何讀取文件到C++中的矢量?](https://stackoverflow.com/q/15138785)等 – jww

回答

3

如何讀寫文件中的AES密鑰?

我要避開你的代碼,因爲它主要是C代碼。安德魯指出了它的一些問題,所以沒有意義重新調整它。相反,我會向你展示Crypto ++和C++的處事方式。我還會討論一下SecByteBlock


這裏是Crypto ++的方式來讀取數據到使用源和匯的字節數組。您可以在Crypto ++ wiki的Pipelines中閱讀更多關於它們的信息。

byte key[CryptoPP::AES::MAX_KEYLENGTH]; 
FileSource fs("C:\\key.bin", true, new ArraySink(key, sizeof(key))); 

以下是使用源和匯將數據寫入文件的Crypto ++方法。

byte key[CryptoPP::AES::MAX_KEYLENGTH]; 
ArraySource as(key, sizeof(key), true, new FileSink("C:\\key.bin")); 

這裏是C++的方式來將數據讀入使用流的字節數組。它取自Reading and writing binary file

byte key[CryptoPP::AES::MAX_KEYLENGTH]; 
std::ifstream fs("C:\\key.bin", std::ios::binary); 
fs.read(key, sizeof(key)); 

以下是使用流將數據寫入文件的C++方法。

byte key[CryptoPP::AES::MAX_KEYLENGTH]; 
std::ofstream fs("C:\\key.bin", std::ios::binary); 
fs.write(key, sizeof(key)); 

std::vector<byte> key(32); 
rnd.GenerateBlock(key, key.size()); 

因爲rnd.Generateblock不能轉換成std::vector<byte> byte*。這讓我瘋狂......

在這裏,你需要一個非const指針指向第一個元素。採取向量中第一個元素的地址。這同樣適用於std::string

std::vector<byte> key(32); 
rnd.GenerateBlock(&key[0], key.size()); 

由於密鑰是敏感的,你應該使用SecByteBlock。一旦完成使用,它會將內存中的密鑰歸零。

一般來說,如果信息是敏感的,那麼你想使用SecBlock<T>。在SecByteBlock的情況下,Tbyte並且存在SecByteBlock的typedef。但是你可以做任何事情SecBlock<T>

以下是Crypto ++的使用信號源和接收器將數據讀入SecByteBlock的方法。

SecByteBlock key(AES::MAX_KEYLENGTH); 
FileSource fs("C:\\key.bin", true, new ArraySink(key.begin(), key.size())); 

SecByteBlock可以初始化元件在構造的已知值。您正在使用下面的功能。所有元素都被初始化爲0x00

SecByteBlock key(0x00, AES::MAX_KEYLENGTH); 
rnd.GenerateBlock(key, key.size()); 

既然你立即用隨機數據覆蓋的元素,你應該放棄初始化。只要求一個未初始化的內存塊:

SecByteBlock key(AES::MAX_KEYLENGTH); 
rnd.GenerateBlock(key, key.size()); 
+0

感謝您的詳細解答,jww,如果您願意,請更正'intialize'。:) –

+0

謝謝@Teo。是的,有時候我是一個可怕的拼寫器。如果我打開拼寫檢查,那麼它會將我的拼寫錯誤變成錯誤的語法... – jww

+0

呵呵,沒關係。我自己恰好是一個糟糕的拼寫者。 –

2

keyarray of byte,即其類型是byte[32](假定CryptoPP::AES::MAX_KEYLENGTH是等於32的整數常量)。 byte[N]在某些情況下衰減至byte*,包括在使用==進行比較期間,例如在您的if (key == readed_key)行中。

readed_key定義爲byte,這是不相同的。

此外,您錯誤地使用了fread (3);返回值是讀取的項目數,而不是讀取的數據。您讀取的數據存儲在in陣列中。您需要將key的每個元素與in的每個元素進行比較,以檢查密鑰是否相同。

編輯:感謝@vasek爲指出的比較應該因爲你是用C++編寫

if (memcmp(key, in, size) == 0) { /* keys are equal */ } 

(該加密++庫是一個C++庫),你可以使用更高以避免手動內存管理與malloc/free並使代碼更易於使用:

live example

#include <cstdint> 
#include <fstream> 
#include <iostream> 
#include <vector> 

using byte = char; 

int main() { 
    std::vector<byte> key(32); 
    // Code would go here to generate the `key` 
    // ... 

    { 
     std::ofstream out("C:\\key", std::ios::out | std::ios::binary); 
     out.write(key.data(), key.size()); 
    } // file is closed automatically here! 

    std::vector<byte> read_key(32); 
    { 
     std::ifstream in("C:\\key", std::ios::in | std::ios::binary); 
     in.read(read_key.data(), read_key.size()); 
    } 

    if (key == read_key) { 
     std::cout << "Keys are equal!\n"; 
    } 

    return 0;  
} 

這裏,std::vector<byte>處理內存分配(您只需在構造函數中告訴它的大小;使用.data()來獲取指向內容的指針;全鍵的比較免費提供,std::vectoroperator==),而C++ iostreams read/writefread/fwrite相比要容易一些。你仍然可以通過尋找來確定密鑰大小;我會把它作爲exercise to the reader

+1

也值得注意的比較應該使用'if(memcmp(key,in,size)== 0){/ *鍵是相等的* /}' – vasek

+0

我明白。所以有一種方法(與fread或不),以返回文件中的數據並將其存儲在一個字節數組? – EinderJam

+1

'fread(in,sizeof(unsigned char),size,read_file)'是正確的,但key不在'fread'的返回值中,但是在'in'數組中。 – vasek