I have clear text, usually less than 10 bytes, which contains a few infrequently changing bytes.

Reading: http://lollyrock.com/articles/nodejs-encryption/ I tried aes-256-ctr:

  • The cipher text is as short as the clear text, which is good.
  • The cipher text contains patterns, at the positions of the infrequently changing bytes, which is bad.

I tried aes-256-cbc:

  • The cipher text length is rounded up to the nearest 16 bytes, which is bad.
  • The cipher text appears random, which is good.

Is there a form of AES encryption where the cipher text matches the length of the clear text and does not show patterns?

  • 5
    $\begingroup$ I strongly recommend sacrificing a few bytes to store an IV/nonce and ideally a MAC. Format preserving encryption is complex, slow and inherently weaker than normal encryption. $\endgroup$ – CodesInChaos Mar 2 '17 at 14:15
  • $\begingroup$ Sometimes it is possible to compress the amount of input as well. 10 bytes sounds like a lot, but it could still have quite a bit of redundancy. For an indication on how far you can go with this, take a look at PER encoding. $\endgroup$ – Maarten Bodewes Mar 2 '17 at 14:25

What you want is length-preserving encryption, which is a special case of Format-preserving encryption.

A standard mode for achieving this FFX mode, which uses a blockcipher, like AES, in a Feistel network. This mode is relatively complex and slow.

But I strongly recommend using normal authenticated encryption over format preserving encryption whenever possible. Format-preserving encryption always leaks if two plaintexts are identical, whereas semantically secure encryption avoids this leak. It also lacks integrity protection, unlike authenticated encryption.

| improve this answer | |

If you look at the definition of counter mode, you will see that it actually turns the blockcipher into a stream cipher:

  • The keystream is independent of the message.
  • The ciphertext is just XOR of the keystream and the plaintext.

So if you just flip a single bit in the message, you just flip a single bit in the ciphertext if the keystream is the same - I guess that's what you call the patterns in the changing bytes?

However, this indicates wrong usage of counter mode: There is a nonce in CTR, basically it is the starting value of the counter (padded with 0 at the end). And it should never be the same for several messages. The concatenation of the nonce and the counter is the input to the block cipher, and 128 bits (AES) are more than enough that you never have to reuse either (e.g. 96 bit nonce and 32 bit counter, or both with 64 bit).

With a proper nonce, you should get an entirely different keystream for every message, and (under the assumption that a block cipher acts like a pseudo-random permutation, which is the theoretical model for a secure blockcipher) should not be able to distinguish different messages or in fact a ciphertext from a truly random number.

If you don't want to store the nonce (it is the equivalent of an IV in other modes), you could use a message-counter instead: A nonce does not have to be random, it just needs to be unique (never reused - even after restarting the whole process / program).

| improve this answer | |
  • $\begingroup$ Note that AES has a 128-bit block size (regardless of the key size), so the nonce + counter for AES-CTR can be at most 128 bits long in total. A reasonably common choice seems to be to divide it into a 96-bit nonce and a 32-bit block counter, but e.g. 64 + 64 bits would also be possible. $\endgroup$ – Ilmari Karonen Mar 2 '17 at 16:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.