2017-08-02 3 views
1

Ich versuche, zu verschlüsseln (nach und entschlüsseln) eine Datei mit AES im CBC-Modus und Crypto ++ BibliothekSpeichern der IV mit dem verschlüsselten Text Crypto ++ CBC-AES-Verschlüsselung

Hier ist, was ich schon tat:

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); 

eine Datei zu verschlüsseln, ich öffne es im binär-Modus, und Dump den Inhalt in einen String:

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(); 

Dann verschlüsseln ich diese Zeichenfolge mit dem Schlüssel und iv zuvor erzeugten:

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(); 

Nun, ich mag den verschlüsselten String in eine Datei schreiben, und speichern Sie die IV mit ihm, da der iv nicht geheim werden muss gehalten werden, idealerweise am Anfang oder Ende des chiffrierten Textes

Hier kommt das Problem: die IV ist ein Byte-Array und der verschlüsselte Text ist eine Zeichenfolge, benötige ich eine der beiden in einen anderen Typ zu konvertieren, oder kann ich nur tun:

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

Wenn ich werde versuchen, Um diese Datei zu entschlüsseln, wie kann ich den iv und chiffretext getrennt extrahieren? Die IV ist 16 Bytes lang, aber hier bin ich komplett verloren und ich weiß nicht wie es geht.

+0

gibt es keine vorgefertigten primitiv, dass in diesem lib für Sie tun? Nein? Dann seien Sie vorsichtig und lesen Sie sich die base64-Codierung durch. – sascha

+0

Ich habe nichts im wiki gesehen, das zu tun. Ich kann das iv (das ein Byte [] ist) zu einem String kodieren, aber der Dekodierungsprozess ist komplizierter, da er den kodierten String in einen decodierten String konvertiert, und ich möchte meine Byte-Array wiederherstellen :) – EinderJam

Antwort

0

Die StringSink hat die folgende Dokumentation:

A StringSink dient als Ziel für die String-Daten im Pipelining Paradigma. Die Daten können binär oder ASCII sein.

Und obwohl es ein String ist, ist es intern ein octet- oder Bytestring. Also ja, du kannst den IV und den Chiffretext einfach so speichern.

Aber um sicher zu sein, vergleichen Sie einfach die Länge des Ergebnisses mit der IV-Größe (16 Bytes) und Chiffretext-Größe zusammen. Wenn es gleich ist, sollte es dir gut gehen.

1

Speichern der IV mit dem verschlüsselten Text Crypto ++ CBC-AES-Verschlüsselung

Einige der Code, den Sie verwenden, ist ein bisschen zu mir ungewöhnlich. Ich wähle ein paar Dinge aus und zeige dir einige der Möglichkeiten von Crypto ++.

Bevor Sie beginnen, werfen Sie einen Blick auf Pipelines und Pumping Data auf dem Crypto ++ Wiki. Denken Sie daran, dass Daten von Quellen zu Senken fließen. Dazwischen treffen die Daten auf Filter, die die Daten transformieren.


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(); 

A Crypto ++ FileSource hat einen Konstruktor, der ein std::istream dauert. Sie könnten etwas wie das Folgende tun. Siehe auch FileSource im Crypto ++ Wiki.

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 sind für die FIPS-DLL. Sie können sie ohne die DLL verwenden, aber sie existieren für die DLL. Normalerweise verwenden Sie:

CBC_Mode<AES>::Encryption encryptor; 

Auch Sie in der Regel vermeiden wollen eine Vertraulichkeit-only Modus. Normalerweise möchten Sie eine Authenticated Encryption Betriebsart verwenden. Es bietet Vertraulichkeit und Authentizität.

Crypto ++ bietet CCM, EAX und GCM authentifizierte Verschlüsselungsmodi. OCB und EAX sind eine sehr gute Wahl. Der EAX-Modus ist unter EAX Mode im Crypto ++ Wiki dokumentiert. OCB ist im Moment nicht verfügbar. Wir bereiten uns auf den OCB-Modus vor.


Nun, ich möchte den verschlüsselten String in eine Datei schreiben, und speichern Sie die IV mit ihm, da der iv muss nicht geheim gehalten werden, idealerweise am Anfang oder am Ende der Chiffretext

Verwenden Sie etwas wie folgt. Ich habe es nicht kompiliert, also müssen Sie die Tippfehler beheben.

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))); 

Wenn ich werde versuchen, diese Datei zu entschlüsseln, wie kann ich extrahieren Sie die iv und Chiffretext getrennt?

Verwenden Sie etwas wie folgt.

// 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 

Die verschlüsselten Daten werden in einem ByteQueue sein. Es ist nicht bieten C++ Iterator-ähnliche Funktionalität, wie ein Zeiger und eine Größe. Um die Daten zu erhalten, aus dem ByteQueue Sie es übertragen oder kopieren Sie sie in einem anderen Filter oder ein Waschbecken:

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

Sie können die Daten erhalten aus dem ByteQueue und steckte es in eine std::string mit:

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

Und Sie können die IV aus der Datei wiederhergestellt drucken mit:

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

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

Vielen Dank! Es gibt etwas, das ich nicht verstehe: mit dieser FileSource-Quelle (Fin, true/* Pumpe alle * /, NULLPTR); , wo speichern Sie den Dateiinhalt?Ich bekomme auch eine "Fin: Multiples Initialisierungen mit Ihrem ifstream/filesource Beispiel – EinderJam

+0

@Einder - Stellen Sie eine neue Frage und zeigen Sie Ihren Code. Ich muss sehen, was Sie tun. Auch zeigen Sie die vollständige Fehlermeldung. – jww

+0

Ich habe den Fehler behoben (fin war der Name, den ich vorher benutzte, um den Klartext zu lesen), aber meine Frage bleibt – EinderJam

Verwandte Themen