Skip to content

Implement external ownership for AES-GCM context - #8178

Open
Eddy Ashton (eddyashton) wants to merge 4 commits into
mainfrom
agents/context-object-ownership-implementation
Open

Implement external ownership for AES-GCM context#8178
Eddy Ashton (eddyashton) wants to merge 4 commits into
mainfrom
agents/context-object-ownership-implementation

Conversation

@eddyashton

@eddyashton Eddy Ashton (eddyashton) commented Aug 19, 2026

Copy link
Copy Markdown
Member

This pull request implements an alternative approach to the context object ownership as discussed in #8170. The key changes include:

  • External Ownership: Introduced an externally owned KeyAesGcm::Context that can be created through make_context(), allowing for faster encryption and decryption calls.
  • Thread-Safe API: Preserved the existing thread-safe convenience API by maintaining the creation of fresh contexts for direct KeyAesGcm::encrypt/decrypt calls.
  • Reusable Context: Each LedgerSecret now owns a reusable context, synchronized with a mutex to ensure thread safety.
  • Benchmark Improvements: Updated benchmarks to reflect the performance of the new implementation, showing significant latency reductions compared to previous versions.
  • Code Simplification: Removed unnecessary provider-fetch logic for cipher selection, reverting to static EVP_aes_*_gcm() calls for improved performance.

Validation

  • All targeted tests passed successfully.
  • Benchmark results indicate improved performance:
    • 64 bytes: 265 ns/op (compared to 522 ns/op from the previous context pool implementation).
    • 1 KiB: 429 ns/op.

This implementation enhances the performance and usability of the AES-GCM encryption while ensuring thread safety and compatibility with existing APIs.

Copilot AI and others added 4 commits August 18, 2026 15:17
Co-authored-by: eddyashton <6000239+eddyashton@users.noreply.github.com>
…m-contexts' into agents/context-object-ownership-implementation
@eddyashton
Eddy Ashton (eddyashton) requested a review from a team as a code owner August 19, 2026 12:12
Copilot AI lite review requested due to automatic review settings August 19, 2026 12:12

Copilot AI left a comment

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.

Pull request overview

This PR extends CCF’s AES-GCM symmetric key abstraction to support externally owned, reusable “pre-keyed” cipher contexts (KeyAesGcm::Context via make_context()), and wires this into ledger encryption by giving each LedgerSecret a reusable context protected by a mutex. It also adds new concurrency/behavior tests and a microbenchmark to validate and measure the new approach.

Changes:

  • Introduce ccf::crypto::KeyAesGcm::Context and make_context() for reusable, non-concurrently-used AES-GCM contexts.
  • Update the OpenSSL AES-GCM implementation to create and reuse pre-keyed EVP_CIPHER_CTX instances.
  • Update ledger encryption to use LedgerSecret-owned reusable contexts, plus add concurrent tests and an AES-GCM benchmark.

Custom instructions used:

  • .github/copilot-instructions.md
  • .github/instructions/reviewing.instructions.md

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/node/test/encryptor.cpp Adds a concurrent encrypt/decrypt test and strengthens rollback lifetime checks.
src/node/ledger_secret.h Adds per-LedgerSecret reusable AES-GCM context with mutex-guarded encrypt/decrypt helpers.
src/kv/encryptor.h Switches to retrieving LedgerSecret and calling its encrypt/decrypt wrappers.
src/crypto/test/crypto.cpp Adds AES-GCM context-reuse, empty-input, and concurrency tests.
src/crypto/test/bench.cpp Adds AES-GCM encryption microbench using a reusable context.
src/crypto/openssl/symmetric_key.h Adds make_context() to the OpenSSL-backed AES-GCM key and moves cleansing to out-of-line dtor.
src/crypto/openssl/symmetric_key.cpp Refactors AES-GCM encrypt/decrypt around reusable pre-keyed contexts.
include/ccf/crypto/symmetric_key.h Extends public API with KeyAesGcm::Context and make_context().
CHANGELOG.md Documents the new public API for reusable AES-GCM contexts.
Suppressed comments (4)

src/crypto/openssl/symmetric_key.cpp:152

  • On authentication failure, decrypt_with_context() returns false without clearing the output buffer. Callers that reuse the plain vector can accidentally observe stale plaintext from a previous successful decrypt.
      if (EVP_DecryptFinal_ex(ctx, nullptr, &final_outl) != 1)
      {
        return false;
      }

src/crypto/openssl/symmetric_key.cpp:165

  • decrypt_with_context() only assigns to the output plain when cipher is non-empty. For valid AAD-only messages (empty cipher), the function returns true but leaves plain unchanged, so callers reusing the vector may see stale data.
      if (!cipher.empty())
      {
        plain = std::move(plaintext);
      }

src/crypto/openssl/symmetric_key.cpp:157

  • Typo in comment: should refer to GCM (not GSM) and fix grammar (“As long as …”).
      // As long a we use GSM cipher, the final outl must be 0, because there's
      // no padding and the block size is equal to 1, so EncryptUpdate() always
      // does the whole thing. Final is still a must to finalize and check the
      // error.

src/crypto/test/crypto.cpp:921

  • Similarly, this empty-cipher decrypt assertion seeds decrypted as empty, so it won’t catch a bug where decrypt() returns true but leaves stale data in the output buffer. Seed the output with non-empty data first.
  decrypted.clear();
  REQUIRE(empty_aes_gcm_key->decrypt(iv, empty_tag, {}, {}, decrypted));
  REQUIRE(decrypted.empty());

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/node/test/encryptor.cpp
Comment thread src/crypto/openssl/symmetric_key.cpp
Comment thread src/crypto/openssl/symmetric_key.cpp
Comment thread src/crypto/test/crypto.cpp
Comment thread CHANGELOG.md
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.

3 participants