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

前端 未结 2 960
礼貌的吻别
礼貌的吻别 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<AES>::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<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)));
    

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

    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;
    
    0 讨论(0)
  • 2021-01-07 13:02

    The StringSink has the following documentation:

    A StringSink serves as a destination for string data in the pipelining paradigm. The data can be binary or ASCII.

    So although it is a string, it is internally an octet- or byte string. So yes, you can just save the IV and ciphertext that way.

    But to be sure, just compare the length of the result with the IV size (16 bytes) and ciphertext size together. If it is equal then you should be fine.

    0 讨论(0)
提交回复
热议问题