I have some fields, similar to NAME, SURNAME, EMAIL, ADDRESS... I'm using NaCl for symmetric encryption. Is bad If I Encrypt every field with the same key and nonce? They are encrypted and stored separately. Thanks for help
-
$\begingroup$ Is those field of some database table? If so, you will enable Frequency attack on the columns $\endgroup$ – kelalaka Oct 15 '19 at 16:50
I will assume you're asking about NaCl crypto_secretbox, although the same considerations apply everywhere ‘nonce’ appears in the NaCl API.
Is it bad if I encrypt every field with the same key and nonce?
Yes, it is very bad. If you reuse a key/nonce pair for two different messages, you violate the security contract of NaCl. It is so bad that an adversary who knows the plaintext/ciphertext of one field can decrypt all the other fields, and forge arbitrarily many more fields.
Here are a couple of things you can do instead:
If you never modify a field, and you can uniquely name each field—e.g., name each field by (table name, column name, rowid), as long as you never reuse a rowid—then you could derive a key by a pseudorandom function of the field name: Given a master key $k$ and a field name $f$, use $k_f = \operatorname{HMAC-SHA256}_k(f)$ as the key to encrypt the field, with an all-zero nonce.
However, if you ever modify a field, even this is no good in case an adversary ever sees two versions of the same field, which would again violate the security contract. If you additionally have a version number so that (table name, column name, rowid, version) is unique, you could use that instead (or use the version number as the nonce).
If you are willing to allow an adversary to see when a field value is repeated in multiple places or at multiple times, you can use a deterministic authenticated cipher. NaCl doesn't have one built-in, but here's a relatively simple one you can make out of parts available in NaCl, which is designed to make a security reduction theorem easy to prove:
Parameters: 512-bit master key $(k_1, k_2)$, field name $f$ encoded so that no field name is a prefix of another field name.
(The field name need not be unique, but if you repeat a field name then the adversary will be able to tell when the field value is repeated. Typical prefix-free encodings might be either (a) making sure every field name is exactly the same length, or (b) NUL-terminated field names if field names can't have embedded NULs, or (c) length-delimited field names with a prefix-free encoding of the field name's length followed by the field name.)
To store a field value $m$:
- Compute the authentication tag $t = \operatorname{HMAC-SHA256/192}_{k_1}(f \mathbin\| m)$. Here HMAC-SHA256/192 is first 192 bits of HMAC-SHA256. (You can compute HMAC-SHA256 with
crypto_auth_hmacsha256
in NaCl.) - Compute the unauthenticated ciphertext $c = \operatorname{XSalsa20}_{k_2}(t) \oplus m$, using $t$ as the nonce for XSalsa20. (You can compute XSalsa20 encryption with
crypto_stream_xsalsa20_xor
.) - Store the concatenation $t \mathbin\| c$.
- Compute the authentication tag $t = \operatorname{HMAC-SHA256/192}_{k_1}(f \mathbin\| m)$. Here HMAC-SHA256/192 is first 192 bits of HMAC-SHA256. (You can compute HMAC-SHA256 with
To load an encrypted field value $\hat t \mathbin\| \hat c$ (which may or may not be the same as what you previously stored, $t \mathbin\| c$):
- Compute the putative plaintext $\hat m = \operatorname{XSalsa20}_{k_2}(\hat t) \oplus \hat c$. (The forward and backward directions of XSalsa20 encryption are the same, so also use
crypto_stream_xsalsa20_xor
here.) - Check whether $\hat t \stackrel?= \operatorname{HMAC-SHA256/192}_{k_1}(f \mathbin\| \hat m)$; if not, immediately erase $\hat m$ and either drop the field on the floor or raise an alarm. (Make sure to do this check in constant time. NaCl provides
crypto_verify_16
andcrypto_verify_32
for constant-time comparison; you can usecrypto_verify_32
for this if you just zero-pad the 24-byte tags up to 32 bytes.) - Otherwise, if verification succeeded, return $\hat m$ as the value of the field.
- Compute the putative plaintext $\hat m = \operatorname{XSalsa20}_{k_2}(\hat t) \oplus \hat c$. (The forward and backward directions of XSalsa20 encryption are the same, so also use
There are other deterministic authenticated ciphers on the market too, like AES-SIV and AES-GCM-SIV, but they have much smaller safe data volume limits than the one I just described, and they essentially require hardware support to avoid timing side channel attacks.