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

AEAD decryption-in-place traits with additional tag processing, created for committing AEAD wrappers #1372

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

rlee287
Copy link
Contributor

@rlee287 rlee287 commented Nov 1, 2023

Add AEAD decryption-in-place traits that allow additional processing on the expected tag before comparison to the received tag. This will allow me to implement the full CTX construction and possibly other similar constructions (see RustCrypto/AEADs#564) instead of only the encryption direction.

Exposing the expected tag in this way may increase the chances of misuse. I tried to file off as many potential sharp edges as possible (e.g. by leaving the final tag comparison up to the implementer of the trait and by using Fn instead of FnMut or FnOnce to make copying the expected tag out of the closure harder), but do leave feedback if there are safer ways of allowing this functionality.

@tarcieri
Copy link
Member

tarcieri commented Nov 1, 2023

I'm still confused why these are necessary. The Aead and AeadInPlace traits already provide access to the original tag as part of the original message.

With a breaking change we can split the *_detached methods of AeadInPlace into their own trait which would make the latter cleaner for this particular use case. Of all of the APIs, they are the only ones which don't expose the tag, but if we filed them under their own trait you could simply not implement them and implement AeadInPlace instead.

@rlee287
Copy link
Contributor Author

rlee287 commented Nov 1, 2023

Under the CTX construction (which is the motivation for this PR), the original (inner) tag is not available.

Pseudocode for CTX (crossposted from the Zulip chat) is as follows:

fn ctx_encrypt<AEAD, Digest>(key, ptxt, aad) -> (ctxt, outer_tag) {
    let nonce = AEAD::generate_nonce();

    let (ctxt, inner_tag) = AEAD::encrypt(key, ptxt, aad);

    let digest_obj = Digest::new();
    digest_obj.update(key);
    digest_obj.update(nonce);
    digest_obj.update(aad);
    digest_obj.update(inner_tag);

    let outer_tag = digest_obj.finalize();
    (ctxt, outer_tag)
}

fn ctx_decrypt<AEAD, Digest>(key, nonce, ctxt, aad, outer_tag) -> Result<ptxt, ()> {
    let (ptxt, expected_inner_tag) = AEAD::decrypt_with_expected_tag(key, nonce, ctxt, aad);

    let digest_obj = Digest::new();
    digest_obj.update(key);
    digest_obj.update(nonce);
    digest_obj.update(aad);
    digest_obj.update(expected_inner_tag);

    let expected_outer_tag = digest_obj.finalize();
    if expected_outer_tag.ct_eq(tag) {
        Ok(ptxt)
    } else {
        Err(())
    }
}

The CTX construction wraps an AEAD and replaces the original (inner) tag with a hash that is computed over the AEAD's inputs. Only the hash (outer tag) gets sent as the MAC, but CTX decryption requires the original (inner) tag in order to check the received (outer) tag. The original (inner) tag cannot be recovered from the transmitted hash (outer tag), and as far as I can tell, there is no way to retrieve the expected inner tag during decryption using the current interfaces. Sending both tags has potential problems, which is why I created a CTXish-HMAC construction in the other PR to enable that to be done safely.

@tarcieri
Copy link
Member

tarcieri commented Nov 1, 2023

But if you have a generic implementation of committing AEADs, what is the purpose of the trait? Abstracting over that and potential future constructions?

@rlee287
Copy link
Contributor Author

rlee287 commented Nov 1, 2023

The generic implementation of CTX in the other PR is incomplete because the decryption stage of many of the wrapping constructions, including CTX, require access to more of the wrapped AEAD's internal state than is provided by a decryption method that returns the equivalent of Result<ptxt, Error>. This PR would give me access to the extra internal state (namely, the wrapped AEAD's computed tag, before the equality check) that would let me implement the decryption direction of CTX as well (along with potential future constructions that also need it.)

@tarcieri
Copy link
Member

tarcieri commented Nov 1, 2023

Aha, that makes sense. Thanks.

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

Successfully merging this pull request may close these issues.

2 participants