Search code examples
c++aescrypto++cbc-mode

Decrypt of file displays both original and cipher text?


I am working to encrypt and decrypt files using Crypto++. In encryption, key and random IV are generated and hexencoded where as text from file is encrypted. Both IV and cipher text are written to the same file.

In decryption, key is generated using same criteria as encryption and random IV is extracted from the file and hexdecoded. Text after iv length is stored in a string and decrypted.

What happens is I can see the original file so I know that it is working but it also displays cipher text after the original file text. Does any one how to solve it?

 //some code to declare variables, read from file and so on 

  unsigned char * inputContent = (unsigned char *) malloc(fileSize * sizeof(char));     //create char array of same size as file content 

 //inputContent is for storing file data    

  string rawString(reinterpret_cast<char*>(inputContent), fileSize);        //convert char array to string

  //extract iv, key and cipher from rawString
  string rawIV;
  rawIV = rawString.substr(0, 32);

  //code to hexdecode iv

  string cipher;
  cipher = rawString.substr(32, fileSize - 32);

  string recovered;

  CBC_Mode< AES >::Decryption d;
  d.SetKeyWithIV(key, sizeof(key), iv);

  StringSource s_recover(cipher, true, 
      new StreamTransformationFilter(d,
                new StringSink(recovered)
            )
        );  

  const char * writeContent = recovered.c_str();

  if(pwrite(fd, writeContent, recovered.length(), 0) <= 0)
  {
      return -1;    //error
  }

Thanks in advance. ☺


Solution

  • You might try something like this. But its hard to say if it will actually work since its not clear what you are actually doing or where the problem lies.

    FileSource fs("<filename>", false /*pumpAll*/);    
    SecByteBlock key(AES::DEFAULT_KEYLENGTH), iv(AES::BLOCKSIZE);
    
    // Fetch key from somewhere
    key = ...;
    
    // Fetch IV from file
    fs.Detach(new HexDecoder(new ArraySink(iv, iv.size()));
    fs.Pump(32);
    
    CBC_Mode< AES >::Decryption dec;
    dec.SetKeyWithIV(key, key.size(), iv, iv.size());
    
    string recovered;
    fs.Detach(new HexDecoder(new StreamTransformationFilter(dec, new StringSink(recovered))));
    fs.PumpAll();
    

    You can also use the following if you get the SecByteBlockSink patch:

    SecByteBlock recovered;
    fs.Detach(new HexDecoder(new StreamTransformationFilter(dec, new SecByteBlockSink(recovered))));
    fs.PumpAll();
    

    rawString isn't needed below:

    //create char array of same size as file content 
    unsigned char * inputContent = (unsigned char *) malloc(fileSize * sizeof(char));     
    
    //inputContent is for storing file data    
    
    //convert char array to string
    string rawString(reinterpret_cast<char*>(inputContent), fileSize);
    

    Maybe you should try:

    ArraySource as(inputContent, fileSize, false /*pumpAll*/);
    

    Using the ArraySource means you don't make a copy of the data (the string copies the data), and its ready to go for Crypto++.

    Also, since you're already into C++ code, use an unique_ptr and new rather than malloc. The unique_ptr will handle cleanup for you. (Or, use a std::vector).

    unique_ptr<byte[]> buffer(new byte[fileSize]);
    

    I don't know how you are going to make a file descriptor work in the grand scheme of things. Crypto++ is a C++ library, and C++ uses I/O streams. Maybe this will help: How to construct a c++ fstream from a POSIX file descriptor?

    Also see Retrieving file descriptor from a std::fstream and Getting a FILE* from a std::fstream.