# which en/decrypt algorithm should use for small byte array that result have same length

I wanted to use Rijndael for encrypting big array of bytes, as you know this algorithm will add up to 15 byte to result (if you use block with length equal to 16). It is acceptable in most cases but in this case I can not afford such a thing (result length should be same as given length). So I think about using this algorithm for encryption but for a few remaining bytes use another algorithm. Which algorithm is proper for this conditions:

1. data can be small byte array with length less than 16.

2. result have same length as input array

3. be reserve able (decryption)(it is not password)

4. be safe enough (not out of date)

It also will be great if this algorithm work with small key (I prefer do not use all password/iv for this part).

(I use C#)

• Just a curio; why is an additional 15 bytes a problem if you have a machine capable of executing bloatware like C# ? Commented Apr 13, 2017 at 0:53
• You realise that it's not really really safe to encrypt 15 bytes or less into 15 bytes? SHA1 has been (kinda) broken with a length of 20 bytes. Less bytes would be easier, right down to 1 byte with just 256 brute force attempts. Commented Apr 13, 2017 at 0:57
• Would an extra 12 bytes be acceptable? How many total arrays would be encrypted with the same key? Commented Apr 13, 2017 at 1:05

result have same length as input array

If you insist on this, then you must lose some security.

• At the very least, there's no room for a given value to be encrypted in two different ways. This means that an attacker can at least tell whether two encrypted values are the same, because the encrypted values will be the same if the ciphertexts are the same.
• You think that's not really a problem? But consider that in many scenarios, it means that an attacker can make guesses. They guess that the value is AB, arrange for you to encrypt AB and compare the ciphertexts. Repeat for AC, AD, etc. It isn't too bad if the attackers cannot submit plaintext, but that's rare. Most databases containing encrypted data contain some user-supplied input (e.g. names).
• It's worse than that: usually, if two values start with the same prefix then their ciphertext will also start with the same prefix (except for the last few characters of the common prefix, depending on the mode). This is because most encryption modes proceed in a single pass, so they encrypt the first few bytes, then the next block and so on. If the first block of plaintext is identical and the ciphertext is the same size as the plaintext then the ciphertext for the first block will be equal if the plaintexts are equal.
• Additionally, if the ciphertext is the same size as the plaintext then you may ensure some confidentiality of the data, but you won't be able to guarantee its integrity. There's no way to detect that the data has been modified without adding some redundancy information, and that redundancy information has to go somewhere.

Encryption modes solve this problem by including a unique value at the beginning of each ciphertext, called an IV¹. That's the reason why any sensible encryption mode results in ciphertext that's a little larger.

A second reason why the ciphertext is larger is padding, for modes that work on whole blocks at a time. This an be avoided by using a mode that doesn't have padding. Your library should offer CTR mode, which is fine if used correctly.

For CTR mode, like any other mode, you need a unique IV for each value that's encrypted. For CTR mode, you actually need a bit more than that: the counter value must be unique for each block. The counter value doesn't have to be random, although that's a popular choice, so it's ok to construct the counter value from the array index. If each value is at most $16 \times 2^n$ bytes long then you can use $2^n \times k$ as the IV for block $k$. (Note that the IV is a 16-byte string; be careful not to use a smaller type like 32-bit integers where you risk wraparound in arithmetic operations.)

Do note that this is only safe if the attacker sees a single version of the database. If the attacker sees multiple versions then they will see changed contents in some blocks that are encrypted with the same IV. This gives the attacker some information about the content of the block, possibly revealing both the old value and the new value depending on what partial information the attacker has on the values (data format, content of some guessable fields, …).

The simple option is to accept that storage is cheaper than security breaches, and use a high-level crypto API that doesn't require you to understand all the details.

A few more remarks…

Rijndael

The modern name is AES. It's perfectly fine: it's the standard symmetric algorithm these days. “AES” only tells part of the story: it only says how to transform a 16-byte block of plaintext into a 16-byte block of ciphertext. To specify the algorithm, you also need to specify the mode which explains how to assemble the blocks together. Two popular modes for encryption only are CTR and CBC. (Some libraries provide a mode called ECB; never use it: this isn't a proper encryption mode, it's a building block for when you want to use a mode that isn't provided by the library.)

this algorithm will add up to 15 byte to result (if you use block with length equal to 16)

No, actually the algorithm will add 16 bytes at the beginning for the IV. It may additionally pad the last block (CBC does, CTR doesn't).

I can not afford such a thing (result length should be same as given length)

Scenarios where a few bytes are not possible are extremely rare. Think again.

If you really really really can't do the simple thing and use a proper mode with a proper IV, then I urge you to have someone competent review the code. I'm sorry to say, but if you needed to ask this question then the chances that you'll get it right are small, even after reading a few Stack Overflow and Stack Exchange posts.

¹ “IV” isn't the technically correct term for some modes, but it'll do.