4
$\begingroup$

I have a field in my data store which must take exactly 180 bits of information. Some users will choose to make this data encrypted, some won't, so some of those 180 bit fields will be ciphertext some will be plaintext. A boolean will indicate which one the user is using. The important thing here is that I need this field to be exactly 180 bits long.

However, a 128-bit cipher will mean I have to put in 256 bits in as plaintext, which is fine, just use a buffer string, but this means that the output is 256 bits when what is stored must be exactly 180 bits. And I can't simply cut off the ciphertext or that would mess up the decryption.

$\endgroup$
  • $\begingroup$ This question would probably be better suited for Cryptography. $\endgroup$ – Ilmari Karonen Oct 1 '15 at 18:43
  • $\begingroup$ @IlmariKaronen Cryptography is more specialized but this question is perfectly fine here too. $\endgroup$ – Gilles Oct 1 '15 at 18:49
  • $\begingroup$ Are those 160 bits the size of the plaintext or the ciphertext? Certain security properties can only be achieved if the ciphertext is longer than the plaintext. And is the flag indicating whether the field is encrypted one of those 160 bits? Or is it stored separately? What are your requirements for integrity of the data stored in this field? $\endgroup$ – kasperd Oct 2 '15 at 10:10
  • $\begingroup$ Originally it had been 160 bits rather than 180 bits. Any reason for the change? $\endgroup$ – Yuval Filmus Nov 9 '15 at 18:23
5
$\begingroup$

If you have a unique, unchanging identifier for each entry in your data store, you can use counter mode.

A nice thing about counter mode turns a block cipher into a stream cipher. No matter what the block size is, CTR mode encrypts an $n$-bit plaintext into an $n$-bit ciphertext.

In order to achieve that, CTR requires a unique counter value per block. Note: not just a unique counter value per message, but a unique counter value per block. The counter size is the same as the block size. In your case, you have messages that fit on two blocks, thus each message requires two counter values. If you have a unique identifier $k$ for each message, you can use $k$ and $k+1$ as the counter values for the two blocks (the second of which is partial) of the message.

Thus you need a 127-bit unique identifier for each message (128-bit block, minus one bit to distinguish the two blocks inside each message). The only security requirement for these 127 bits is that they are never reused for a given key. The initial counter value to encrypt a message is often chosen randomly, but this is not a requirement, just a convenience to ensure uniqueness. Of course, to decrypt the data, you need to be able to recover the unique identifier associated with each entry.

If your entries have some kind of unique identifier, which is often the case in databases, then you're set. Just remember that if you move data around or normalize it in a way that changes the identifiers, you will need to decrypt and reencrypt the data.

Some crypto libraries may present CTR mode through a function that randomly generates the initial counter value and prepends it to the message (so you'd input a 160-bit plaintext and get back a 288-bit ciphertext). Use a library that lets you specify the initial counter value (almost all implementations will increment the counter by 1 for each successive block, so pick initial counter values that are even, but you'll need to be aware of the endianness used by your library).

Keep in mind that encryption only gives you confidentiality, not integrity. In other words, someone who obtains the ciphertexts but not the key will not be able to find any information about the data; but if someone can inject fake ciphertexts or modify existing ciphertexts, the tampering cannot be detected. It is intrinsically impossible to detect tampering by cryptographic means in your scenario since there is no room for any redundancy.

$\endgroup$
4
$\begingroup$

One approach is to use what is known as format-preserving encryption. For instance, you could use VIL mode or FFX mode.

I recommend you spend some quality time on Cryptography.SE and with some research literature to learn more about these schemes. e.g.,

However, I do see two serious red flags with your scheme:

  • There is no salt/tweak. This means that all instances of the field will be encrypted the same way: if the same input repeats twice, you'll get the same output both times. This is usually a bad mode, as it makes your scheme equivalent to ECB mode, which is notoriously a bad idea. Instead, I recommend you use a tweakable FPE scheme, and set the tweak to be some identifier that is different for each row (e.g., a primary key, a row number, etc.).

  • None of these schemes provide any authentication/integrity. The lack of authentication/integrity is a red flag. In my experience, most schemes that use encryption without authentication/integrity are subject to a range of non-obvious attacks.

Due to these red flags, I recommend you talk to a professional cryptographer if security is important in your domain. You're in tricky waters.

$\endgroup$
  • $\begingroup$ I'm puzzled: assuming that a durable, unique identifier can be found, which is often the case in a database (but of course not guaranteed), what's wrong with CTR? $\endgroup$ – Gilles Oct 1 '15 at 18:49
  • 2
    $\begingroup$ @Gilles, CTR is not totally unreasonable, but CTR is more fragile in several respects. CTR makes the lack of authentication/integrity problems even worse. Its security properties are also worse if you ever change the value of the field without changing the identifier (e.g., encrypt one value, then later change it and encrypt the new value, and the new value gets the same identifier since it's in the same row); then the xor of the ciphertexts reveals the xor of the corresponding plaintexts. $\endgroup$ – D.W. Oct 1 '15 at 18:53
1
$\begingroup$

The simplest solution is the following encryption procedure:

Encrypt the first 128 bits.

Encrypt the last 128 bits.

Decryption works the other way around:

Decrypt the last 128 bits.

Decrypt the first 128 bits.

Performance is $256/160 = 1.6$ times slower than AES. It's best to use two different keys for the two steps.

There is a slight problem with this procedure regarding data integrity: if the first 32 bits of the ciphertext are modified, then the last 32 bits of the resulting plaintext will stay the same. If this worries you, add an extra step:

Encrypt the first 128 bits.

Encrypt the last 128 bits.

Encrypt the first 128 bits.

Performance drops to $384/160 = 2.4$ times slower than AES. Again, it's best to use three different keys.

$\endgroup$
  • 1
    $\begingroup$ Your second scheme is reasonable, though it doesn't achieve quite as much as some standard schemes: It is not a secure pseudorandom permutation (SPRP), which is probably what cryptographers would use as their definition of security. I suspect a fourth round would take care of that, though I don't have any proof of that fact. That said, I doubt this will be a serious issue in practice. Separately: In general, like other unmodified FPE schemes, this scheme suffers from the two limitations in my answer: use of ECB mode, and lack of data integrity/authentication. Those could be more serious. $\endgroup$ – D.W. Oct 1 '15 at 18:19
  • $\begingroup$ The OP also comments that four rounds are better, though without explanation. $\endgroup$ – Yuval Filmus Nov 9 '15 at 18:24

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.