I'm trying to understand cryptosystems and their implementations to understand how to properly implement them. I have a function implementing AES-128 in OFB mode. Let's call it

encrypt(plainText, key, iv)

and assume everything else is properly implemented within the function.

Assume I'm going to encrypt 3 messages: 'a', 'b', and 'a' again, using the same key, k. The outputs are not realistic, I'm just trying to show that this function outputs the same character for the same message, with the same IV.

encrypt('a', k, 1) // outputs 'j'
encrypt('b', k, 2) // outputs 'f'
encrypt('a', k 1) // outputs 'j'

The question is: is my choice of IV for the 1st and 3rd invocation insecure? I've been told to make sure that the IV is unique, but how so? If the same message is supplied, should the IV be unique to that message, or globally unique?

I say it is insecure because I should never get the same ciphertext for the same message, but I do not know how to prove this. Furthermore, I do not know how to generate OR store a properly generated IV for each message.

If anything, I think the proper way to do this would be like so:

encryptWrapper(plainText, key):
    iv = // get some random bytes from /dev/urandom
    cipherText = encrypt(plainText, key, iv)
    //store the IV and the ciphertext in the same database table

So that my decrypt function would look like this:

decrypt(databaseIndex, key)
    //the databaseIndex is used to retrieve the ciphertext and its corresponding IV

Is it safe to store the IV with the ciphertext?


1 Answer 1


For each message position or role, such as a different time in a conversation or a different field in a database, you must use a distinct nonce, sometimes also called IV.

It doesn't matter what the content of the message is: in your database, you might store the same record content in two different places, in which case if you use the same nonce an adversary can tell that the two places contain the same content. Worse, if you use the same nonce for two different places and two different message contents, an adversary can learn something about both messages or use information about one of them to learn information about another.

Your obligations in the AES-OFB security contract are simple:

  1. You must pick the key $k$ uniformly at random and keep it secret.
  2. For each distinct message position that you encrypt with the same key $k$, and each time if you can reuse message positions, you must use a distinct nonce.

Both the sender and recipient must share $k$ and, for each message position, the nonce in that position. You can make the nonce for each message position public and transmit it alongside the ciphertext, or you can make it a function of where the message is, such as a message sequence number in a conversation or a record number in a database. Note that if you ever reuse a message position, e.g. by overwriting a field in a database, then the nonce must also change from the first time you use it to the second time you use it; otherwise an adversary with two snapshots of the database can learn information about the old message and the new message from the two ciphertexts.

In exchange, AES-OFB guarantees that for up to a terabyte of data (240 bytes) under a single key, an adversary with read-only access to your database won't learn anything about the content of what you have encrypted, with the adversary's distinguishing advantage bounded by about $2^{-64}$.

Out of scope:

  • an adversary with write access to your database;
  • an adversary impersonating the database on the network;
  • concealing access patterns of your database;
  • concealing the lengths of the messages in your database;
  • etc.

If write access might ever be relevant—and it often can be in ways you didn't think of—then you must also use authenticated encryption: for example, AES-GCM, or NaCl crypto_secretbox_xsalsa20poly1305. If you're not sure, err on the side of using authenticated encryption.

If access patterns and message lengths must be concealed, you have to think carefully about how to engineer your application. Beware that compression makes the message lengths a function of the message content, which can cause lengths to reveal information about content!

In the special case where it is safe for an adversary to learn when two distinct message places hold the same message content, you can use a nonce-misuse-resistant authenticated encryption scheme such as AES-SIV or AES-GCM-SIV, which is usually constructed out of a nonce-based authenticated encryption like AES-GCM with the internal nonce chosen to be a pseudorandom function of the message and the caller-specified nonce, at the cost of some performance.

But although the concept has been formalized for some time, nonce-misuse-resistant authenticated encryption schemes are not widespread yet, and the CAESAR competition muddied the waters by not making NMR AEAD a distinct goal from AEAD, and the IETF barged ahead with adopting AES-GCM-SIV, and it's a bit of a mess. Sorry! In any case, it's safer if you can uniquely label all your message positions by a short string of bits (96 bits for AES-GCM, 192 bits for crypto_secretbox_xsalsa20poly1305) and never worry about it again.

  • 1
    $\begingroup$ "Note that if you ever reuse a message position, e.g. by overwriting a field in a database, then the nonce must also change from the first time you use it to the second time you use it" exactly what I was looking for, thank you! $\endgroup$
    – appills
    Mar 15, 2018 at 21:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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