I am serialising JSON objects, and would like to encrypt some of the values. I plan to do this with AES-GCM.

I would also like to ensure the integrity of the overall object.

The requirements are for integrity of the overall object, confidentiality for some of the values, plus a requirement for plaintext for other values.

There are a small number of known top-level keys.

For example, if my "plaintext" JSON object were

{
    "id":"823623672",
    "address": {
        "line1": "2000 Broadway",
        "line2": "New York",
        "zip": "12345"
    },
    "telephone": "+1 212 555 1234",
    "last-accessed": 1543946340
}

I would like an "encrypted" object to be something like

{
    "id":"823623672",
    "address": "URAVvDTOrovXBehz2ms8ej9BRCaKdx8LsmuA81IkESM=",
    "telephone": "0gAtx7Hh/kPD7chfNGy90A==",
    "last-accessed": 1543946340
}

Now, I can easily serialise the address and telephone and encrypt them, and provide the values of id and last-accessed as the associated data.

However, the actual objects I will be using will have quite a bit more data in the "do not encrypt" keys.

So instead of using the values of id and last-accessed as the associated data directly, I would like to hash these values and use the hash as the associated data. (Probably SHA-512/256, if it matters.)

To decrypt, I will re-create the associated data (hash) from the input data, then decrypt each of the encrypted keys; if any of the decryptions fail then the overall decryption fails.

(And using the hash means I can create the associated data using hash "updates" with the values of the known keys one after the other, rather than having to create a single contiguous data item with the values all concatenated. In this instance I would be hashing 823623672 then '\0' then 1543946340 then '\0'; the separators are to ensure an attacker couldn't change the id to "82362367" and the last-accessed to 21543946340, for example.)

(I do not have to worry about an attacker adding additional top-level keys; the ones that have semantic importance will be in the associated data/hash.)

It seems to me that using the hash should not weaken the security of the encryption, but I'd like to check.

Is using a hash rather than the full data going to weaken the security of the encryption?

New contributor
user239146146 is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
  • This seems overly complex; why not just encrypt and authenticate the enitre object? Presumably the client and server already share the encyption key; AES-GCM is very fast on modern hardware. Your piecemeal parsing+hashing scheme will likely be much more expensive (and fraught with peril due to logic bugs) than just encrypting the whole object. Complexity is the enemy of security. – rmalayter Dec 5 at 0:00
  • 1
    We very specifically want parts of the JSON objects to be in plaintext, but authenticated – user239146146 Dec 5 at 0:34
  • Why? What is the use case? If you explain the application you’re going to get better assistance. What you want to do seems inadvisable from a security (and code maintenance) perspective. If this is a JWT browser auth token just don’t. Google will tell you why. – rmalayter Dec 5 at 3:25
up vote 4 down vote accepted

If I understood you correctly, you will hash everything you need to authenticate and include that in the AAD. This will be secure, as long as the hash is a secure collision resistant hash function. However, I don't understand what you gain. You can compute on all of this data in the AAD but only send what is necessary for reconstructing it. In this way, you don't have to store/send anything more than needed. In addition, the GCM authenticator is actually much faster than SHA256/SHA512, so it will also be more efficient.

  • If I don't hash, I have to prepare a single data item for the authenticated data (and I am processing a JSON string passed to me). If it's safe to hash, I can just use the hash "update" function with each of the authenticate-only JSON values in turn. I had thought the hashing would also be faster when there are multiple encryptions; I didn't realise the Galois authenticator was faster than SHA512/256 - thanks! – user239146146 Dec 4 at 18:46
  • Accepting this answer as it directly addresses my specific question "will it be as secure to use the has rather than the full data". I was concerned about this because I know that in some cases combining operations (e.g. CBC mode encryption with CMAC with the same key) can compromise security. It should have been obvious to me that a hash (keyless) isn't going to have the same problem, as long as it is cryptographically secure. – user239146146 Dec 6 at 8:16

In theory, hashing the data before passing it in as AAD doesn't gain you anything. You do mention a practical consideration (my boldface):

And using the hash means I can create the associated data using hash "updates" with the values of the known keys one after the other, rather than having to create a single contiguous data item with the values all concatenated. In this instance I would be hashing 823623672 then '\0' then 1543946340 then '\0'; the separators are to ensure an attacker couldn't change the id to "82362367" and the last-accessed to 21543946340, for example.

From this I can guess that your AEAD implementation takes the AAD input all at once as a byte array, but your hash function implementation takes it as incremental chunks. That's an implementation limitation of the former, though, not an essential property of AEADs.

The advice I'd give is to beware needless optimization. Hash function implementations offer incremental interfaces because they're often used to hash really ginormous inputs, but it doesn't sound like the AAD values you're contemplating here will be very small, seen in big-picture terms. Maybe you should just swallow the bullet and concatenate the AAD values.

  • Yes, that is exactly the issue, and I see your point about premature optimisation. – user239146146 Dec 6 at 8:12

Your Answer

user239146146 is a new contributor. Be nice, and check out our Code of Conduct.

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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