Skip to content

aead: avoid double allocation/copy in AES-GCM(-SIV) encrypt - #874

Open
vmaheshw wants to merge 1 commit into
project-oak:mainfrom
vmaheshw:vmaheshw/fix-aead-encrypt-avoid-double-copy
Open

aead: avoid double allocation/copy in AES-GCM(-SIV) encrypt#874
vmaheshw wants to merge 1 commit into
project-oak:mainfrom
vmaheshw:vmaheshw/fix-aead-encrypt-avoid-double-copy

Conversation

@vmaheshw

Copy link
Copy Markdown

What

AesGcm::encrypt (and AesGcmSiv::encrypt) currently go through the RustCrypto aead crate's allocating Aead::encrypt, which allocates a new Vec for ciphertext || tag, and then that whole buffer gets copied a second time into a freshly allocated iv || ciphertext Vec.

This switches both to AeadInPlace::encrypt_in_place_detached:

  1. Allocate the final output buffer once, sized for iv + pt + tag.
  2. Write iv then pt into it.
  3. Encrypt the pt portion of that same buffer in place (no extra buffer), getting the tag back detached.
  4. Append the 16-byte tag.

Net effect: one heap allocation and one full-size copy of the ciphertext removed per encrypt() call. decrypt(), the wire format (iv || ciphertext || tag), and public API are unchanged.

Testing

cargo test -p tink-tests --test aead_test

All AES-GCM and AES-GCM-SIV unit tests and Wycheproof vector tests pass (33 passed; 0 failed, after git submodule update --init for wycheproof vectors).

cargo clippy -p tink-aead --all-targets reports no new warnings from this change.

AesGcm::encrypt (and AesGcmSiv::encrypt) previously called the
RustCrypto aead crate's allocating encrypt(), which allocates a new
Vec for the ciphertext+tag, then copied that whole buffer a second
time into a freshly allocated iv||ciphertext Vec.

Switch to AeadInPlace::encrypt_in_place_detached: allocate the final
output buffer once (iv || pt, sized for iv + pt + tag), encrypt the
plaintext portion of that same buffer in place, and append the
16-byte tag. This drops one heap allocation and one full-size copy
of the ciphertext per encrypt call, while leaving decrypt and the
wire format unchanged.

Verified with cargo test -p tink-tests --test aead_test (all AES-GCM
and AES-GCM-SIV unit + Wycheproof vector tests pass).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@google-cla

google-cla Bot commented Aug 25, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

let ct_buf = &mut ret[iv.len()..];
let tag = match &self.key {
AesGcmVariant::Aes128(key) => key.encrypt_in_place_detached(&iv, aad, ct_buf),
AesGcmVariant::Aes256(key) => key.encrypt_in_place_detached(&iv, aad, ct_buf),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Aside: this method gets deprecated in favour of AeadInOut::encrypt_inout_detached as of aes-gcm version 0.11; however, the replacement method isn't available in the 0.10 version used here.)

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