Storing the IV with the ciphertext Crypto++ CBC AES encryption

前端 未结 2 985
礼貌的吻别
礼貌的吻别 2021-01-07 12:43

I\'m trying to encrypt(and decrypt after) a file using AES in CBC mode and Crypto++ library

Here\'s what I already did:

using namespace CryptoPP;
Aut         


        
2条回答
  •  死守一世寂寞
    2021-01-07 12:49

    Storing the IV with the ciphertext Crypto++ CBC AES encryption

    Some of the code you are using is a bit unusual to me. I'll pick a couple things out and show you some of the Crypto++ ways.

    Before you begin, take a look at Pipelines and Pumping Data on the Crypto++ wiki. Remember that data flows from sources to sinks. In between the data encounters filters which transform the 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();
    

    A Crypto++ FileSource has a constructor that takes a std::istream. You could do something like the following. Also see FileSource on the 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 are for the FIPS DLL. You can use them without the DLL, but they exist for the DLL. Usually you use:

     CBC_Mode::Encryption encryptor;
    

    Also, you usually want to avoid a confidentiality-only mode. Typically you want to use an Authenticated Encryption mode of operation. It provides confidentiality and authenticity.

    Crypto++ provides CCM, EAX and GCM authenticated encryption modes of operation. OCB and EAX are very good choices. EAX mode is documented at EAX Mode on the Crypto++ wiki. OCB is not available at the moment. We are getting ready to check-in OCB mode.


    Now,i want to write the encrypted string to a file,and store the IV with it,since the iv doesn't need to be kept secret,ideally at the beginning or the end of the ciphertext

    Use something like the following. I did not compile it, so you will need to fix the typos.

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

    When i will try to decrypt this file,how can i extract the iv and ciphertext separately ?

    Use something like the following.

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

    The encrypted data will be in a ByteQueue. It does not provide C++ iterator-like functionality, like a pointer and a size. To get the data out of the ByteQueue you transfer it or copy it to another filter or a sink:

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

    You can get the data out of the ByteQueue and put it in astd::string with:

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

    And you can print the IV recovered from the file with:

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

提交回复
热议问题