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.


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

  • Does the TripleDES class support CTS? You'll get roughly equivalent security from it.
    – Polynomial
    Oct 30, 2012 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, 2012 at 16:41
  • You could cheat by just padding the original file to give yourself some working room... Oct 31, 2012 at 9: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 8, 2014 at 21:09

3 Answers 3


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

  • 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, 2012 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. Oct 30, 2012 at 20:51
  • There are modes which are decently secure(obviously no semantic security) and don't increase the size of the ciphertext. Oct 31, 2012 at 10:23

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.

  • 1
    Using the time is tricky: it relies on that piece of metadata being kept intact. In the situation presented here there may not even be a path and file name, but there may be some other unique value that ensures that no two encryptions use the same (IV, key) combination. Oct 30, 2012 at 21:25
  • Keep in mind the IV must sometimes be unpredictable in addition to being unique.
    – Thomas
    Oct 31, 2012 at 10:23
  • @Thomas - which is why I wrote the two conditions above. I'll edit the post to clarify this point. Oct 31, 2012 at 17:34
  • @Thomas - is this clearer now? Oct 31, 2012 at 17:40
  • Yes, with the edit it's now clearer.
    – Thomas
    Oct 31, 2012 at 22:28

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.

  • 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. Oct 30, 2012 at 16:52
  • TripleDES doesn't support CTS in the .NET framework
    – Fabio
    Oct 30, 2012 at 22:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .