RustCrypto / AEADs

Authenticated Encryption with Associated Data Algorithms: high-level encryption ciphers
668 stars 140 forks source link

Key comitting AEADs #241

Open burdges opened 3 years ago

burdges commented 3 years ago

It's maybe too soon to consider this here, but..

There are a few recent standards that started including key committing AEADs, notable anything extremely low-entropy like OPAQUE. https://eprint.iacr.org/2017/664.pdf https://eprint.iacr.org/2020/1491.pdf https://eprint.iacr.org/2020/1153.pdf

There remain some gaps in the literature, like encrypt-then-MAC with either a KDF or KEX that yields a common encryption and MAC key sounds more committing than any of those articles indicates, and is already fairly standard practice.

tarcieri commented 3 years ago

I'm not sure it makes sense to work on these until there are some sort of standardized constructions which have evolved beyond the research (or internal corporate usage) stage.

rozbb commented 2 years ago

Adding to the list: https://eprint.iacr.org/2022/268 https://eprint.iacr.org/2020/1456

rozbb commented 2 years ago

I've been looking into implementing some of these lately. It seems the generic transformations will require a new aead trait.

Often, a generic transformation will be of the form "open AND check some value; succeed iff both succeed". In order for this to be constant time, open should probably return a Choice.

Currently, most open functions decrypt, check the MAC, and re-encrypt and return Error on MAC failure. Our generic transformation needs to be able to defer the re-encryption to the end of all the checks. So concretely, the new trait would probably look like

trait ClobberingDecryptor {
    // Still to return `Result` because buffer or AAD might exceed max length
    fn clobbering_decrypt(
        &mut self,
        buffer: &mut [u8],
        aad: &[u8],
        tag: &Tag,
    ) -> Result<Choice>;

    // Re-encrypts the previously decrypted ciphertext; only called when opening fails
    fn unclobber(&mut self, buffer: &mut [u8], tag: &Tag);
}

Open to suggestions. Other alternatives include:

Also this would definitely be feature gated because nobody should reasonably use this.

tarcieri commented 2 years ago

@rozbb perhaps build one or more implementations with inherent methods first?

rozbb commented 2 years ago

Sure, I can use a fork of AEADs and see how it goes.

On Apr 29, 2022, at 09:42, Tony Arcieri @.***> wrote:

 @rozbb perhaps build one or more implementations with inherent methods first?

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.

rozbb commented 2 years ago

I have some preliminary key-committing AEADs running now. Here's an example of how I use the clobbering decryption feature.

I settled on the ClobberingDecrypt trait, which I defined for AES-GCM. The reasoning I chose ClobberingDecrypt over the ideas that take in a Choice is because of composability: a type that impls the Choice-style trait still does not produce any Choice values in its own API. So it cannot be used as input to another implementor of a Choice-style trait.

Separately, there's the question of whether the unclobber() method should exist. This is inconsistent in RustCrypto right now. AES-GCM-SIV currently re-encrypts plaintext that failed to authenticate. At the same time, AES-GCM does not. What's the behavior I should be targeting?

tarcieri commented 2 years ago

This is inconsistent in RustCrypto right now. AES-GCM-SIV currently re-encrypts plaintext that failed to authenticate. At the same time, AES-GCM does not. What's the behavior I should be targeting?

As we move towards one-pass interleaved authentication/decryption (#74), they will all need to do this, as the MAC can't be verified until that pass is complete.