Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider adding tag size of 4 and 8 to AES GCM #541

Open
d3lm opened this issue Jul 17, 2023 · 27 comments
Open

Consider adding tag size of 4 and 8 to AES GCM #541

d3lm opened this issue Jul 17, 2023 · 27 comments

Comments

@d3lm
Copy link

d3lm commented Jul 17, 2023

I have noticed that AesGcm only accepts tag sizes >= 12 and <= 16. However, Node.js for example also allows tag sizes of 4 and 8 (see here). Could we implement SealedTagSize for consts::U4 and consts::U8 as well?

@tarcieri
Copy link
Member

NIST SP 800-38D Appendix C provides guidelines for the use of short tags, noting the following potential attack up front:

Absent the requirements and guidelines in this appendix, it may be practical for the attack to produce the hash subkey, H, after which the authentication assurance is completely lost.

While we could potentially support them, using them securely comes with a whole host of caveats described in that section which makes their usage fall into more of a "hazmat" category which requires short lived, frequently-rotated keys with bounds on how many times they can safely be used for decryption without being vulnerable to a targeted forgery attack:

For any implementation that supports 32-bit or 64-bit tags, one of the rows in Table 1 or Table 2,
respectively, shall be enforced. In particular, the supported lengths for the plaintext/ciphertext
and the AAD shall ensure that every valid packet satisfies the length restriction in the row, and
the controlling protocol/system shall ensure that the key is changed before the authenticated
decryption function is invoked more than the maximum that is given in the row. A smaller
maximum may also be enforced.

@d3lm
Copy link
Author

d3lm commented Jul 17, 2023

Oh ok, I wasn't actually aware of that - thanks for pointing that out. I guess it'd be more effort than to support short tags. It might be ok for us to restrict the tag size and ignore short tags. I also don't know if there's applications that really use short tags and it's just something I noticed while I was implementing AES-GCM that complies to Node.js using aes_gcm.

@tarcieri
Copy link
Member

It sounds like they are buffering and perhaps incrementally encrypting/authenticating the data.

We only have one-shot APIs at the moment, though you could largely achieve the same effect by buffering the data into a Vec<u8> and then encrypting it with the one-shot API.

@d3lm
Copy link
Author

d3lm commented Jul 19, 2023

Yes, that's what I am doing for encryption and it works, but I have issues with incrementally decrypt data. Because parts of the encrypted data will throw an aead::Error likely because the tag isn't correct and corresponds to the tag for the entire data. Any idea what I can do?

@tarcieri
Copy link
Member

It's not possible to safely decrypt individual AEAD messages incrementally. At the very least, the tag needs to be checked before decryption can begin.

@d3lm
Copy link
Author

d3lm commented Jul 19, 2023

I wonder how Node.js does that then 🤔

@tarcieri
Copy link
Member

My guess would be: unsafely

@d3lm
Copy link
Author

d3lm commented Jul 19, 2023

Oh my, I just realized, with every call to update(<partial_aead_message>) they don't even check the tag only once you call final and have all the "chunks".

@d3lm
Copy link
Author

d3lm commented Jul 19, 2023

But that is prolly not a good idea is it?

@d3lm
Copy link
Author

d3lm commented Jul 19, 2023

Hm I guess maybe it is because only after calling final() the entire decryption process is finished and I would expect that you can not expect it to be fully checked before calling final().

@tarcieri
Copy link
Member

Operating on unauthenticated data can be a source of chosen ciphertext attacks which completely undermine AEAD security.

These sorts of streaming decryption APIs are "hazmat" which is difficult to use correctly with high misuse potential.

@d3lm
Copy link
Author

d3lm commented Jul 19, 2023

Thanks a lot for your input on this 🙏 I am not a crypto expert myself so appreciate it.

@d3lm
Copy link
Author

d3lm commented Jul 19, 2023

Maybe you can still consider adding short tags, that would be really nice. But for now it's fine and I can work around it and only support 128 bit tags.

@tarcieri
Copy link
Member

We could add an API for it, but it would require a special decryptor object which caps the max message size and number of decryptions allowed under a given key

@d3lm
Copy link
Author

d3lm commented Jul 19, 2023

I think that sounds reasonable as long as those numbers are decently high or maybe configurable?

@d3lm
Copy link
Author

d3lm commented Jul 19, 2023

I think generally I am fighting a bit the fact that the nonce length and tag length are both configured "statically" and I can't pass them as arguments dynamically.

@tarcieri
Copy link
Member

Do you have a particular use case for dynamic tag lengths which isn't limited to a small number of possibilities?

@d3lm
Copy link
Author

d3lm commented Jul 20, 2023

I think it's just the ability to pass in the tag length from the passed u8 slice for the tag instead of statically defining the tag length via a type.

@tarcieri
Copy link
Member

That wasn’t what I was asking. What is the use case for dynamic tag sizes? What are you doing that demands them?

@d3lm
Copy link
Author

d3lm commented Jul 21, 2023

The use case is that I can create the "handle" so AesGcm::<Aes, NonceLength, TagSize>::new_from_slice(key) once and not every time I encrypt partial data which is what I need to implement the same interface as Node.js. I suppose creating the handle is not expensive so it should be somewhat fine? It'd be really nice if it was possible to do

AesGcm::<Aes, NonceLength, TagSize>::new_from_slice(key, nonce_size, tag_size)

instead of passing the sizes as types. Curious to hear your thoughts because right now I have a match for the tag size but for nonce sizes it's a bit unfortunate because I'd have to define every size and then pass the right type, so

match nonce.len() {
  1 => AesGcm::<Aes, aes::cipher::consts::U1, TagSize>::new_from_slice(key)
  2 => ...
  ...
}

@tarcieri
Copy link
Member

Sorry, that's not what I'm asking. Why are you working with arbitrary tag sizes in the first place? Who is choosing them? Why are they arbitrary? Why aren't they some fixed, low-cardinality set as specified by a protocol you're implementing?

@d3lm
Copy link
Author

d3lm commented Jul 21, 2023

The user is choosing the tag size. In Node.js you can do:

const cipher = crypto.createCipheriv('aes-128-gcm', key, iv, { authTagLength: 4 });

So when the cipher object is created they can pass in the auth tag size. By default it's 16. Node allows 4, 8, and 12 - 16 byte auth tags.

@tarcieri
Copy link
Member

I'm afraid that still doesn't answer my question.

I am asking for specific examples of scenarios where being able to dynamically select the IV size using a runtime parameter would be helpful.

You gave a code example which uses a constant literal. That's not only not an example of a use case/scenario, but also an example of the sort which is very much amenable to being a compile time constant.

@d3lm
Copy link
Author

d3lm commented Jul 21, 2023

Hm I am not sure I understand. It's a constant literal in the user's code, but in our runtime we don't know those values upfront and we run arbitrary code that can use any IV length or different tag sizes.

@tarcieri
Copy link
Member

So your use case is you're implementing a Node.js interpreter and need to support this kind of dynamic selection?

If so, please file a new issue specific to that request.

@d3lm
Copy link
Author

d3lm commented Jul 21, 2023

Yea exactly. We are building a Node.js runtime for the browser so you can run Node.js entirely in your browser without relying on cloud servers. Should have said that in the beginning, sorry about that. Will file a new issue for that.

@mouse07410
Copy link

One example of where variable tag size may help is a noisy link, where you adjust the tag size based on the available practical bandwidth and the point in the protocol flow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants
@tarcieri @mouse07410 @d3lm and others