Search code examples
c++encryptioncryptographycrypto++

File not decrypting when program restarts, using the same encrypting key


I have a simple program that encrypts and decrypts text from input gotten from a text file. When I encrypt and decrypt in one cycle, I get the desired result, but if I encrypt, close application then re-run application, this time decrypt, the process fails.

The decryption snippet looks like this :

string decoded, plainText;
string fileData((istreambuf_iterator<char>(fileDecrypt)), (istreambuf_iterator<char>()));

ECB_Mode<AES>::Decryption decryption;
decryption.SetKey((byte*)key.c_str(), sizeof(key));
StringSource(fileData, true, new HexDecoder(new StringSink(decoded)));
StringSource(decoded, true, new StreamTransformationFilter(decryption, new StringSink(plainText)));

When I run debugger in VS2010, I get error on the last line

StringSource(decoded, true, new StreamTransformationFilter(decryption, new StringSink(plainText)));

When I wrap a try-catch block around decrypt function, I get this error

StreamTransformationFilter: invalid PKCS #7 block padding found

Not sure why it works if I encrypt and decrypt in one build, but fail if I try to decrypt without first encrypting first on the same run.


Solution

  • ECB_Mode<AES>::Decryption decryption;
    

    ECB mode operates on a full block size, and no padding is required.

    You can pad it, but it does not look like you are doing so. The caveat is the plain text must be a multiple of 16, which is AES's blocksize.


    When I wrap a try-catch block around decrypt function, I get this error

    StreamTransformationFilter: invalid PKCS #7 block padding found

    That's because you are padding it in:

    StreamTransformationFilter(decryption, new StringSink(...)).
    

    StreamTransformationFilter has a padding parameter. As you probably realize, it is BlockPaddingScheme::PKCS_PADDING


    Try:

    ECB_Mode<AES>::Decryption decryption;
    decryption.SetKey((byte*)key.data(), key.size());
    
    std::string plainText;
    StreamTransformationFilter filter(decryption, new StringSink(plainText),
                                      StreamTransformationFilter::NO_PADDING);
    
    FileSource fs(filename.c_str(), true, new HexDecoder(new Redirector(filter)));
    ...
    

    Other errata:

    ECB_Mode<AES>::Decryption decryption;
    decryption.SetKey((byte*)key.c_str(), sizeof(key));
    

    sizeof(key) is wrong. Use 16, 24, or 32. If the std::string is properly sized, then you can use key.size().

    And name you objects. I've seen GCC generate bad code with Crypto++:

    ECB_Mode<AES>::Decryption decryption;
    StringSource ss1(fileData, ...);
    StringSource ss2(decoded, ...);
    

    And a quick warning....

    ECB mode is usually wrong. I'm not saying it is in this case, or that you are wrong. But you might want to have a look at EAX mode, GCM mode or CCM mode. My apologies if this is more than it seems.

    Even better, use a scheme like Elliptic Curve Integrated Encryption Scheme (ECIES) or Discrete Logarithm Integrated Encryption Scheme (DLIES). The schemes are IND-CCA, which is a very strong notion of security.

    When using ECIES or DLIES, your problem reduces to sharing the public keys. But you have that problem now with the symmetric keys, so its a lateral move for key distribution, and a win for encryption.