10

I'm using .NET and I've written an awesome routine (xD) that encrypts and decrypts a file using AES256 CBC. It works perfectly, but now they told me that the encrypted file must be of the same size of the decrypted one. (There is a problem with some other API's, not my fault, I swear.)

So, I've tried everything that I can find, but nothing works. The .NET Framework has a CipherMode.CTS that looks exactly like what I need, but unfortunately it is not currently supported.

I tried to set the padding to none, but of course I've got errors because the block size is less than what it's supposed to be.

Ideas?

Edit: I've managed to solve this problem in 2 ways:


With .NET API SymmetricAlgorithm alg = new RijndaelManaged(); alg.Mode = CipherMode.CFB; alg.Padding = PaddingMode.None; alg.FeedbackSize = 8;


With BouncyCastle API's IBufferedCipher cipher = new CtsBlockCipher(new CbcBlockCipher(new AesFastEngine()));

Hope this can help others with the same problem :)

Fabio
  • 153
  • 1
  • 7
  • Does the TripleDES class support CTS? You'll get roughly equivalent security from it. – Polynomial Oct 30 '12 at 16:38
  • Nope, the thing is that they've added the CTS mode for a future use, but no algorithm implements it yet. – Fabio Oct 30 '12 at 16:41
  • You could cheat by just padding the original file to give yourself some working room... – Inverted Llama Oct 31 '12 at 09:47
  • If no file will be smaller than 16 bytes, a workable approach is to encrypt all complete 16-byte blocks, and then encrypt the last 16 bytes of the file (which will overlap the last encrypted block). This won't require any extra storage, but won't work at all for encrypting files smaller than 16 bytes. – supercat Dec 08 '14 at 21:09

3 Answers3

11

Even if you use CTS, you still need an initialization vector (IV) which MUST (I insist, MUST) be generated anew for each file with a cryptographically strong pseudo-random number generator. So you will not be able to fit all of it without increasing the size. This is unavoidable, as long as you use a "normal" block cipher.

Also, if you need encryption, then you most probably need integrity, i.e. a MAC, which, intrinsically, requires a bit of extra space.

What you could try is to compress the file before encrypting it (System.IO.Compression.DeflateStream); this could give you the extra breathing space you need (not in a guaranteed way, but it will work, especially if the file you need to encrypt is an XML file or something like that, with a lot of structure).

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
  • 1
    Just to emphasize Thomas saying you need integrity: If I am a man-in-the-middle and know you probably sent the message `!JUNK!Please send $500 to Joe Smith!JUNK!`, I may be able to change it to `!JUNK!Please send $600 to Joe Smith!JUNK!` Encryption w/o integrity prevents someone from knowing what was said, but does not protect you from someone changing what was said. *Some* of your message is probably predictable, so this is pretty dangerous. – Brian Oct 30 '12 at 17:10
  • 1
    Worse, with things like CBC padding oracle attacks, an attacker can often decrypt entire messages if the decryption step isn't guarded by authentication of the ciphertext. – Stephen Touset Oct 30 '12 at 20:51
  • Related: [Lessons learned in cryptography and encryption](http://security.stackexchange.com/a/2206/396) – makerofthings7 Oct 30 '12 at 23:35
  • There are modes which are decently secure(obviously no semantic security) and don't increase the size of the ciphertext. – CodesInChaos Oct 31 '12 at 10:23
5

As Thomas wrote, to securely encrypt the file you must have an IV in addition to the encrypted file. For an IV to be secure it needs to meet two conditions:

  1. The same IV and key pair isn't used for two different messages.
  2. An attacker can't predict the IV used for a message of his choice encrypted with the same key as a message the attacker wants to decrypt.

These two conditions are generally met by using a different random IV per message, which in your case would require adding the IV to the encrypted file thus increasing the file size. But if certain conditions are true you can use the file properties (path, name, date and time) as the IV (so as not to need to add the IV to the encrypted file). The conditions are:

  1. The encryption key is unique per machine. This ensures that the same IV is never used with the same encryption key since you can't have two files on the same machine with the same file properties.
  2. The encryption key is unique per user.This ensures that an attacker cannot mount a chosen plaintext attack to decrypt other user's files since the keys are different.

If these two conditions are met you can use a stream cipher mode of operation (e.g. CTR, OFB, CFB) and use the file properties as the IV.

David Wachtfogel
  • 5,512
  • 21
  • 35
2

There are a few options:

  1. See if TripleDESCryptoServiceProvider supports CTS.
  2. Turn CBC-mode AES into a stream cipher.

For the latter, simply encrypt blocks of zeros and xor your plaintext with the resulting cipherstream:

// work out what the padding length needs to be
int paddingSize = cipher.BlockSize - (message.Length % cipher.BlockSize);
int paddedSize = message.Length + paddingSize;

// build a block of zeros
byte[] zeros = new byte[paddedSize];

// create a keystream from the key and IV, using the zeros as a plaintext
byte[] keystream = EncryptAES(zeros, key, iv);

// produce the ciphertext by xoring the plaintext and the keystream
byte[] ciphertext = new byte[message.Length];
for (int i = 0; i < message.Length; i++)
    ciphertext[i] = message[i] ^ keystream[i];

This works as both the encryption and decryption algorithm - just feed the ciphertext back through with the same key and IV, and you'll get the original plaintext. But, as Thomas Pornin points out, you'll still need to send a unique IV with each message.

Polynomial
  • 132,208
  • 43
  • 298
  • 379
  • 2
    Actually that's a homemade way to implement OFB (Output Feedback Mode), which might be supported intrinsically. CFB and CTR are also padding-less modes. But the IV must still be stored "somewhere", and the lack of verified integrity is probably an issue. – Thomas Pornin Oct 30 '12 at 16:52
  • TripleDES doesn't support CTS in the .NET framework – Fabio Oct 30 '12 at 22:19