Skip to content

AES Key Wrap (KW) and Key Wrap with Padding (KWP), SP 800-38F, on the key-object path (#150) - #160

Closed
roy-basmacier wants to merge 18 commits into
bcgit:release/0.1.4alphafrom
roy-basmacier:feature/150-key-wrap
Closed

roy-basmacier wants to merge 18 commits into
bcgit:release/0.1.4alphafrom
roy-basmacier:feature/150-key-wrap

Conversation

@roy-basmacier

@roy-basmacier roy-basmacier commented Sep 30, 2026 •

Copy link
Copy Markdown

AES Key Wrap (KW) and Key Wrap with Padding (KWP), NIST SP 800-38F Sec 6.2 and 6.3 (RFC 3394 / RFC 5649), over any 128-bit block permutation, on the key-object path of release/0.1.4alpha. Closes #150.

The first two commits are Roy's original traits and implementation. The rest is the port onto the key objects, the mode traits and the borrowed workers that landed in the meantime, one commit per crate, plus the review fixes.

core

  • KeyWrapper / KeyUnwrapper are worker traits on the shape of MAC: &self methods over a worker that borrows the keyed permutation, no key parameter. They are separate so a policy can allow unwrapping without wrapping. AlgorithmInfo supertrait and Self: Sized fences on the const-generic one-shots keep the run-time-length half dyn-compatible, like every other worker trait.
  • Fixed-length one-shots wrap_key / unwrap_key (provided over wrap_key_out / unwrap_key_out) reject an invalid (KEY_LEN, CT_LEN) pair with an inline const assertion, so a wrong length is a compile error. Run-time-length wrap_out / unwrap_out, sized by wrap_out_len (exact) and unwrap_out_max_len (upper bound), return InvalidInputLength outside SP 800-38F Table 1. Every _out method zeroizes its whole buffer first. The roles also provide the allocating wrap / unwrap under std, as the cipher roles do beside their _out forms.
  • Unwrap output is a Secret, not a KeyMaterial: unwrapping says nothing about the type or provenance of the bytes. Every authenticity failure is the one DecryptionFailed.
  • hazmat KeyWrapMode / KeyUnwrapMode hand the worker out from a key state; the role traits KeyWrappingKey / KeyUnwrappingKey in symmetric_key forward to them with the one-shots provided.
  • SymmetricCipherError::InvalidInputLength.

core-test-framework

  • key_wrap::TestFrameworkKeyWrap: test runs a key type through both roles and both workers (round trips, determinism, length helpers, buffer-too-small and invalid-length errors with the buffer checked for zeroing, tamper and wrong-KEK rejection); test_kat takes a published vector. An in-file mock (not cryptography) keeps the suite honest.

cipher

  • KW / KWP mode types whose key state is the permutation; Kw<'k, P> / Kwp<'k, P> workers on the shape of Cmac. W and W⁻¹ (Algorithms 1 and 2) run in place in the RFC 3394 Sec 2.2.1 index form; KW-AE/AD are Algorithms 3 and 4, KWP-AE/AD Algorithms 5 and 6 with the single-block path, and the three KWP-AD checks are made unconditionally and combined bitwise. ModeNames gains KW_ALG_NAME / KWP_ALG_NAME (the open cipher PRs will need the two consts when this lands).

aes

  • AES128Key<KW>, AES128Key<KWP> and the 192/256 forms implement the two roles; AES_KW_128 … AES_KWP_256 name the workers. Tests: all six RFC 3394 Sec 4 vectors and both RFC 5649 Sec 6 examples through test_kat, the framework at 26 payload lengths, the ACVP-AES-KW and -KWP sets from bc-test-data (1800 cases each, forgeries counted), the construction suite, alias names, and KW/KWP benches.

cli

  • aes{128,192,256}-{kw,kwp} -d encrypt|decrypt, stdin to stdout, key loading shared with the other AES commands. Not streaming: all of stdin is read, then written in one go. cli/tests/test_aes_kw.sh replays the RFC vectors both ways and pins the length rules, the fail-closed unwrap and key loading.

TKW (TDEA) is not included; it needs the 64-bit-block engine of #139.

Mutants (apollo, scoped to the changed files, cipher + aes tests):

  • bouncycastle-cipher, modes/kw.rs + modes/kwp.rs: 151 mutants, 111 caught, 38 unviable, 2 missed. Both misses replace 2 * SEMIBLOCK_LEN with 2 + SEMIBLOCK_LEN in a minimum-length check that runs after the 8-byte alignment test, so >= 16 and >= 10 agree on every length that reaches it: equivalent.
  • bouncycastle-core, the key-wrap traits and roles in traits.rs + symmetric_key.rs (tests from cipher, aes and the framework): 46 mutants, 18 caught, 28 unviable, 0 missed.
  • bouncycastle-aes, the two role impls in key.rs: 2 mutants, both unviable.

Assisted-by: Claude:claude-opus-5-5
Assisted-by: Claude:claude-fable-5-1
Assisted-by: Claude:claude-mythos-5-1

@ounsworth ounsworth added this to the 0.1.4alpha milestone Oct 24, 2026
@dghgit
dghgit force-pushed the feature/150-key-wrap branch from 339868e to 80c25ff Compare October 26, 2026 18:39
dghgit added a commit to roy-basmacier/bc-rust that referenced this pull request Oct 26, 2026
…KeyWrapMode/KeyUnwrapMode and the KeyWrappingKey/KeyUnwrappingKey roles

The traits from PR bcgit#160 took the KEK as a KeyMaterial on every call. On the key path the KEK is
validated once, when the key object is made, so the pair becomes worker traits on the shape of
MAC: `&self` methods over a worker that borrows the keyed permutation, with no key parameter and
no KeyMaterialError. The mode traits (hazmat) hand the worker out from a key state, and the role
traits forward to them with the one-shots provided, as the MAC roles do. The length helpers take
`&self` so the role can forward them through a worker.

Assisted-by: Claude:claude-mythos-5-1
dghgit added a commit to roy-basmacier/bc-rust that referenced this pull request Oct 26, 2026
… the keyed permutation

The two structs from PR bcgit#160 held a PhantomData and keyed the permutation on every call. They
become workers on the shape of Cmac: `Kw<'k, P>` over a `&'k P`, with `KW` / `KWP` as the mode
markers a key is bound to, their key state the permutation alone, and KeyWrapMode / KeyUnwrapMode
handing the worker out. ModeNames gains KW_ALG_NAME and KWP_ALG_NAME. The toy key gets the two
roles, and the structural tests run over it; the framework's tamper checks need diffusion, so
they run in `aes`.

Assisted-by: Claude:claude-mythos-5-1
dghgit added a commit to roy-basmacier/bc-rust that referenced this pull request Oct 26, 2026
…ild key objects

The six commands load `AES*Key<KW>` / `AES*Key<KWP>` through load_key_object and call the key's
one-shots. The direction takes the CipherDirection flag every other cipher command takes, so
`-d encrypt` wraps and `-d decrypt` unwraps, instead of PR bcgit#160's positional wrap|unwrap. The Rust
subprocess test becomes cli/tests/test_aes_kw.sh on the shell harness the other commands use,
with the same cases: the RFC vectors both ways, framing, the length rules, rejection with no
output, and key loading.

Assisted-by: Claude:claude-mythos-5-1

@ounsworth ounsworth 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.

Why is this +65,000 lines, changing 354 files?

I suspect there's a bit branching issue here. Once we finish the release/0.1.3alpha, and fork a new release/0.1.4alpha branch and point this at it, maybe the diff will get smaller?

@dghgit
dghgit changed the base branch from feature/simple-ciphers to feature/key-rework-memory October 31, 2026 05:55
@dghgit
dghgit self-requested a review October 31, 2026 13:22
@dghgit
dghgit force-pushed the feature/key-rework-memory branch from 3c170c9 to 81cef74 Compare November 3, 2026 02:36
dghgit added a commit that referenced this pull request Nov 3, 2026
…KeyWrapMode/KeyUnwrapMode and the KeyWrappingKey/KeyUnwrappingKey roles

The traits from PR #160 took the KEK as a KeyMaterial on every call. On the key path the KEK is
validated once, when the key object is made, so the pair becomes worker traits on the shape of
MAC: `&self` methods over a worker that borrows the keyed permutation, with no key parameter and
no KeyMaterialError. The mode traits (hazmat) hand the worker out from a key state, and the role
traits forward to them with the one-shots provided, as the MAC roles do. The length helpers take
`&self` so the role can forward them through a worker.

Assisted-by: Claude:claude-mythos-5-1
dghgit added a commit that referenced this pull request Nov 3, 2026
… the keyed permutation

The two structs from PR #160 held a PhantomData and keyed the permutation on every call. They
become workers on the shape of Cmac: `Kw<'k, P>` over a `&'k P`, with `KW` / `KWP` as the mode
markers a key is bound to, their key state the permutation alone, and KeyWrapMode / KeyUnwrapMode
handing the worker out. ModeNames gains KW_ALG_NAME and KWP_ALG_NAME. The toy key gets the two
roles, and the structural tests run over it; the framework's tamper checks need diffusion, so
they run in `aes`.

Assisted-by: Claude:claude-mythos-5-1
dghgit added a commit that referenced this pull request Nov 3, 2026
…ild key objects

The six commands load `AES*Key<KW>` / `AES*Key<KWP>` through load_key_object and call the key's
one-shots. The direction takes the CipherDirection flag every other cipher command takes, so
`-d encrypt` wraps and `-d decrypt` unwraps, instead of PR #160's positional wrap|unwrap. The Rust
subprocess test becomes cli/tests/test_aes_kw.sh on the shell harness the other commands use,
with the same cases: the RFC vectors both ways, framing, the length rules, rejection with no
output, and key loading.

Assisted-by: Claude:claude-mythos-5-1
@dghgit
dghgit force-pushed the feature/150-key-wrap branch from 6c866ff to 020dbe6 Compare November 3, 2026 02:41
@hubot
hubot deleted the branch bcgit:feature/key-rework-memory November 3, 2026 13:17
@hubot
hubot deleted the branch bcgit:feature/key-rework-memory November 4, 2026 22:43
dghgit added a commit to roy-basmacier/bc-rust that referenced this pull request Nov 5, 2026
…KeyWrapMode/KeyUnwrapMode and the KeyWrappingKey/KeyUnwrappingKey roles

The traits from PR bcgit#160 took the KEK as a KeyMaterial on every call. On the key path the KEK is
validated once, when the key object is made, so the pair becomes worker traits on the shape of
MAC: `&self` methods over a worker that borrows the keyed permutation, with no key parameter and
no KeyMaterialError. The mode traits (hazmat) hand the worker out from a key state, and the role
traits forward to them with the one-shots provided, as the MAC roles do. The length helpers take
`&self` so the role can forward them through a worker.

Assisted-by: Claude:claude-mythos-5-1
dghgit added a commit to roy-basmacier/bc-rust that referenced this pull request Nov 5, 2026
… the keyed permutation

The two structs from PR bcgit#160 held a PhantomData and keyed the permutation on every call. They
become workers on the shape of Cmac: `Kw<'k, P>` over a `&'k P`, with `KW` / `KWP` as the mode
markers a key is bound to, their key state the permutation alone, and KeyWrapMode / KeyUnwrapMode
handing the worker out. ModeNames gains KW_ALG_NAME and KWP_ALG_NAME. The toy key gets the two
roles, and the structural tests run over it; the framework's tamper checks need diffusion, so
they run in `aes`.

Assisted-by: Claude:claude-mythos-5-1
@dghgit
dghgit force-pushed the feature/150-key-wrap branch from 020dbe6 to 3983972 Compare November 5, 2026 01:35
dghgit added a commit to roy-basmacier/bc-rust that referenced this pull request Nov 5, 2026
…ild key objects

The six commands load `AES*Key<KW>` / `AES*Key<KWP>` through load_key_object and call the key's
one-shots. The direction takes the CipherDirection flag every other cipher command takes, so
`-d encrypt` wraps and `-d decrypt` unwraps, instead of PR bcgit#160's positional wrap|unwrap. The Rust
subprocess test becomes cli/tests/test_aes_kw.sh on the shell harness the other commands use,
with the same cases: the RFC vectors both ways, framing, the length rules, rejection with no
output, and key loading.

Assisted-by: Claude:claude-mythos-5-1
@dghgit
dghgit changed the base branch from feature/key-rework-memory to release/0.1.4alpha November 5, 2026 01:40
royb and others added 10 commits November 5, 2026 13:47
Adds the core API for the key-wrap algorithms of NIST SP 800-38F (KW, KWP,
TKW; RFC 3394 / RFC 5649), following the discussion on bcgit#150 and the
conventions of the cipher traits on this branch. Traits only: an AES-KW/KWP
implementation over ElectronicCodeBook in bouncycastle-modes is to follow
once the API is agreed.

core/traits.rs:
- KeyWrapper<KEK_LEN> and KeyUnwrapper<KEK_LEN> as separate traits, so a
  policy can allow unwrapping existing ciphertexts while forbidding new
  wrappings, as with the *Encryptor/*Decryptor pairs.
- Fixed-length one-shots wrap_key/unwrap_key are provided over the required
  wrap_key_out/unwrap_key_out. Implementations must reject invalid
  (KEY_LEN, CT_LEN) pairs with an inline const assertion, so a wrong length
  is a compile error rather than a runtime Err.
- Runtime-length wrap_out/unwrap_out cover KWP over arbitrary data, sized by
  wrap_out_len (exact) and unwrap_out_max_len (upper bound), mirroring
  encrypt_out_len/decrypt_out_max_len. OutputBufferTooSmall is checked
  before any work is done.
- Wrap input is plain bytes, since wrapping strips KeyMaterial metadata.
  Unwrap output is a Secret, so it is zeroized on drop without claiming a
  KeyType or provenance.
- Every unwrap authenticity failure (wrong KEK, tampering, ICV mismatch,
  bad padding, wrong recovered length) is the same DecryptionFailed, per
  SP 800-38F Algorithm 6 steps 4, 7 and 8; output buffers are zeroized on
  error.
- The KEK must be a SymmetricCipherKey at least as strong as
  MAX_SECURITY_STRENGTH. App. A.2's advice that the KEK *should* be as
  strong as the wrapped key is documented as the caller's responsibility.

core/errors.rs:
- SymmetricCipherError::InvalidInputLength, for plaintext or ciphertext
  lengths the algorithm is not defined on (variable-length APIs only).

core-test-framework:
- New key_wrap module: TestFrameworkKeyWrap::test() exercises round trips,
  determinism, the length helpers, buffer-size and input-length errors,
  tamper and wrong-KEK rejection, output zeroization, and KEK type and
  strength checks. test_kat() is ready for the RFC 3394/5649 vectors.
- Checked against an in-file mock (not cryptography) with KWP's length
  behaviour. Adds a bouncycastle-utils dependency for Secret.

Assisted-by: Claude:claude-opus-5-5
Implements the KeyWrapper / KeyUnwrapper traits from the previous commit
for the two 128-bit-block key-wrap algorithms of NIST SP 800-38F, KW
(Sec 6.2; RFC 3394) and KWP (Sec 6.3; RFC 5649), generically over any
ElectronicCodeBook permutation, and publishes the AES instantiations.

modes:
- kw.rs: Kw<P, KEK_LEN>. The wrapping function W and its inverse
  (Algorithms 1 and 2) run in place on the caller's buffer, visiting the
  registers in the order the spec's shift register would present them,
  which RFC 3394 Sec 2.2.1 gives as the equivalent index-based form; the
  one block of scratch is a Secret. KW-AE/AD are Algorithms 3 and 4.
- kwp.rs: Kwp<P, KEK_LEN>. KWP-AE/AD are Algorithms 5 and 6, including
  the single-block path for plaintexts of at most one semiblock. The ICV,
  length-field and padding checks of Algorithm 6 steps 4, 7 and 8 are all
  made, combined bitwise, and reported as the one DecryptionFailed.
- The fixed-length API rejects invalid (KEY_LEN, CT_LEN) pairs at compile
  time via const assertions on the Table 1 limits; the run-time API
  returns InvalidInputLength outside them. Output buffers are zeroized on
  every failure. TKW (TDEA) is not included: it needs a 64-bit-block
  engine (PR bcgit#139).

aes:
- kw.rs: AES_KW_128/192/256 and AES_KWP_128/192/256 aliases, with the
  RFC 3394 Sec 4.1 and RFC 5649 7-octet vectors as doctests. No OIDs yet,
  in line with the other AES mode aliases.

tests:
- modes/tests/kw_tests.rs: all six RFC 3394 Sec 4 vectors and both
  RFC 5649 Sec 6 examples via TestFrameworkKeyWrap::test_kat, the shared
  framework for every AES key length at 26 payload lengths (every padding
  length of the single-block case included), and pins for the properties
  that distinguish KW, KWP and a raw block encryption.
- modes/tests/acvp_kw_tests.rs: the NIST ACVP-AES-KW and ACVP-AES-KWP
  sets from bc-test-data, 1800 cases each, through both APIs, including
  the 171 + 178 forged ciphertexts that must be rejected.
- aes/tests/kw_alias_tests.rs: the aliases name the right permutation and
  pass the framework.

benches: KW/KWP wrap and unwrap of a 256-bit key, and KWP over 4 KiB.

cli: aes{128,192,256}-kw and -kwp with wrap|unwrap, reading all of stdin
(key wrap is one-shot), sharing key loading with the other AES commands;
cli/tests/aes_kw_cli_tests.rs replays the RFC vectors in both directions
and pins the length rules, the fail-closed unwrap and the help text.

Assisted-by: Claude:claude-fable-5-1
…KeyWrapMode/KeyUnwrapMode and the KeyWrappingKey/KeyUnwrappingKey roles

The traits from PR bcgit#160 took the KEK as a KeyMaterial on every call. On the key path the KEK is
validated once, when the key object is made, so the pair becomes worker traits on the shape of
MAC: `&self` methods over a worker that borrows the keyed permutation, with no key parameter and
no KeyMaterialError. The mode traits (hazmat) hand the worker out from a key state, and the role
traits forward to them with the one-shots provided, as the MAC roles do. The length helpers take
`&self` so the role can forward them through a worker.

Assisted-by: Claude:claude-mythos-5-1
… roles and its workers

`test` and `test_kat` take the key type and build it from the seed through FromKeyMaterial; the KEK
type and strength checks leave, since the construction suite covers them, and the wrong-KEK case
is a second key. The mock becomes a key with a borrowed worker.

Assisted-by: Claude:claude-mythos-5-1
… the keyed permutation

The two structs from PR bcgit#160 held a PhantomData and keyed the permutation on every call. They
become workers on the shape of Cmac: `Kw<'k, P>` over a `&'k P`, with `KW` / `KWP` as the mode
markers a key is bound to, their key state the permutation alone, and KeyWrapMode / KeyUnwrapMode
handing the worker out. ModeNames gains KW_ALG_NAME and KWP_ALG_NAME. The toy key gets the two
roles, and the structural tests run over it; the framework's tamper checks need diffusion, so
they run in `aes`.

Assisted-by: Claude:claude-mythos-5-1
… aliases name the workers

The key gets the two key-wrap roles, forwarded to the mode as the others are, and the internal
permutations get their KW and KWP names. The aliases become `Kw<'k, AES128Internal>` and friends,
the shape of AES_CMAC_128. Tests: the RFC 3394 and RFC 5649 vectors and the shared key-wrap
framework through the keys, the ACVP KW and KWP sets from bc-test-data (1800 cases each, with
the forgeries counted), the construction suite, and the alias names alongside the other aliases.
The modes bench gains the KW/KWP measurements the old modes crate's bench had.

Assisted-by: Claude:claude-mythos-5-1
…ild key objects

The six commands load `AES*Key<KW>` / `AES*Key<KWP>` through load_key_object and call the key's
one-shots. The direction takes the CipherDirection flag every other cipher command takes, so
`-d encrypt` wraps and `-d decrypt` unwraps, instead of PR bcgit#160's positional wrap|unwrap. The Rust
subprocess test becomes cli/tests/test_aes_kw.sh on the shell harness the other commands use,
with the same cases: the RFC vectors both ways, framing, the length rules, rejection with no
output, and key loading.

Assisted-by: Claude:claude-mythos-5-1
Kw::from_perm and Kwp::from_perm were pub, which the key-rework-memory merge
just made the odd ones out: 534d182 took every other worker's bare
constructor to pub(crate) under QUALITY_AND_STYLE's hazmat rule, since the
key object is the route and the mode impls that call them live in this
crate. The two follow. The doc examples build their KEK through the test
suite's toy key, as the other modes' now do, and kw_tests compares the key
route against the hazmat key-wrap mode traits rather than the constructors.

Assisted-by: Claude:claude-mythos-5-1
…, carried over the rebase onto its release-based history

This branch took feature/key-rework-memory by merge, and the merge commits carried the
adaptations to what arrived. The rebase onto the branch's new history (key-rework-memory
rebased onto release/0.1.3alpha, which carries feature/key-rework as one squash commit)
dropped those merges; this commit restores the affected files to the branch's pre-rebase
tip, so the tree is identical to it.

Assisted-by: Claude:claude-mythos-5-1
… rebase from feature/key-rework-memory

The release reads a key file as raw bytes unless --hex-input is given, so the aes*-kw and
aes*-kwp help says so and the key-file test passes --hex-input for its hex form; kw_tests
allows the shared toy key's unused helpers, as the other mode tests do. The KW bullet moves
to the 0.1.4 release notes in the first commit.

Assisted-by: Claude:claude-opus-5-5
@dghgit
dghgit force-pushed the feature/150-key-wrap branch from 3983972 to 38427f5 Compare November 5, 2026 03:57
…rker traits are

The pair had `Algorithm` as its supertrait and no `Self: Sized` fence on the four const-generic
one-shots, so `&dyn KeyWrapper` was rejected (E0038) where every other cipher and MAC worker
trait can be held as a trait object. The supertrait becomes `AlgorithmInfo` and the const-generic
methods are fenced, leaving `wrap_out`, `wrap_out_len`, `unwrap_out` and `unwrap_out_max_len`
dispatchable; dyn_compatible_tests pins the pair. The `_out` docs now say the buffer is zeroized
before anything else, which the cipher crate's implementations do from the next commit.

Also drops a stray first line on KeyUnwrapper's docs, the KeyStream header a merge had glued on.

Assisted-by: Claude:claude-mythos-5-1
…efore any check

`wrap_out` never zeroized its buffer and `unwrap_out` did so only after the OutputBufferTooSmall
check, so a refused call could leave stale bytes behind. Both now `fill(0)` first, before any
error checking, as the `_out` rule in QUALITY_AND_STYLE and GCM's do_encrypt_out have it.

Assisted-by: Claude:claude-mythos-5-1
…call left the buffer zeroed

The too-small-buffer and invalid-length cases pre-fill the output with 0xFF and assert it is all
zeros after the error; the mock zeroizes first, as the implementations must. Run against the
previous cipher commit's predecessor, the new asserts fail on both KW and KWP.

Assisted-by: Claude:claude-mythos-5-1
…oc matches SP 800-38F Sec 3.1

The six `kw_*`/`kwp_*` length predicates and helpers were public and used only by this crate's
own tests. They become pub(crate): the lower bounds, the alignment rule and the length helpers
are now pinned through a key's run-time API in kw_tests, and the 2^54, 2^32 and 2^29 upper
bounds of Table 1, which no buffer can reach, are a unit test at the bottom of each mode file.

The modes overview said KW and KWP "are not a mode for data"; SP 800-38F Sec 3.1 approves them
for general data as well as keys. It now says so, and points at the determinism note in `kw`
for why an AEAD is the better fit for data that may repeat.

Assisted-by: Claude:claude-mythos-5-1
@dghgit dghgit changed the title Add KeyWrapper/KeyUnwrapper traits for SP 800-38F key wrap (#150) AES Key Wrap (KW) and Key Wrap with Padding (KWP), SP 800-38F, on the key-object path (#150) Nov 5, 2026
…ots under `std`

The roles had the fixed-length `wrap_key` / `unwrap_key` and the buffer-taking `wrap_out` /
`unwrap_out`, but not the allocating form every other role trait provides beside its `_out`
method. `wrap` and `unwrap` are provided over the worker's length helper and `_out` method,
gated on `std` as `encrypt_with_aad` is. `unwrap` returns a `Vec`, which `Secret` cannot wrap,
so its doc points at `unwrap_key` for a known length and asks the caller to zeroize otherwise.

Assisted-by: Claude:claude-mythos-5-1
…/ `unwrap`

They are checked against the fixed-length answers in `test` and `test_kat`, and for the
invalid-length and modified-ciphertext errors.

Assisted-by: Claude:claude-mythos-5-1
The command no longer sizes and truncates its own output buffer.

Assisted-by: Claude:claude-mythos-5-1

@dghgit dghgit 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.

I rebased this first. After that the only thing I found it seemed short was the lack of unwrap/wrap methods that returned the plain-test/cipher-text. I've added these.

This one is now approved and ready to go.

@dghgit

dghgit commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Merged as squash 27b83ed on release/0.1.4alpha (author royb).

@dghgit dghgit closed this Nov 5, 2026
dghgit pushed a commit that referenced this pull request Nov 5, 2026
…W) and Key Wrap with Padding (KWP), NIST SP 800-38F Sec 6.2 and 6.3 (RFC 3394 / RFC 5649), over any 128-bit block permutation on the key-object path: the KeyWrapper / KeyUnwrapper worker traits in core on the shape of MAC (AlgorithmInfo supertrait and Self: Sized on the const-generic one-shots so the run-time-length half is dyn-compatible; fixed-length wrap_key / unwrap_key whose (KEY_LEN, CT_LEN) pair is checked at compile time; run-time-length wrap_out / unwrap_out returning InvalidInputLength outside Table 1, every _out method zeroizing its whole buffer first; unwrap output a Secret rather than a KeyMaterial; every authenticity failure the one DecryptionFailed), the hazmat KeyWrapMode / KeyUnwrapMode and the KeyWrappingKey / KeyUnwrappingKey roles with the one-shots and the allocating wrap / unwrap provided under std; a key_wrap suite in core-test-framework checked against an in-file mock; the KW / KWP mode types and the Kw / Kwp workers in cipher, with W and W⁻¹ (Algorithms 1 and 2) in place in the RFC 3394 Sec 2.2.1 index form, KW-AE/AD and KWP-AE/AD as Algorithms 3 to 6 including the single-block path, the three KWP-AD checks made unconditionally and combined bitwise, and ModeNames gaining KW_ALG_NAME / KWP_ALG_NAME; AES*Key<KW> / AES*Key<KWP> and the AES_KW_* / AES_KWP_* aliases in aes, tested against all six RFC 3394 Sec 4 vectors, both RFC 5649 Sec 6 examples, the ACVP-AES-KW and -KWP sets from bc-test-data (1800 cases each, forgeries counted) and the shared suites, with criterion benches; the aes{128,192,256}-kw and -kwp CLI commands (-d encrypt|decrypt, not streaming) and their shell test. TKW is not included. Mutants on the changed files: cipher kw.rs + kwp.rs 151 (111 caught, 38 unviable, 2 equivalent), core traits and roles 46 (18 caught, 28 unviable), aes key roles 2 unviable.

Assisted-by: Claude:claude-opus-5-5
Assisted-by: Claude:claude-fable-5-1
Assisted-by: Claude:claude-mythos-5-1
hubot pushed a commit that referenced this pull request Nov 5, 2026
…into feature/aria: KW_ALG_NAME / KWP_ALG_NAME on the ARIA permutations

Assisted-by: Claude:claude-mythos-5-1
hubot pushed a commit that referenced this pull request Nov 5, 2026
…into feature/sm4: KW_ALG_NAME / KWP_ALG_NAME on the SM4 permutation

Assisted-by: Claude:claude-mythos-5-1
hubot pushed a commit that referenced this pull request Nov 5, 2026
…into feature/camellia: KW_ALG_NAME / KWP_ALG_NAME on the Camellia permutations

Assisted-by: Claude:claude-mythos-5-1
hubot pushed a commit that referenced this pull request Nov 5, 2026
…into feature/tdes: ModeNames gains KW_ALG_NAME / KWP_ALG_NAME, which the 64-bit TDEA permutations leave empty as they do the 128-bit-block modes' names (KW and KWP need a 128-bit block, SP 800-38F Sec 5.1; TKW is not implemented)

Assisted-by: Claude:claude-mythos-5-1
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