diff --git a/adr/decisions/2026-06-16-mlkem-direct-key-wrap.md b/adr/decisions/2026-06-16-mlkem-direct-key-wrap.md
new file mode 100644
index 0000000000..02887394df
--- /dev/null
+++ b/adr/decisions/2026-06-16-mlkem-direct-key-wrap.md
@@ -0,0 +1,112 @@
+---
+status: accepted
+date: 2026-06-16
+tags:
+ - cryptography
+ - mlkem
+ - kas
+ - hsm
+ - fips
+---
+# ML-KEM-wrapped KAOs use the Decaps shared secret directly as the AES-GCM wrap key (no HKDF)
+
+## Context and Problem Statement
+
+PR [opentdf/platform#3537](https://github.com/opentdf/platform/pull/3537) introduces a pure ML-KEM-768 / ML-KEM-1024 wrapping scheme for KAOs (key-access objects) — wire type `mlkem-wrapped`. The first draft of that PR derived the AES-256-GCM wrap key from the ML-KEM Decaps output via HKDF-SHA256 over a fixed `"TDF"` salt, mirroring the existing hybrid PQ/T (`hybrid-wrapped`) path.
+
+The intended downstream consumer is an HSM-backed KAS provider: specifically Thales Luna T-Series with firmware 7.15.1 in strict-FIPS mode. On that HSM, `CKM_ML_KEM_KEY_DECAP` can only materialize its 32-byte shared secret as a sensitive, non-extractable AES key object (`CKK_AES`). The HSM refuses to emit the Decaps result as `CKK_GENERIC_SECRET`, returning `CKR_ATTRIBUTE_TYPE_INVALID`, which means we cannot:
+
+* run `CKM_SHA256_HMAC` over the shared secret (so no HKDF-on-HSM), nor
+* extract the shared secret to run HKDF off-HSM (`CKA_EXTRACTABLE=false`).
+
+Any KDF in the unwrap chain therefore blocks HSM-backed KAS providers on this firmware.
+
+## Decision Drivers
+
+* Must support HSM-backed KAS providers (Thales Luna T-Series 7.15.1 in strict-FIPS mode) without an HSM firmware change, vendor RFE, or unsafe key extraction.
+* Must remain FIPS-compliant.
+* Must not change the on-wire envelope format (the wire format is the same ASN.1 DER `MLKEMWrappedKey { MLKEMCiphertext, EncryptedDEK }` — only the internal key-derivation step is removed).
+* Must not regress security relative to the HKDF-using draft.
+* Must not bleed into the hybrid PQ/T (`hybrid-wrapped`) wrap path, where HKDF is load-bearing as the combiner for the two shared-secret halves.
+
+## Considered Options
+
+1. Use the ML-KEM Decaps output directly as the AES-256-GCM wrap key for `mlkem-wrapped`.
+2. Keep HKDF-SHA256 over `(sharedSecret, salt, info)` and require vendor firmware support for `CKM_GENERIC_SECRET_KEY_GEN` from Decaps.
+3. Keep HKDF and require KAS operators to mark the ML-KEM private key as software-only (no HSM) when used with this wire format.
+
+## Decision Outcome
+
+Chosen option: **(1) Use the ML-KEM Decaps shared secret directly as the AES-256-GCM wrap key.**
+
+The 32-byte Decaps output is fed straight into AES-256-GCM with a fresh random nonce; the AES-GCM ciphertext + tag are stored as `EncryptedDEK` inside the existing ASN.1 envelope. The `salt` / `info` parameters that flow into the unified `kemEncryptor` / `kemDecryptor` are ignored by the ML-KEM adapter (they remain meaningful for the X-Wing and NIST EC + ML-KEM hybrid adapters, which still derive their AES key via HKDF as the combiner).
+
+### Wire format
+
+Unchanged. The envelope is still:
+
+```asn1
+MLKEMWrappedKey ::= SEQUENCE {
+ mlkemCiphertext [0] IMPLICIT OCTET STRING,
+ encryptedDEK [1] IMPLICIT OCTET STRING
+}
+```
+
+`encryptedDEK` is now `AES-256-GCM(K = mlkemSharedSecret, nonce = random12B, AAD = none, plaintext = DEK)` with the standard 12-byte nonce prefix + 16-byte tag layout produced by `ocrypto.AesGcm.Encrypt`. No HKDF; no `salt`; no `info`.
+
+### FIPS 203 justification
+
+FIPS 203 (Module-Lattice-Based Key-Encapsulation Mechanism Standard) specifies the Decaps output `K` as a uniformly random 32-byte shared secret produced by hashing through the spec's internal G/H/J SHA-3 family functions:
+
+* §7.3 *ML-KEM.Decaps*: "Output: shared secret key K ∈ B^{32}".
+* §6.3 *ML-KEM.Decaps* (the variant exposing the implicit-rejection branch) likewise emits a 32-byte K, including in the failure path where K is derived pseudorandomly from `(z, c)` using J — preserving indistinguishability from a real success.
+
+Because K is already a 32-byte uniformly random string by construction, an additional HKDF expansion would not increase its entropy or change its distribution — at best, HKDF would re-mix uniformly-random input bits into a different uniformly-random 32-byte output. It is not load-bearing.
+
+ML-KEM also produces a fresh K per encapsulation by construction (encapsulation samples fresh randomness `m` and packs it through K-PKE encrypt, so every wrap operation produces an independent K). The per-call key-isolation property HKDF is conventionally used to provide is therefore already present in the input.
+
+### Cryptographic argument
+
+The properties we need for a DEK-wrap key are:
+
+1. **Uniform 32-byte distribution.** ML-KEM `Decaps` outputs a 32-byte K drawn from the SHA-3 family applied to fresh per-encapsulation randomness; FIPS 203 specifies this directly.
+2. **Per-wrap independence.** Encapsulation samples a fresh 32-byte `m` per call, so K is independent across wraps by construction; no domain separation tag is required to keep wraps from colliding.
+3. **Authenticated wrap.** AES-256-GCM provides confidentiality and integrity for the wrapped DEK; a wrong-key unwrap fails at the GCM tag-check stage. FIPS 203 §6.3's implicit-rejection design means a wrong-key Decaps still returns a 32-byte K, but that K is pseudorandom and uncorrelated with the encryptor's K, so the AES-GCM tag verification fails.
+
+Skipping HKDF therefore neither lowers the wrap key's entropy nor weakens the unwrap-failure behaviour observed by the caller. The only thing HKDF would have added is a fixed-string domain-separation tag (`info`); since the `mlkem-wrapped` wire type is itself a domain-separation tag, there is no cross-protocol collision risk to defend against.
+
+### Code shape
+
+* `lib/ocrypto/kem.go`: the `kem` interface gains a `wrapKey(sharedSecret, salt, info []byte) ([]byte, error)` method. `mlkemKEM.wrapKey` returns the shared secret verbatim; `xwingKEM.wrapKey` and `nistHybridKEM.wrapKey` both delegate to the existing `hkdfWrapKey` (renamed from `deriveKEMWrapKey`). The `wrapDEKWithKEM` / `unwrapDEKWithKEM` helpers ask the adapter for the key.
+* `lib/ocrypto/mlkem.go`: the `MLKEM{768,1024}{Wrap,Unwrap}DEK` entry points pass `nil, nil` for salt/info so the ignore-semantics are obvious at the call site.
+* `lib/ocrypto/hybrid_common.go`: `defaultTDFSalt()` is retained — it is still the default HKDF salt for the X-Wing and NIST hybrid adapters and for ECIES (`FromPublicPEMWithSalt`).
+
+### Consequences
+
+* **Good**, because HSM-backed KAS providers (Thales Luna T-Series 7.15.1 in strict-FIPS mode) can now perform `mlkem-wrapped` unwrap end-to-end without ever extracting the Decaps shared secret. The 32-byte K stays on-HSM as a `CKK_AES`, sensitive, non-extractable object and is used directly by `CKM_AES_GCM`.
+* **Good**, because the wire format does not change: the ASN.1 envelope is byte-identical, and only the internal key derivation is removed.
+* **Good**, because the unified `kem` interface keeps the wrap/unwrap path single-source; the per-scheme key-derivation policy is the only thing that diverges, and it is captured in one method on the adapter.
+* **Neutral**, because the `salt` and `info` parameters threaded through the unified encryptor / decryptor constructors still exist (they are needed for X-Wing and NIST hybrid). They are silently ignored for ML-KEM. The `TestMLKEMSaltInfoIgnored` test pins this behaviour so it cannot regress.
+* **Bad**, because any wire-format artifact produced by the HKDF-using draft of PR #3537 is no longer decryptable. This is acceptable: PR #3537 is not merged and the HKDF-using artifacts existed only in the PR branch and its test fixtures.
+
+### Migration
+
+* PR #3537 is not merged. Any `mlkem-wrapped` envelopes that were produced by intermediate versions of that branch are no longer decryptable after this change.
+* The hybrid PQ/T (`hybrid-wrapped`) wrap path is **unchanged**. Both X-Wing and NIST EC + ML-KEM continue to use HKDF-SHA256 over the combined `(EC || ML-KEM)` shared secret, because the KDF is the combiner and is load-bearing for those schemes.
+
+### Out of scope
+
+* Maintaining an HKDF-using variant of `mlkem-wrapped` for non-HSM consumers. There is no consumer that requires HKDF — software KAS implementations can use the Decaps output directly with no measurable difference in behaviour or security, and the KDF only adds compute cost on the unwrap path. A second wire variant would split the ecosystem with no upside.
+* Generalising direct-shared-secret wrapping to the hybrid PQ/T schemes. For X-Wing and NIST EC + ML-KEM the AES wrap key must be derived from `(ecdhSecret || mlkemSecret)` via a KDF, because (a) the combined input is 64+ bytes (not 32), and (b) HKDF is the combiner that turns the two halves into a single uniformly-random key. Removing HKDF there would reduce security, not just compute.
+
+## Validation
+
+* `TestMLKEMSharedSecretIsAESWrapKey` (lib/ocrypto/mlkem_test.go) extracts the AES-GCM ciphertext from an `mlkem-wrapped` envelope and opens it using `AES-256-GCM(K = sharedSecret)` directly, asserting the recovered plaintext matches the original DEK. This pins the no-KDF contract from both directions (encrypt-side and decrypt-side).
+* `TestMLKEMSaltInfoIgnored` (lib/ocrypto/mlkem_test.go) wraps with one `(salt, info)` pair and unwraps with a different pair (and again with `nil, nil`); both must succeed, proving salt/info are no-ops for ML-KEM.
+* The existing `TestMLKEM{768,1024}WrapUnwrapRoundTrip`, `TestMLKEM{768,1024}WrapUnwrapWrongKeyFails`, and `TestMLKEM{768,1024}WrapDEKFormats` tests continue to pass.
+
+## More Information
+
+* FIPS 203, *Module-Lattice-Based Key-Encapsulation Mechanism Standard*, August 2024: https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.203.pdf
+* OpenTDF platform PR #3537 (ML-KEM-768 / ML-KEM-1024 post-quantum encryption support): https://github.com/opentdf/platform/pull/3537
+* Related: `lib/ocrypto/HYBRID_NIST_KEY_WRAPPING.md` (hybrid PQ/T variant, which retains HKDF as the combiner).
diff --git a/docs/grpc/index.html b/docs/grpc/index.html
index e22a412c00..27ca2623c6 100644
--- a/docs/grpc/index.html
+++ b/docs/grpc/index.html
@@ -4379,6 +4379,18 @@
Algorithm
|
+
+ | ALGORITHM_MLKEM_768 |
+ 20 |
+ |
+
+
+
+ | ALGORITHM_MLKEM_1024 |
+ 21 |
+ |
+
+
@@ -4584,6 +4596,18 @@ KasPublicKeyAlgEnum
|
+
+ | KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768 |
+ 20 |
+ |
+
+
+
+ | KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 |
+ 21 |
+ |
+
+
diff --git a/docs/openapi/authorization/authorization.openapi.yaml b/docs/openapi/authorization/authorization.openapi.yaml
index 5a112b61b6..cb0927c76c 100644
--- a/docs/openapi/authorization/authorization.openapi.yaml
+++ b/docs/openapi/authorization/authorization.openapi.yaml
@@ -143,6 +143,8 @@ components:
- ALGORITHM_HPQT_XWING
- ALGORITHM_HPQT_SECP256R1_MLKEM768
- ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ - ALGORITHM_MLKEM_768
+ - ALGORITHM_MLKEM_1024
description: Supported key algorithms.
policy.KasPublicKeyAlgEnum:
type: string
@@ -157,6 +159,8 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024
policy.SourceType:
type: string
title: SourceType
diff --git a/docs/openapi/authorization/v2/authorization.openapi.yaml b/docs/openapi/authorization/v2/authorization.openapi.yaml
index 0e03a9e182..e6914f49ba 100644
--- a/docs/openapi/authorization/v2/authorization.openapi.yaml
+++ b/docs/openapi/authorization/v2/authorization.openapi.yaml
@@ -178,6 +178,8 @@ components:
- ALGORITHM_HPQT_XWING
- ALGORITHM_HPQT_SECP256R1_MLKEM768
- ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ - ALGORITHM_MLKEM_768
+ - ALGORITHM_MLKEM_1024
description: Supported key algorithms.
policy.KasPublicKeyAlgEnum:
type: string
@@ -192,6 +194,8 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024
policy.SourceType:
type: string
title: SourceType
diff --git a/docs/openapi/policy/actions/actions.openapi.yaml b/docs/openapi/policy/actions/actions.openapi.yaml
index 3f16ddef73..6528f1ea00 100644
--- a/docs/openapi/policy/actions/actions.openapi.yaml
+++ b/docs/openapi/policy/actions/actions.openapi.yaml
@@ -206,6 +206,8 @@ components:
- ALGORITHM_HPQT_XWING
- ALGORITHM_HPQT_SECP256R1_MLKEM768
- ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ - ALGORITHM_MLKEM_768
+ - ALGORITHM_MLKEM_1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -257,6 +259,8 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024
policy.SourceType:
type: string
title: SourceType
diff --git a/docs/openapi/policy/attributes/attributes.openapi.yaml b/docs/openapi/policy/attributes/attributes.openapi.yaml
index b5270ccdb5..53c117c1cc 100644
--- a/docs/openapi/policy/attributes/attributes.openapi.yaml
+++ b/docs/openapi/policy/attributes/attributes.openapi.yaml
@@ -725,6 +725,8 @@ components:
- ALGORITHM_HPQT_XWING
- ALGORITHM_HPQT_SECP256R1_MLKEM768
- ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ - ALGORITHM_MLKEM_768
+ - ALGORITHM_MLKEM_1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -776,6 +778,8 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024
policy.SortDirection:
type: string
title: SortDirection
diff --git a/docs/openapi/policy/dynamicvaluemapping/dynamic_value_mapping.openapi.yaml b/docs/openapi/policy/dynamicvaluemapping/dynamic_value_mapping.openapi.yaml
index c05551ba69..0ef548fff7 100644
--- a/docs/openapi/policy/dynamicvaluemapping/dynamic_value_mapping.openapi.yaml
+++ b/docs/openapi/policy/dynamicvaluemapping/dynamic_value_mapping.openapi.yaml
@@ -206,6 +206,8 @@ components:
- ALGORITHM_HPQT_XWING
- ALGORITHM_HPQT_SECP256R1_MLKEM768
- ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ - ALGORITHM_MLKEM_768
+ - ALGORITHM_MLKEM_1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -257,6 +259,8 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024
policy.SortDirection:
type: string
title: SortDirection
diff --git a/docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml b/docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml
index 2d803524bb..b8c7b84cad 100644
--- a/docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml
+++ b/docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml
@@ -526,6 +526,8 @@ components:
- ALGORITHM_HPQT_XWING
- ALGORITHM_HPQT_SECP256R1_MLKEM768
- ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ - ALGORITHM_MLKEM_768
+ - ALGORITHM_MLKEM_1024
description: Supported key algorithms.
policy.KasPublicKeyAlgEnum:
type: string
@@ -540,6 +542,8 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024
policy.KeyMode:
type: string
title: KeyMode
@@ -1181,7 +1185,7 @@ components:
Required The algorithm to be used for the key
The key_algorithm must be one of the defined values.:
```
- this in [1, 2, 3, 4, 5, 6, 7, 8]
+ this in [1, 2, 3, 4, 5, 6, 7, 8, 20, 21]
```
$ref: '#/components/schemas/policy.Algorithm'
@@ -1742,7 +1746,7 @@ components:
Filter keys by algorithm
The key_algorithm must be one of the defined values.:
```
- this in [0, 1, 2, 3, 4, 5, 6, 7, 8]
+ this in [0, 1, 2, 3, 4, 5, 6, 7, 8, 20, 21]
```
$ref: '#/components/schemas/policy.Algorithm'
@@ -2020,7 +2024,7 @@ components:
Required
The key_algorithm must be one of the defined values.:
```
- this in [1, 2, 3, 4, 5, 6, 7, 8]
+ this in [1, 2, 3, 4, 5, 6, 7, 8, 20, 21]
```
$ref: '#/components/schemas/policy.Algorithm'
diff --git a/docs/openapi/policy/namespaces/namespaces.openapi.yaml b/docs/openapi/policy/namespaces/namespaces.openapi.yaml
index d6f72e3e69..c813ecd93c 100644
--- a/docs/openapi/policy/namespaces/namespaces.openapi.yaml
+++ b/docs/openapi/policy/namespaces/namespaces.openapi.yaml
@@ -356,6 +356,8 @@ components:
- ALGORITHM_HPQT_XWING
- ALGORITHM_HPQT_SECP256R1_MLKEM768
- ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ - ALGORITHM_MLKEM_768
+ - ALGORITHM_MLKEM_1024
description: Supported key algorithms.
policy.KasPublicKeyAlgEnum:
type: string
@@ -370,6 +372,8 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024
policy.SortDirection:
type: string
title: SortDirection
diff --git a/docs/openapi/policy/objects.openapi.yaml b/docs/openapi/policy/objects.openapi.yaml
index b888894b3c..c2e9a36bab 100644
--- a/docs/openapi/policy/objects.openapi.yaml
+++ b/docs/openapi/policy/objects.openapi.yaml
@@ -24,6 +24,8 @@ components:
- ALGORITHM_HPQT_XWING
- ALGORITHM_HPQT_SECP256R1_MLKEM768
- ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ - ALGORITHM_MLKEM_768
+ - ALGORITHM_MLKEM_1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -75,6 +77,8 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024
policy.KeyMode:
type: string
title: KeyMode
diff --git a/docs/openapi/policy/obligations/obligations.openapi.yaml b/docs/openapi/policy/obligations/obligations.openapi.yaml
index 01fcb57b6a..4b5c79f0b5 100644
--- a/docs/openapi/policy/obligations/obligations.openapi.yaml
+++ b/docs/openapi/policy/obligations/obligations.openapi.yaml
@@ -556,6 +556,8 @@ components:
- ALGORITHM_HPQT_XWING
- ALGORITHM_HPQT_SECP256R1_MLKEM768
- ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ - ALGORITHM_MLKEM_768
+ - ALGORITHM_MLKEM_1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -607,6 +609,8 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024
policy.SortDirection:
type: string
title: SortDirection
diff --git a/docs/openapi/policy/registeredresources/registered_resources.openapi.yaml b/docs/openapi/policy/registeredresources/registered_resources.openapi.yaml
index cf6f526825..1d08486fa0 100644
--- a/docs/openapi/policy/registeredresources/registered_resources.openapi.yaml
+++ b/docs/openapi/policy/registeredresources/registered_resources.openapi.yaml
@@ -416,6 +416,8 @@ components:
- ALGORITHM_HPQT_XWING
- ALGORITHM_HPQT_SECP256R1_MLKEM768
- ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ - ALGORITHM_MLKEM_768
+ - ALGORITHM_MLKEM_1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -467,6 +469,8 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024
policy.SortDirection:
type: string
title: SortDirection
diff --git a/docs/openapi/policy/resourcemapping/resource_mapping.openapi.yaml b/docs/openapi/policy/resourcemapping/resource_mapping.openapi.yaml
index c17e546137..5810360c25 100644
--- a/docs/openapi/policy/resourcemapping/resource_mapping.openapi.yaml
+++ b/docs/openapi/policy/resourcemapping/resource_mapping.openapi.yaml
@@ -416,6 +416,8 @@ components:
- ALGORITHM_HPQT_XWING
- ALGORITHM_HPQT_SECP256R1_MLKEM768
- ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ - ALGORITHM_MLKEM_768
+ - ALGORITHM_MLKEM_1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -467,6 +469,8 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024
policy.SourceType:
type: string
title: SourceType
diff --git a/docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml b/docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml
index 1113568374..0639d2fdbc 100644
--- a/docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml
+++ b/docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml
@@ -452,6 +452,8 @@ components:
- ALGORITHM_HPQT_XWING
- ALGORITHM_HPQT_SECP256R1_MLKEM768
- ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ - ALGORITHM_MLKEM_768
+ - ALGORITHM_MLKEM_1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -503,6 +505,8 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024
policy.SortDirection:
type: string
title: SortDirection
diff --git a/docs/openapi/policy/unsafe/unsafe.openapi.yaml b/docs/openapi/policy/unsafe/unsafe.openapi.yaml
index eff9dbd4d7..771e2f691d 100644
--- a/docs/openapi/policy/unsafe/unsafe.openapi.yaml
+++ b/docs/openapi/policy/unsafe/unsafe.openapi.yaml
@@ -390,6 +390,8 @@ components:
- ALGORITHM_HPQT_XWING
- ALGORITHM_HPQT_SECP256R1_MLKEM768
- ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ - ALGORITHM_MLKEM_768
+ - ALGORITHM_MLKEM_1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -441,6 +443,8 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
- KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768
+ - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024
policy.KeyMode:
type: string
title: KeyMode
diff --git a/lib/ocrypto/asym_decryption.go b/lib/ocrypto/asym_decryption.go
index 28c31798a2..300f8f9c03 100644
--- a/lib/ocrypto/asym_decryption.go
+++ b/lib/ocrypto/asym_decryption.go
@@ -43,11 +43,22 @@ func FromPrivatePEMWithSalt(privateKeyInPem string, salt, info []byte) (PrivateK
if block == nil {
return AsymDecryption{}, errors.New("failed to parse PEM formatted private key")
}
-
- // Hybrid PQ/T private keys are PKCS#8-wrapped under one of our known OIDs.
- // Peek at the AlgorithmIdentifier and route hybrids to their constructors;
- // everything else (RSA, EC, EC PRIVATE KEY) falls through to x509.
+ // Pure ML-KEM private keys are PKCS#8-wrapped under the NIST OIDs handled by
+ // the unified kem path. Try these first so an ML-KEM key is never misrouted
+ // into the hybrid OID dispatcher.
if block.Type == pemBlockPrivateKey {
+ switch oid, seed, err := parseKEMPrivatePKCS8(block.Bytes); {
+ case err == nil:
+ if k, ok := kemByOID(oid); ok {
+ return newKEMDecryptor(k, seed, salt, info)
+ }
+ case !errors.Is(err, errNotKEM):
+ return AsymDecryption{}, err
+ }
+
+ // Hybrid PQ/T private keys are PKCS#8-wrapped under our composite-KEM
+ // OIDs. Route hybrids to their per-scheme constructors; everything else
+ // (RSA, EC, EC PRIVATE KEY) falls through to x509.
if dec, matched, err := hybridDecryptorFromPKCS8(block.Bytes, salt, info); matched {
return dec, err
}
@@ -95,19 +106,6 @@ func FromPrivatePEMWithSalt(privateKeyInPem string, salt, info []byte) (PrivateK
return nil, errors.New("not a supported PEM formatted private key")
}
-func NewAsymDecryption(privateKeyInPem string) (AsymDecryption, error) {
- d, err := FromPrivatePEMWithSalt(privateKeyInPem, nil, nil)
- if err != nil {
- return AsymDecryption{}, err
- }
- switch d := d.(type) {
- case AsymDecryption:
- return d, nil
- default:
- return AsymDecryption{}, errors.New("not an RSA private key")
- }
-}
-
// Decrypt decrypts ciphertext with private key.
func (asymDecryption AsymDecryption) Decrypt(data []byte) ([]byte, error) {
if asymDecryption.PrivateKey == nil {
@@ -221,15 +219,8 @@ func hybridDecryptorFromPKCS8(der, salt, info []byte) (PrivateKeyDecryptor, bool
// KEY). Fall through to the legacy decoder.
return nil, false, nil //nolint:nilerr // intentional fall-through on non-envelope input
}
- switch {
- case oid.Equal(oidXWing):
- dec, err := NewSaltedXWingDecryptor(raw, salt, info)
- return dec, true, err
- case oid.Equal(oidCompositeMLKEM768P256):
- dec, err := NewP256MLKEM768Decryptor(raw)
- return dec, true, err
- case oid.Equal(oidCompositeMLKEM1024P384):
- dec, err := NewP384MLKEM1024Decryptor(raw)
+ if k, ok := hybridKEMByOID(oid); ok {
+ dec, err := newKEMDecryptor(k, raw, salt, info)
return dec, true, err
}
// Valid PKCS#8 envelope with a non-hybrid OID. If the stdlib recognises it,
diff --git a/lib/ocrypto/asym_encryption.go b/lib/ocrypto/asym_encryption.go
index 860e799cbf..5d302cd756 100644
--- a/lib/ocrypto/asym_encryption.go
+++ b/lib/ocrypto/asym_encryption.go
@@ -26,6 +26,7 @@ const (
RSA SchemeType = "wrapped"
EC SchemeType = "ec-wrapped"
Hybrid SchemeType = "hybrid-wrapped"
+ MLKEM SchemeType = "mlkem-wrapped"
)
type PublicKeyEncryptor interface {
@@ -74,11 +75,23 @@ func FromPublicPEMWithSalt(publicKeyInPem string, salt, info []byte) (PublicKeyE
if block == nil {
return nil, errors.New("failed to parse PEM formatted public key")
}
-
- // Hybrid PQ/T public keys are SPKI-wrapped under one of our known OIDs.
- // Peek at the AlgorithmIdentifier and route hybrids to their constructors;
- // everything else (RSA, EC, CERTIFICATE) falls through to the x509 path.
+ // Pure ML-KEM public keys are SPKI-wrapped under the NIST OIDs handled by
+ // the unified kem path. Try these first so an ML-KEM key is never misrouted
+ // into the hybrid OID dispatcher (which would treat an unknown OID as an
+ // error rather than falling through).
if block.Type == pemBlockPublicKey {
+ switch oid, key, err := ParseKEMPublicSPKI(block.Bytes); {
+ case err == nil:
+ if k, ok := kemByOID(oid); ok {
+ return newKEMEncryptor(k, key, salt, info)
+ }
+ case !errors.Is(err, errNotKEM):
+ return nil, err
+ }
+
+ // Hybrid PQ/T public keys are SPKI-wrapped under our composite-KEM OIDs.
+ // Peek at the AlgorithmIdentifier and route hybrids to their per-scheme
+ // constructors; everything else (RSA, EC) falls through to the x509 path.
if enc, matched, err := hybridEncryptorFromSPKI(block.Bytes, salt, info); matched {
return enc, err
}
@@ -117,25 +130,6 @@ func newECIES(pub *ecdh.PublicKey, salt, info []byte) (ECEncryptor, error) {
return ECEncryptor{pub, ek, salt, info}, err
}
-// NewAsymEncryption creates and returns a new AsymEncryption.
-//
-// Deprecated: Use FromPublicPEM instead.
-func NewAsymEncryption(publicKeyInPem string) (AsymEncryption, error) {
- pub, err := getPublicPart(publicKeyInPem)
- if err != nil {
- return AsymEncryption{}, err
- }
-
- switch pub := pub.(type) {
- case *rsa.PublicKey:
- return AsymEncryption{pub}, nil
- default:
- break
- }
-
- return AsymEncryption{}, fmt.Errorf("unsupported public key type: %T", pub)
-}
-
func getPublicPart(publicKeyInPem string) (any, error) {
block, _ := pem.Decode([]byte(publicKeyInPem))
if block == nil {
@@ -303,15 +297,8 @@ func hybridEncryptorFromSPKI(der, salt, info []byte) (PublicKeyEncryptor, bool,
// which handles PKCS#1 keys, certificates, and stdlib-recognised SPKI.
return nil, false, nil //nolint:nilerr // intentional fall-through on non-envelope input
}
- switch {
- case oid.Equal(oidXWing):
- enc, err := NewXWingEncryptor(raw, salt, info)
- return enc, true, err
- case oid.Equal(oidCompositeMLKEM768P256):
- enc, err := NewP256MLKEM768Encryptor(raw)
- return enc, true, err
- case oid.Equal(oidCompositeMLKEM1024P384):
- enc, err := NewP384MLKEM1024Encryptor(raw)
+ if k, ok := hybridKEMByOID(oid); ok {
+ enc, err := newKEMEncryptor(k, raw, salt, info)
return enc, true, err
}
// Valid SPKI envelope with a non-hybrid OID. If the stdlib recognises it,
diff --git a/lib/ocrypto/benchmark_test.go b/lib/ocrypto/benchmark_test.go
index b325672176..199f1939e2 100644
--- a/lib/ocrypto/benchmark_test.go
+++ b/lib/ocrypto/benchmark_test.go
@@ -234,7 +234,7 @@ func BenchmarkUnwrapDEK(b *testing.B) {
if err != nil {
b.Fatal(err)
}
- rsaEnc, err := NewAsymEncryption(rsaPubPEM)
+ rsaEnc, err := FromPublicPEM(rsaPubPEM)
if err != nil {
b.Fatal(err)
}
@@ -242,7 +242,7 @@ func BenchmarkUnwrapDEK(b *testing.B) {
if err != nil {
b.Fatal(err)
}
- rsaDec, err := NewAsymDecryption(rsaPrivPEM)
+ rsaDec, err := FromPrivatePEM(rsaPrivPEM)
if err != nil {
b.Fatal(err)
}
@@ -364,7 +364,7 @@ func BenchmarkUnwrapDEK(b *testing.B) {
if err != nil {
b.Fatal(err)
}
- xwingWrapped, err := XWingWrapDEK(xwingKP.publicKey, testDEK)
+ xwingWrapped, err := wrapDEKWithKEM(xwingKEM{}, xwingKP.publicKey, testDEK, salt, nil)
if err != nil {
b.Fatal(err)
}
@@ -378,7 +378,7 @@ func BenchmarkUnwrapDEK(b *testing.B) {
if err != nil {
b.Fatal(err)
}
- p256Wrapped, err := P256MLKEM768WrapDEK(p256KP.publicKey, testDEK)
+ p256Wrapped, err := wrapDEKWithKEM(hybridNISTKEM{params: &p256mlkem768Params}, p256KP.publicKey, testDEK, nil, nil)
if err != nil {
b.Fatal(err)
}
@@ -392,7 +392,7 @@ func BenchmarkUnwrapDEK(b *testing.B) {
if err != nil {
b.Fatal(err)
}
- p384Wrapped, err := P384MLKEM1024WrapDEK(p384KP.publicKey, testDEK)
+ p384Wrapped, err := wrapDEKWithKEM(hybridNISTKEM{params: &p384mlkem1024Params}, p384KP.publicKey, testDEK, nil, nil)
if err != nil {
b.Fatal(err)
}
@@ -473,7 +473,7 @@ func TestWrappedKeySizeComparison(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- rsaEnc, err := NewAsymEncryption(rsaPubPEM)
+ rsaEnc, err := FromPublicPEM(rsaPubPEM)
if err != nil {
t.Fatal(err)
}
@@ -547,7 +547,7 @@ func TestWrappedKeySizeComparison(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- xwingWrapped, err := XWingWrapDEK(xwingKP.publicKey, testDEK)
+ xwingWrapped, err := wrapDEKWithKEM(xwingKEM{}, xwingKP.publicKey, testDEK, nil, nil)
if err != nil {
t.Fatal(err)
}
@@ -567,7 +567,7 @@ func TestWrappedKeySizeComparison(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- p256Wrapped, err := P256MLKEM768WrapDEK(p256KP.publicKey, testDEK)
+ p256Wrapped, err := wrapDEKWithKEM(hybridNISTKEM{params: &p256mlkem768Params}, p256KP.publicKey, testDEK, nil, nil)
if err != nil {
t.Fatal(err)
}
@@ -587,7 +587,7 @@ func TestWrappedKeySizeComparison(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- p384Wrapped, err := P384MLKEM1024WrapDEK(p384KP.publicKey, testDEK)
+ p384Wrapped, err := wrapDEKWithKEM(hybridNISTKEM{params: &p384mlkem1024Params}, p384KP.publicKey, testDEK, nil, nil)
if err != nil {
t.Fatal(err)
}
diff --git a/lib/ocrypto/ec_key_pair.go b/lib/ocrypto/ec_key_pair.go
index c5e288373b..84056d02b8 100644
--- a/lib/ocrypto/ec_key_pair.go
+++ b/lib/ocrypto/ec_key_pair.go
@@ -4,6 +4,7 @@ import (
"crypto/ecdh"
"crypto/ecdsa"
"crypto/elliptic"
+ "crypto/mlkem"
"crypto/rand"
"crypto/sha256"
"crypto/x509"
@@ -17,46 +18,6 @@ import (
"golang.org/x/crypto/hkdf"
)
-type ECCMode uint8
-
-type KeyType string
-
-const (
- RSA2048Key KeyType = "rsa:2048"
- RSA4096Key KeyType = "rsa:4096"
- EC256Key KeyType = "ec:secp256r1"
- EC384Key KeyType = "ec:secp384r1"
- EC521Key KeyType = "ec:secp521r1"
-)
-
-// ParseKeyType validates a string as a known KeyType, returning an error for
-// unrecognized values.
-func ParseKeyType(alg string) (KeyType, error) {
- switch KeyType(alg) {
- case RSA2048Key, RSA4096Key,
- EC256Key, EC384Key, EC521Key,
- HybridXWingKey, HybridSecp256r1MLKEM768Key, HybridSecp384r1MLKEM1024Key:
- return KeyType(alg), nil
- default:
- return "", fmt.Errorf("unrecognized key type: %s", alg)
- }
-}
-
-const (
- ECCModeSecp256r1 ECCMode = 0
- ECCModeSecp384r1 ECCMode = 1
- ECCModeSecp521r1 ECCMode = 2
- ECCModeSecp256k1 ECCMode = 3
-)
-
-const (
- ECCurveP256Size = 256
- ECCurveP384Size = 384
- ECCurveP521Size = 521
- RSA2048Size = 2048
- RSA4096Size = 4096
-)
-
type KeyPair interface {
PublicKeyInPemFormat() (string, error)
PrivateKeyInPemFormat() (string, error)
@@ -79,6 +40,10 @@ func NewKeyPair(kt KeyType) (KeyPair, error) {
return NewECKeyPair(mode)
case HybridSecp256r1MLKEM768Key, HybridSecp384r1MLKEM1024Key, HybridXWingKey:
return NewHybridKeyPair(kt)
+ case MLKEM768Key:
+ return NewMLKEMKeyPair()
+ case MLKEM1024Key:
+ return NewMLKEM1024KeyPair()
default:
return nil, fmt.Errorf("unsupported key type: %v", kt)
}
@@ -88,95 +53,12 @@ type ECKeyPair struct {
PrivateKey *ecdsa.PrivateKey
}
-func IsECKeyType(kt KeyType) bool {
- switch kt { //nolint:exhaustive // only handle ec types
- case EC256Key, EC384Key, EC521Key:
- return true
- default:
- return false
- }
-}
-
-func IsRSAKeyType(kt KeyType) bool {
- switch kt { //nolint:exhaustive // only handle rsa types
- case RSA2048Key, RSA4096Key:
- return true
- default:
- return false
- }
-}
-
-// GetECCurveFromECCMode return elliptic curve from ecc mode
-func GetECCurveFromECCMode(mode ECCMode) (elliptic.Curve, error) {
- var c elliptic.Curve
-
- switch mode {
- case ECCModeSecp256r1:
- c = elliptic.P256()
- case ECCModeSecp384r1:
- c = elliptic.P384()
- case ECCModeSecp521r1:
- c = elliptic.P521()
- case ECCModeSecp256k1:
- // TODO FIXME - unsupported?
- return nil, errors.New("unsupported ECC mode")
- default:
- return nil, fmt.Errorf("unsupported ECC mode %d", mode)
- }
-
- return c, nil
-}
-
-func (mode ECCMode) String() string {
- switch mode {
- case ECCModeSecp256r1:
- return "ec:secp256r1"
- case ECCModeSecp384r1:
- return "ec:secp384r1"
- case ECCModeSecp521r1:
- return "ec:secp521r1"
- case ECCModeSecp256k1:
- return "ec:secp256k1"
- }
- return "unspecified"
-}
-
-// ECSizeToMode converts a curve size to an ECCMode
-func ECSizeToMode(size int) (ECCMode, error) {
- switch size {
- case ECCurveP256Size:
- return ECCModeSecp256r1, nil
- case ECCurveP384Size:
- return ECCModeSecp384r1, nil
- case ECCurveP521Size:
- return ECCModeSecp521r1, nil
- default:
- return 0, fmt.Errorf("unsupported EC curve size: %d", size)
- }
+type MLKEMKeyPair struct {
+ PrivateKey *mlkem.DecapsulationKey768
}
-func ECKeyTypeToMode(kt KeyType) (ECCMode, error) {
- switch kt { //nolint:exhaustive // only handle ec types
- case EC256Key:
- return ECCModeSecp256r1, nil
- case EC384Key:
- return ECCModeSecp384r1, nil
- case EC521Key:
- return ECCModeSecp521r1, nil
- default:
- return 0, fmt.Errorf("unsupported type: %v", kt)
- }
-}
-
-func RSAKeyTypeToBits(kt KeyType) (int, error) {
- switch kt { //nolint:exhaustive // only handle rsa types
- case RSA2048Key:
- return RSA2048Size, nil
- case RSA4096Key:
- return RSA4096Size, nil
- default:
- return 0, fmt.Errorf("unsupported type: %v", kt)
- }
+type MLKEM1024KeyPair struct {
+ PrivateKey *mlkem.DecapsulationKey1024
}
// NewECKeyPair Generates an EC key pair of the given bit size.
@@ -452,7 +334,7 @@ func ECPrivateKeyInPemFormat(privateKey ecdsa.PrivateKey) (string, error) {
privateKeyPem := pem.EncodeToMemory(
&pem.Block{
- Type: "PRIVATE KEY",
+ Type: pemBlockPrivateKey,
Bytes: privateKeyBytes,
},
)
@@ -468,7 +350,7 @@ func ECPublicKeyInPemFormat(publicKey ecdsa.PublicKey) (string, error) {
publicKeyPem := pem.EncodeToMemory(
&pem.Block{
- Type: "PUBLIC KEY",
+ Type: pemBlockPublicKey,
Bytes: pkb,
},
)
@@ -509,3 +391,77 @@ func GetECKeySize(pemData []byte) (int, error) {
func (keyPair ECKeyPair) GetKeyType() KeyType {
return EC256Key
}
+
+func NewMLKEMKeyPair() (MLKEMKeyPair, error) {
+ privateKey, err := mlkem.GenerateKey768()
+ if err != nil {
+ return MLKEMKeyPair{}, fmt.Errorf("mlkem.GenerateKey768 failed: %w", err)
+ }
+
+ return MLKEMKeyPair{PrivateKey: privateKey}, nil
+}
+
+func NewMLKEM1024KeyPair() (MLKEM1024KeyPair, error) {
+ privateKey, err := mlkem.GenerateKey1024()
+ if err != nil {
+ return MLKEM1024KeyPair{}, fmt.Errorf("mlkem.GenerateKey1024 failed: %w", err)
+ }
+
+ return MLKEM1024KeyPair{PrivateKey: privateKey}, nil
+}
+
+func (keyPair MLKEMKeyPair) PrivateKeyInPemFormat() (string, error) {
+ if keyPair.PrivateKey == nil {
+ return "", errors.New("failed to generate PEM formatted private key")
+ }
+
+ der, err := marshalKEMPrivatePKCS8(OIDMLKEM768, keyPair.PrivateKey.Bytes())
+ if err != nil {
+ return "", fmt.Errorf("marshal ML-KEM-768 PKCS#8 failed: %w", err)
+ }
+ return string(pem.EncodeToMemory(&pem.Block{Type: pemBlockPrivateKey, Bytes: der})), nil
+}
+
+func (keyPair MLKEMKeyPair) PublicKeyInPemFormat() (string, error) {
+ if keyPair.PrivateKey == nil {
+ return "", errors.New("failed to generate PEM formatted public key")
+ }
+
+ der, err := marshalKEMPublicSPKI(OIDMLKEM768, keyPair.PrivateKey.EncapsulationKey().Bytes())
+ if err != nil {
+ return "", fmt.Errorf("marshal ML-KEM-768 SPKI failed: %w", err)
+ }
+ return string(pem.EncodeToMemory(&pem.Block{Type: pemBlockPublicKey, Bytes: der})), nil
+}
+
+func (keyPair MLKEMKeyPair) GetKeyType() KeyType {
+ return MLKEM768Key
+}
+
+func (keyPair MLKEM1024KeyPair) PrivateKeyInPemFormat() (string, error) {
+ if keyPair.PrivateKey == nil {
+ return "", errors.New("failed to generate PEM formatted private key")
+ }
+
+ der, err := marshalKEMPrivatePKCS8(OIDMLKEM1024, keyPair.PrivateKey.Bytes())
+ if err != nil {
+ return "", fmt.Errorf("marshal ML-KEM-1024 PKCS#8 failed: %w", err)
+ }
+ return string(pem.EncodeToMemory(&pem.Block{Type: pemBlockPrivateKey, Bytes: der})), nil
+}
+
+func (keyPair MLKEM1024KeyPair) PublicKeyInPemFormat() (string, error) {
+ if keyPair.PrivateKey == nil {
+ return "", errors.New("failed to generate PEM formatted public key")
+ }
+
+ der, err := marshalKEMPublicSPKI(OIDMLKEM1024, keyPair.PrivateKey.EncapsulationKey().Bytes())
+ if err != nil {
+ return "", fmt.Errorf("marshal ML-KEM-1024 SPKI failed: %w", err)
+ }
+ return string(pem.EncodeToMemory(&pem.Block{Type: pemBlockPublicKey, Bytes: der})), nil
+}
+
+func (keyPair MLKEM1024KeyPair) GetKeyType() KeyType {
+ return MLKEM1024Key
+}
diff --git a/lib/ocrypto/ecc_mode.go b/lib/ocrypto/ecc_mode.go
new file mode 100644
index 0000000000..a2dbeec9fa
--- /dev/null
+++ b/lib/ocrypto/ecc_mode.go
@@ -0,0 +1,71 @@
+package ocrypto
+
+import (
+ "crypto/elliptic"
+ "errors"
+ "fmt"
+)
+
+type ECCMode uint8
+
+const (
+ ECCModeSecp256r1 ECCMode = 0
+ ECCModeSecp384r1 ECCMode = 1
+ ECCModeSecp521r1 ECCMode = 2
+ ECCModeSecp256k1 ECCMode = 3
+)
+
+const (
+ ECCurveP256Size = 256
+ ECCurveP384Size = 384
+ ECCurveP521Size = 521
+)
+
+// GetECCurveFromECCMode return elliptic curve from ecc mode
+func GetECCurveFromECCMode(mode ECCMode) (elliptic.Curve, error) {
+ var c elliptic.Curve
+
+ switch mode {
+ case ECCModeSecp256r1:
+ c = elliptic.P256()
+ case ECCModeSecp384r1:
+ c = elliptic.P384()
+ case ECCModeSecp521r1:
+ c = elliptic.P521()
+ case ECCModeSecp256k1:
+ // TODO FIXME - unsupported?
+ return nil, errors.New("unsupported ECC mode")
+ default:
+ return nil, fmt.Errorf("unsupported ECC mode %d", mode)
+ }
+
+ return c, nil
+}
+
+func (mode ECCMode) String() string {
+ switch mode {
+ case ECCModeSecp256r1:
+ return "ec:secp256r1"
+ case ECCModeSecp384r1:
+ return "ec:secp384r1"
+ case ECCModeSecp521r1:
+ return "ec:secp521r1"
+ case ECCModeSecp256k1:
+ return "ec:secp256k1"
+ }
+ return "unspecified"
+}
+
+// ECSizeToMode converts a curve size to an ECCMode
+func ECSizeToMode(size int) (ECCMode, error) {
+ switch size {
+ case ECCurveP256Size:
+ return ECCModeSecp256r1, nil
+ case ECCurveP384Size:
+ return ECCModeSecp384r1, nil
+ case ECCurveP521Size:
+ return ECCModeSecp521r1, nil
+ default:
+ return 0, fmt.Errorf("unsupported EC curve size: %d", size)
+ }
+}
diff --git a/lib/ocrypto/hybrid_common.go b/lib/ocrypto/hybrid_common.go
index f7178d009c..a9f9631d27 100644
--- a/lib/ocrypto/hybrid_common.go
+++ b/lib/ocrypto/hybrid_common.go
@@ -5,6 +5,26 @@ import (
"fmt"
)
+// WrapDEK parses the recipient's KEM public key PEM via the OID/PEM-routed
+// dispatcher and produces the ASN.1-encoded wrapped DEK envelope. It covers
+// both pure ML-KEM (`mlkem-wrapped`) and hybrid PQ/T (`hybrid-wrapped`) KAOs so
+// SDK and service callers can wrap against any KEM scheme without a per-scheme
+// switch — the encryptor returned by FromPublicPEM selects the format.
+func WrapDEK(ktype KeyType, kasPublicKeyPEM string, dek []byte) ([]byte, error) {
+ if !IsKEMKeyType(ktype) {
+ return nil, fmt.Errorf("unsupported KEM key type: %s", ktype)
+ }
+
+ enc, err := FromPublicPEM(kasPublicKeyPEM)
+ if err != nil {
+ return nil, fmt.Errorf("kem public key: %w", err)
+ }
+ if enc.KeyType() != ktype {
+ return nil, fmt.Errorf("kem key type mismatch: PEM is %s, requested %s", enc.KeyType(), ktype)
+ }
+ return enc.Encrypt(dek)
+}
+
// HybridWrapDEK parses the recipient's hybrid public key PEM via the
// OID-routed dispatcher, asserts the encryptor matches the requested ktype,
// and produces the ASN.1-encoded wrapped DEK envelope used in
diff --git a/lib/ocrypto/hybrid_conformance_test.go b/lib/ocrypto/hybrid_conformance_test.go
index 4f1bfeb8d0..4945139f49 100644
--- a/lib/ocrypto/hybrid_conformance_test.go
+++ b/lib/ocrypto/hybrid_conformance_test.go
@@ -178,23 +178,22 @@ func assertHybridNISTPrivateKeyLayout(t *testing.T, keyPair HybridNISTKeyPair, p
func assertHybridNISTWrappedCiphertextLayout(t *testing.T, keyPair HybridNISTKeyPair, params *hybridNISTParams, mlkemCiphertextSize int) {
t.Helper()
- enc, err := NewP256MLKEM768Encryptor(keyPair.publicKey)
- if params.keyType == HybridSecp384r1MLKEM1024Key {
- enc, err = NewP384MLKEM1024Encryptor(keyPair.publicKey)
- }
+ pubPEM, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+ enc, err := FromPublicPEM(pubPEM)
require.NoError(t, err)
wrappedDER, err := enc.Encrypt([]byte("layout-test-dek"))
require.NoError(t, err)
- var wrapped HybridNISTWrappedKey
+ var wrapped kemEnvelope
rest, err := asn1.Unmarshal(wrappedDER, &wrapped)
require.NoError(t, err)
require.Empty(t, rest)
- require.Len(t, wrapped.HybridCiphertext, mlkemCiphertextSize+params.ecPubSize)
- require.Len(t, wrapped.HybridCiphertext[:mlkemCiphertextSize], mlkemCiphertextSize)
+ require.Len(t, wrapped.KEMCiphertext, mlkemCiphertextSize+params.ecPubSize)
+ require.Len(t, wrapped.KEMCiphertext[:mlkemCiphertextSize], mlkemCiphertextSize)
- ephemeralECPub := wrapped.HybridCiphertext[mlkemCiphertextSize:]
+ ephemeralECPub := wrapped.KEMCiphertext[mlkemCiphertextSize:]
require.Len(t, ephemeralECPub, params.ecPubSize)
require.Equal(t, byte(0x04), ephemeralECPub[0], "ephemeral EC point must be uncompressed SEC1")
_, err = params.curve.NewPublicKey(ephemeralECPub)
diff --git a/lib/ocrypto/hybrid_nist.go b/lib/ocrypto/hybrid_nist.go
index c127e7093e..2b6aa454c5 100644
--- a/lib/ocrypto/hybrid_nist.go
+++ b/lib/ocrypto/hybrid_nist.go
@@ -41,14 +41,6 @@ const (
P384MLKEM1024CiphertextSize = P384MLKEM1024MLKEMCtSize + P384MLKEM1024ECPublicKeySize // 1665
)
-// HybridNISTWrappedKey is the ASN.1 envelope stored in wrapped_key. The IETF
-// composite-KEM draft defines only the KEM; this DEK wrapping envelope is
-// kept identical to its pre-conformance shape so the TDF layer is unaffected.
-type HybridNISTWrappedKey struct {
- HybridCiphertext []byte `asn1:"tag:0"`
- EncryptedDEK []byte `asn1:"tag:1"`
-}
-
// hybridNISTParams captures the curve-specific parameters for one composite-KEM
// hybrid scheme.
type hybridNISTParams struct {
@@ -97,18 +89,6 @@ type HybridNISTKeyPair struct {
params *hybridNISTParams
}
-// HybridNISTEncryptor implements PublicKeyEncryptor for composite-KEM hybrids.
-type HybridNISTEncryptor struct {
- publicKey []byte
- params *hybridNISTParams
-}
-
-// HybridNISTDecryptor implements PrivateKeyDecryptor for composite-KEM hybrids.
-type HybridNISTDecryptor struct {
- privateKey []byte
- params *hybridNISTParams
-}
-
// IsHybridKeyType returns true if the key type is a hybrid post-quantum type.
func IsHybridKeyType(kt KeyType) bool {
switch kt { //nolint:exhaustive // only handle hybrid types
@@ -212,98 +192,133 @@ func (k HybridNISTKeyPair) GetKeyType() KeyType {
return k.params.keyType
}
-func NewP256MLKEM768Encryptor(publicKey []byte) (*HybridNISTEncryptor, error) {
- return newHybridNISTEncryptor(&p256mlkem768Params, publicKey)
-}
-
-func NewP384MLKEM1024Encryptor(publicKey []byte) (*HybridNISTEncryptor, error) {
- return newHybridNISTEncryptor(&p384mlkem1024Params, publicKey)
-}
-
-func newHybridNISTEncryptor(p *hybridNISTParams, publicKey []byte) (*HybridNISTEncryptor, error) {
- expectedSize := p.mlkemPubSize + p.ecPubSize
- if len(publicKey) != expectedSize {
- return nil, fmt.Errorf("invalid %s public key size: got %d want %d", p.keyType, len(publicKey), expectedSize)
+// hybridNISTKEM adapts a NIST composite-KEM hybrid (EC + ML-KEM) onto the
+// shared kem interface so it flows through wrapDEKWithKEM / unwrapDEKWithKEM
+// and the single kemEnvelope wire format. The combiner that produces the
+// AES-256 wrap key is folded into encapsulate / decapsulate, so wrapKey is an
+// identity pass-through of the already-derived key (mirroring pure ML-KEM).
+type hybridNISTKEM struct {
+ params *hybridNISTParams
+}
+
+func (k hybridNISTKEM) keyType() KeyType { return k.params.keyType }
+func (hybridNISTKEM) scheme() SchemeType { return Hybrid }
+func (k hybridNISTKEM) pubSize() int { return k.params.mlkemPubSize + k.params.ecPubSize }
+func (k hybridNISTKEM) ctSize() int { return k.params.mlkemCtSize + k.params.ecPubSize }
+
+// privSize is negative to mark a variable-length private key encoding
+// (mlkemSeed || ECPrivateKey DER, whose length depends on the RFC 5915
+// serialization). newKEMDecryptor skips its exact-size check for this scheme;
+// decapsulate validates the layout instead.
+func (hybridNISTKEM) privSize() int { return -1 }
+
+// encapsulate performs ECDH against an ephemeral key, ML-KEM encapsulation, and
+// the SHA3-256 combiner (draft-ietf-lamps-pq-composite-kem-14 §3.4), returning
+// the 32-byte combined key as the "shared secret" and `mlkemCT || ephemeralEC`
+// as the ciphertext. Math is preserved verbatim from the former
+// hybridNISTWrapDEK.
+func (k hybridNISTKEM) encapsulate(publicKeyRaw []byte) ([]byte, []byte, error) {
+ p := k.params
+ expectedPubSize := p.mlkemPubSize + p.ecPubSize
+ if len(publicKeyRaw) != expectedPubSize {
+ return nil, nil, fmt.Errorf("invalid %s public key size: got %d want %d", p.keyType, len(publicKeyRaw), expectedPubSize)
}
- return &HybridNISTEncryptor{
- publicKey: append([]byte(nil), publicKey...),
- params: p,
- }, nil
-}
-func (e *HybridNISTEncryptor) Encrypt(data []byte) ([]byte, error) {
- return hybridNISTWrapDEK(e.params, e.publicKey, data)
-}
+ mlkemPubBytes := publicKeyRaw[:p.mlkemPubSize]
+ ecPubBytes := publicKeyRaw[p.mlkemPubSize:]
-func (e *HybridNISTEncryptor) PublicKeyInPemFormat() (string, error) {
- der, err := marshalHybridSPKI(e.params.oid, e.publicKey)
+ ecPub, err := p.curve.NewPublicKey(ecPubBytes)
if err != nil {
- return "", err
+ return nil, nil, fmt.Errorf("invalid EC public key: %w", err)
}
- return string(pem.EncodeToMemory(&pem.Block{Type: pemBlockPublicKey, Bytes: der})), nil
-}
+ ephemeral, err := p.curve.GenerateKey(rand.Reader)
+ if err != nil {
+ return nil, nil, fmt.Errorf("ECDH ephemeral key generation failed: %w", err)
+ }
+ tradSS, err := ephemeral.ECDH(ecPub)
+ if err != nil {
+ return nil, nil, fmt.Errorf("ECDH failed: %w", err)
+ }
+ ephemeralPub := ephemeral.PublicKey().Bytes()
-func (e *HybridNISTEncryptor) Type() SchemeType { return Hybrid }
-func (e *HybridNISTEncryptor) KeyType() KeyType { return e.params.keyType }
-func (e *HybridNISTEncryptor) EphemeralKey() []byte { return nil }
+ mlkemSS, mlkemCT, err := mlkemEncapsulate(p, mlkemPubBytes)
+ if err != nil {
+ return nil, nil, err
+ }
-func (e *HybridNISTEncryptor) Metadata() (map[string]string, error) {
- return make(map[string]string), nil
-}
+ wrapKey := hybridNISTCombiner(p, mlkemSS, tradSS, ephemeralPub, ecPubBytes)
-func NewP256MLKEM768Decryptor(privateKey []byte) (*HybridNISTDecryptor, error) {
- return newHybridNISTDecryptor(&p256mlkem768Params, privateKey)
-}
+ hybridCt := make([]byte, 0, len(mlkemCT)+len(ephemeralPub))
+ hybridCt = append(hybridCt, mlkemCT...)
+ hybridCt = append(hybridCt, ephemeralPub...)
-func NewP384MLKEM1024Decryptor(privateKey []byte) (*HybridNISTDecryptor, error) {
- return newHybridNISTDecryptor(&p384mlkem1024Params, privateKey)
+ return wrapKey, hybridCt, nil
}
-func newHybridNISTDecryptor(p *hybridNISTParams, privateKey []byte) (*HybridNISTDecryptor, error) {
- if len(privateKey) <= mlkemSeedSize {
+// decapsulate is the symmetric inverse of encapsulate, returning the combiner
+// output as the "shared secret". Math is preserved verbatim from the former
+// hybridNISTUnwrapDEK. The ciphertext length is validated by unwrapDEKWithKEM
+// against ctSize() before this is called.
+func (k hybridNISTKEM) decapsulate(privateKeyRaw, ct []byte) ([]byte, error) {
+ p := k.params
+ if len(privateKeyRaw) <= mlkemSeedSize {
return nil, fmt.Errorf("invalid %s private key: shorter than ML-KEM seed + ECPrivateKey", p.keyType)
}
- // Parse the EC DER tail up front so a malformed key surfaces at
- // construction time — mirrors newHybridNISTEncryptor's exact-size check
- // on the public-key side. The parsed key itself is discarded; Decrypt
- // re-parses (cheap relative to ML-KEM decapsulation) for code simplicity.
- ecPriv, err := x509.ParseECPrivateKey(privateKey[mlkemSeedSize:])
+ mlkemSeed := privateKeyRaw[:mlkemSeedSize]
+ ecPrivDER := privateKeyRaw[mlkemSeedSize:]
+
+ mlkemCT := ct[:p.mlkemCtSize]
+ ephemeralPubBytes := ct[p.mlkemCtSize:]
+
+ ecdsaPriv, err := x509.ParseECPrivateKey(ecPrivDER)
if err != nil {
- return nil, fmt.Errorf("invalid %s private key: parse ECPrivateKey: %w", p.keyType, err)
+ return nil, fmt.Errorf("parse ECPrivateKey: %w", err)
}
- if ecPriv.Curve != p.namedCurve {
- return nil, fmt.Errorf("invalid %s private key: EC curve mismatch", p.keyType)
+ if ecdsaPriv.Curve != p.namedCurve {
+ return nil, fmt.Errorf("EC private key curve mismatch for %s", p.keyType)
}
- return &HybridNISTDecryptor{
- privateKey: append([]byte(nil), privateKey...),
- params: p,
- }, nil
-}
-
-func (d *HybridNISTDecryptor) Decrypt(data []byte) ([]byte, error) {
- return hybridNISTUnwrapDEK(d.params, d.privateKey, data)
-}
+ ecdhPriv, err := ecdsaPriv.ECDH()
+ if err != nil {
+ return nil, fmt.Errorf("convert ECDSA to ECDH: %w", err)
+ }
+ tradPK := ecdhPriv.PublicKey().Bytes()
-// KeyType identifies the hybrid scheme so KAS-layer callers can cross-check
-// the OID-routed decryptor against an asserted algorithm before trusting it.
-func (d *HybridNISTDecryptor) KeyType() KeyType {
- return d.params.keyType
-}
+ ephemeralPub, err := p.curve.NewPublicKey(ephemeralPubBytes)
+ if err != nil {
+ return nil, fmt.Errorf("invalid ephemeral EC public key: %w", err)
+ }
+ tradSS, err := ecdhPriv.ECDH(ephemeralPub)
+ if err != nil {
+ return nil, fmt.Errorf("ECDH failed: %w", err)
+ }
-func P256MLKEM768WrapDEK(publicKeyRaw, dek []byte) ([]byte, error) {
- return hybridNISTWrapDEK(&p256mlkem768Params, publicKeyRaw, dek)
-}
+ // ML-KEM implicit rejection (FIPS 203 §6.3) yields a pseudorandom shared
+ // secret on a wrong-key ciphertext rather than an error here; the AES-GCM
+ // decrypt in unwrapDEKWithKEM provides authentication.
+ mlkemSS, err := mlkemDecapsulate(p, mlkemSeed, mlkemCT)
+ if err != nil {
+ return nil, fmt.Errorf("ML-KEM decapsulate failed: %w", err)
+ }
-func P256MLKEM768UnwrapDEK(privateKeyRaw, wrappedDER []byte) ([]byte, error) {
- return hybridNISTUnwrapDEK(&p256mlkem768Params, privateKeyRaw, wrappedDER)
+ return hybridNISTCombiner(p, mlkemSS, tradSS, ephemeralPubBytes, tradPK), nil
}
-func P384MLKEM1024WrapDEK(publicKeyRaw, dek []byte) ([]byte, error) {
- return hybridNISTWrapDEK(&p384mlkem1024Params, publicKeyRaw, dek)
+func (k hybridNISTKEM) publicKeyPEM(pub []byte) (string, error) {
+ der, err := marshalHybridSPKI(k.params.oid, pub)
+ if err != nil {
+ return "", err
+ }
+ return string(pem.EncodeToMemory(&pem.Block{Type: pemBlockPublicKey, Bytes: der})), nil
}
-func P384MLKEM1024UnwrapDEK(privateKeyRaw, wrappedDER []byte) ([]byte, error) {
- return hybridNISTUnwrapDEK(&p384mlkem1024Params, privateKeyRaw, wrappedDER)
+// wrapKey is an identity pass-through: encapsulate / decapsulate already ran the
+// SHA3-256 combiner, which emits the 32-byte AES-256 key directly (no extra KDF
+// per draft-14 §3.4). The length check guards against a combiner change.
+func (hybridNISTKEM) wrapKey(sharedSecret, _ /*salt*/, _ /*info*/ []byte) ([]byte, error) {
+ if len(sharedSecret) != kemWrapKeySize {
+ return nil, fmt.Errorf("invalid hybrid NIST wrap key size: got %d want %d", len(sharedSecret), kemWrapKeySize)
+ }
+ return append([]byte(nil), sharedSecret...), nil
}
// hybridNISTCombiner returns the 32-byte SHA3-256 digest defined in
@@ -382,124 +397,3 @@ func mlkemDecapsulate(p *hybridNISTParams, mlkemSeed, mlkemCT []byte) ([]byte, e
return nil, fmt.Errorf("unsupported ML-KEM key type: %s", p.keyType)
}
}
-
-func hybridNISTWrapDEK(p *hybridNISTParams, publicKeyRaw, dek []byte) ([]byte, error) {
- expectedPubSize := p.mlkemPubSize + p.ecPubSize
- if len(publicKeyRaw) != expectedPubSize {
- return nil, fmt.Errorf("invalid %s public key size: got %d want %d", p.keyType, len(publicKeyRaw), expectedPubSize)
- }
-
- mlkemPubBytes := publicKeyRaw[:p.mlkemPubSize]
- ecPubBytes := publicKeyRaw[p.mlkemPubSize:]
-
- ecPub, err := p.curve.NewPublicKey(ecPubBytes)
- if err != nil {
- return nil, fmt.Errorf("invalid EC public key: %w", err)
- }
- ephemeral, err := p.curve.GenerateKey(rand.Reader)
- if err != nil {
- return nil, fmt.Errorf("ECDH ephemeral key generation failed: %w", err)
- }
- tradSS, err := ephemeral.ECDH(ecPub)
- if err != nil {
- return nil, fmt.Errorf("ECDH failed: %w", err)
- }
- ephemeralPub := ephemeral.PublicKey().Bytes()
-
- mlkemSS, mlkemCT, err := mlkemEncapsulate(p, mlkemPubBytes)
- if err != nil {
- return nil, err
- }
-
- wrapKey := hybridNISTCombiner(p, mlkemSS, tradSS, ephemeralPub, ecPubBytes)
-
- hybridCt := make([]byte, 0, len(mlkemCT)+len(ephemeralPub))
- hybridCt = append(hybridCt, mlkemCT...)
- hybridCt = append(hybridCt, ephemeralPub...)
-
- gcm, err := NewAESGcm(wrapKey)
- if err != nil {
- return nil, fmt.Errorf("NewAESGcm failed: %w", err)
- }
- encryptedDEK, err := gcm.Encrypt(dek)
- if err != nil {
- return nil, fmt.Errorf("AES-GCM encrypt failed: %w", err)
- }
-
- wrappedDER, err := asn1.Marshal(HybridNISTWrappedKey{
- HybridCiphertext: hybridCt,
- EncryptedDEK: encryptedDEK,
- })
- if err != nil {
- return nil, fmt.Errorf("asn1.Marshal failed: %w", err)
- }
- return wrappedDER, nil
-}
-
-func hybridNISTUnwrapDEK(p *hybridNISTParams, privateKeyRaw, wrappedDER []byte) ([]byte, error) {
- if len(privateKeyRaw) <= mlkemSeedSize {
- return nil, fmt.Errorf("invalid %s private key: shorter than ML-KEM seed + ECPrivateKey", p.keyType)
- }
- mlkemSeed := privateKeyRaw[:mlkemSeedSize]
- ecPrivDER := privateKeyRaw[mlkemSeedSize:]
-
- var wrapped HybridNISTWrappedKey
- rest, err := asn1.Unmarshal(wrappedDER, &wrapped)
- if err != nil {
- return nil, fmt.Errorf("asn1.Unmarshal failed: %w", err)
- }
- if len(rest) != 0 {
- return nil, fmt.Errorf("asn1.Unmarshal left %d trailing bytes", len(rest))
- }
-
- expectedCtSize := p.mlkemCtSize + p.ecPubSize
- if len(wrapped.HybridCiphertext) != expectedCtSize {
- return nil, fmt.Errorf("invalid %s ciphertext size: got %d want %d",
- p.keyType, len(wrapped.HybridCiphertext), expectedCtSize)
- }
-
- mlkemCT := wrapped.HybridCiphertext[:p.mlkemCtSize]
- ephemeralPubBytes := wrapped.HybridCiphertext[p.mlkemCtSize:]
-
- ecdsaPriv, err := x509.ParseECPrivateKey(ecPrivDER)
- if err != nil {
- return nil, fmt.Errorf("parse ECPrivateKey: %w", err)
- }
- if ecdsaPriv.Curve != p.namedCurve {
- return nil, fmt.Errorf("EC private key curve mismatch for %s", p.keyType)
- }
- ecdhPriv, err := ecdsaPriv.ECDH()
- if err != nil {
- return nil, fmt.Errorf("convert ECDSA to ECDH: %w", err)
- }
- tradPK := ecdhPriv.PublicKey().Bytes()
-
- ephemeralPub, err := p.curve.NewPublicKey(ephemeralPubBytes)
- if err != nil {
- return nil, fmt.Errorf("invalid ephemeral EC public key: %w", err)
- }
- tradSS, err := ecdhPriv.ECDH(ephemeralPub)
- if err != nil {
- return nil, fmt.Errorf("ECDH failed: %w", err)
- }
-
- // ML-KEM implicit rejection (FIPS 203 §6.3) yields a pseudorandom shared
- // secret on a wrong-key ciphertext rather than an error here; the AES-GCM
- // decrypt below provides authentication.
- mlkemSS, err := mlkemDecapsulate(p, mlkemSeed, mlkemCT)
- if err != nil {
- return nil, fmt.Errorf("ML-KEM decapsulate failed: %w", err)
- }
-
- wrapKey := hybridNISTCombiner(p, mlkemSS, tradSS, ephemeralPubBytes, tradPK)
-
- gcm, err := NewAESGcm(wrapKey)
- if err != nil {
- return nil, fmt.Errorf("NewAESGcm failed: %w", err)
- }
- plaintext, err := gcm.Decrypt(wrapped.EncryptedDEK)
- if err != nil {
- return nil, fmt.Errorf("AES-GCM decrypt failed: %w", err)
- }
- return plaintext, nil
-}
diff --git a/lib/ocrypto/hybrid_nist_test.go b/lib/ocrypto/hybrid_nist_test.go
index bc9e238f56..bff6def4a7 100644
--- a/lib/ocrypto/hybrid_nist_test.go
+++ b/lib/ocrypto/hybrid_nist_test.go
@@ -75,10 +75,10 @@ func TestP256MLKEM768WrapUnwrapRoundTrip(t *testing.T) {
require.NoError(t, err)
dek := []byte("0123456789abcdef0123456789abcdef")
- wrapped, err := P256MLKEM768WrapDEK(keyPair.publicKey, dek)
+ wrapped, err := wrapDEKWithKEM(hybridNISTKEM{params: &p256mlkem768Params}, keyPair.publicKey, dek, nil, nil)
require.NoError(t, err)
- plaintext, err := P256MLKEM768UnwrapDEK(keyPair.privateKey, wrapped)
+ plaintext, err := unwrapDEKWithKEM(hybridNISTKEM{params: &p256mlkem768Params}, keyPair.privateKey, wrapped, nil, nil)
require.NoError(t, err)
assert.Equal(t, dek, plaintext)
}
@@ -88,10 +88,10 @@ func TestP384MLKEM1024WrapUnwrapRoundTrip(t *testing.T) {
require.NoError(t, err)
dek := []byte("0123456789abcdef0123456789abcdef")
- wrapped, err := P384MLKEM1024WrapDEK(keyPair.publicKey, dek)
+ wrapped, err := wrapDEKWithKEM(hybridNISTKEM{params: &p384mlkem1024Params}, keyPair.publicKey, dek, nil, nil)
require.NoError(t, err)
- plaintext, err := P384MLKEM1024UnwrapDEK(keyPair.privateKey, wrapped)
+ plaintext, err := unwrapDEKWithKEM(hybridNISTKEM{params: &p384mlkem1024Params}, keyPair.privateKey, wrapped, nil, nil)
require.NoError(t, err)
assert.Equal(t, dek, plaintext)
}
@@ -102,10 +102,10 @@ func TestP256MLKEM768WrapUnwrapWrongKeyFails(t *testing.T) {
wrongKeyPair, err := NewP256MLKEM768KeyPair()
require.NoError(t, err)
- wrapped, err := P256MLKEM768WrapDEK(keyPair.publicKey, []byte("top secret dek"))
+ wrapped, err := wrapDEKWithKEM(hybridNISTKEM{params: &p256mlkem768Params}, keyPair.publicKey, []byte("top secret dek"), nil, nil)
require.NoError(t, err)
- _, err = P256MLKEM768UnwrapDEK(wrongKeyPair.privateKey, wrapped)
+ _, err = unwrapDEKWithKEM(hybridNISTKEM{params: &p256mlkem768Params}, wrongKeyPair.privateKey, wrapped, nil, nil)
require.Error(t, err)
// Wrong-key failure must surface through AES-GCM authentication, not a
// parse/size mismatch — ML-KEM uses implicit rejection so DecapsulateTo
@@ -119,30 +119,14 @@ func TestP384MLKEM1024WrapUnwrapWrongKeyFails(t *testing.T) {
wrongKeyPair, err := NewP384MLKEM1024KeyPair()
require.NoError(t, err)
- wrapped, err := P384MLKEM1024WrapDEK(keyPair.publicKey, []byte("top secret dek"))
+ wrapped, err := wrapDEKWithKEM(hybridNISTKEM{params: &p384mlkem1024Params}, keyPair.publicKey, []byte("top secret dek"), nil, nil)
require.NoError(t, err)
- _, err = P384MLKEM1024UnwrapDEK(wrongKeyPair.privateKey, wrapped)
+ _, err = unwrapDEKWithKEM(hybridNISTKEM{params: &p384mlkem1024Params}, wrongKeyPair.privateKey, wrapped, nil, nil)
require.Error(t, err)
assert.ErrorContains(t, err, "AES-GCM decrypt failed")
}
-func TestHybridNISTWrappedKeyASN1RoundTrip(t *testing.T) {
- original := HybridNISTWrappedKey{
- HybridCiphertext: []byte("hybrid-ciphertext-data"),
- EncryptedDEK: []byte("encrypted-dek-data"),
- }
-
- der, err := asn1.Marshal(original)
- require.NoError(t, err)
-
- var decoded HybridNISTWrappedKey
- rest, err := asn1.Unmarshal(der, &decoded)
- require.NoError(t, err)
- assert.Empty(t, rest)
- assert.Equal(t, original, decoded)
-}
-
func TestP256MLKEM768PEMDispatch(t *testing.T) {
keyPair, err := NewP256MLKEM768KeyPair()
require.NoError(t, err)
@@ -158,7 +142,7 @@ func TestP256MLKEM768PEMDispatch(t *testing.T) {
decryptor, err := FromPrivatePEM(privatePEM)
require.NoError(t, err)
- nistEncryptor, ok := encryptor.(*HybridNISTEncryptor)
+ nistEncryptor, ok := encryptor.(*kemEncryptor)
require.True(t, ok)
assert.Equal(t, Hybrid, nistEncryptor.Type())
assert.Equal(t, HybridSecp256r1MLKEM768Key, nistEncryptor.KeyType())
@@ -168,7 +152,7 @@ func TestP256MLKEM768PEMDispatch(t *testing.T) {
require.NoError(t, err)
assert.Empty(t, metadata)
- nistDecryptor, ok := decryptor.(*HybridNISTDecryptor)
+ nistDecryptor, ok := decryptor.(*kemDecryptor)
require.True(t, ok)
wrapped, err := nistEncryptor.Encrypt([]byte("dispatch-dek"))
@@ -194,13 +178,13 @@ func TestP384MLKEM1024PEMDispatch(t *testing.T) {
decryptor, err := FromPrivatePEM(privatePEM)
require.NoError(t, err)
- nistEncryptor, ok := encryptor.(*HybridNISTEncryptor)
+ nistEncryptor, ok := encryptor.(*kemEncryptor)
require.True(t, ok)
assert.Equal(t, Hybrid, nistEncryptor.Type())
assert.Equal(t, HybridSecp384r1MLKEM1024Key, nistEncryptor.KeyType())
assert.Nil(t, nistEncryptor.EphemeralKey())
- nistDecryptor, ok := decryptor.(*HybridNISTDecryptor)
+ nistDecryptor, ok := decryptor.(*kemDecryptor)
require.True(t, ok)
wrapped, err := nistEncryptor.Encrypt([]byte("dispatch-dek-384"))
diff --git a/lib/ocrypto/kem.go b/lib/ocrypto/kem.go
new file mode 100644
index 0000000000..d86a49e448
--- /dev/null
+++ b/lib/ocrypto/kem.go
@@ -0,0 +1,373 @@
+package ocrypto
+
+import (
+ "crypto/mlkem"
+ "encoding/asn1"
+ "encoding/pem"
+ "fmt"
+)
+
+// kem is the post-quantum KEM contract implemented by every KEM family: the
+// pure ML-KEM schemes and the IETF-draft hybrid PQ/T schemes (X-Wing and the
+// NIST EC + ML-KEM composites). Each family is adapted onto this interface
+// (mlkemKEM, xwingKEM, hybridNISTKEM) and they all share one envelope, one
+// AES-GCM call site, and the unified kemEncryptor / kemDecryptor types, reached
+// via the OID-routed dispatcher in asym_encryption.go / asym_decryption.go.
+// The wrap-key derivation still differs per family; see wrapKey below.
+type kem interface {
+ keyType() KeyType
+ scheme() SchemeType
+ pubSize() int
+ privSize() int
+ ctSize() int
+ encapsulate(pub []byte) (sharedSecret, ciphertext []byte, err error)
+ decapsulate(priv, ct []byte) (sharedSecret []byte, err error)
+ // publicKeyPEM returns the PEM serialization for the given raw public key.
+ // Each adapter handles its own format. After the planned follow-up moves
+ // X-Wing and the NIST hybrid keys onto standard SPKI PEM blocks this
+ // per-adapter hook collapses to a single shared helper.
+ publicKeyPEM(pub []byte) (string, error)
+ // wrapKey returns the AES-256 key used to seal the DEK from the
+ // shared secret produced by encapsulate / decapsulate.
+ //
+ // ML-KEM returns the 32-byte Decaps output verbatim (no KDF) so that an
+ // HSM-backed KAS holding the shared secret as a CKK_AES, non-extractable
+ // object can perform AES-GCM directly. See FIPS 203 §6.3 / §7.3 and
+ // adr/decisions/2026-06-16-mlkem-direct-key-wrap.md.
+ //
+ // Hybrid PQ/T schemes (X-Wing, NIST EC + ML-KEM) concatenate two
+ // shared-secret halves and still require HKDF-SHA256 over (salt, info)
+ // for proper combiner hygiene.
+ wrapKey(sharedSecret, salt, info []byte) ([]byte, error)
+}
+
+// kemEnvelope is the ASN.1 wire format for every KEM-wrapped DEK across
+// `hybrid-wrapped` and `mlkem-wrapped` KAOs. It is byte-identical to the three
+// legacy structs (MLKEMWrappedKey, XWingWrappedKey, HybridNISTWrappedKey) it
+// replaces — same tags, same field order.
+type kemEnvelope struct {
+ KEMCiphertext []byte `asn1:"tag:0"`
+ EncryptedDEK []byte `asn1:"tag:1"`
+}
+
+// kemWrapKeySize is the AES-256 wrap key length. Pure ML-KEM uses the
+// 32-byte Decaps output directly; hybrid PQ/T schemes derive it via
+// HKDF-SHA256 over the combined shared secret.
+const kemWrapKeySize = 32
+
+// kemRegistry maps the SPKI/PKCS#8 OID published for a KEM scheme to a
+// constructor that returns a kem adapter bound to that scheme. ML-KEM is the
+// only family with standardized OIDs landed today; the planned hybrid PQ/T
+// SPKI follow-up adds X-Wing and the two NIST hybrid OIDs by inserting
+// registry entries here.
+var kemRegistry = map[string]func() kem{
+ OIDMLKEM768.String(): func() kem { return mlkemKEM{variant: mlkem768} },
+ OIDMLKEM1024.String(): func() kem { return mlkemKEM{variant: mlkem1024} },
+}
+
+// kemByOID returns the kem adapter registered for the supplied OID, or false
+// if the OID is not a recognised KEM algorithm.
+func kemByOID(oid asn1.ObjectIdentifier) (kem, bool) {
+ ctor, ok := kemRegistry[oid.String()]
+ if !ok {
+ return nil, false
+ }
+ return ctor(), true
+}
+
+// hybridKEMByOID returns the hybrid PQ/T kem adapter for the supplied
+// AlgorithmIdentifier OID. The hybrid schemes are kept out of kemRegistry
+// because their PKCS#8 private-key encoding differs from the RFC 5958 KEM
+// CHOICE that parseKEMPrivatePKCS8 expects (X-Wing/NIST store the raw key
+// directly, ML-KEM double-wraps the seed in a [0] IMPLICIT OCTET STRING).
+// The OID-routing dispatchers in asym_encryption.go / asym_decryption.go use
+// this helper to build kemEncryptor / kemDecryptor for hybrid keys.
+func hybridKEMByOID(oid asn1.ObjectIdentifier) (kem, bool) {
+ switch {
+ case oid.Equal(oidXWing):
+ return xwingKEM{}, true
+ case oid.Equal(oidCompositeMLKEM768P256):
+ return hybridNISTKEM{params: &p256mlkem768Params}, true
+ case oid.Equal(oidCompositeMLKEM1024P384):
+ return hybridNISTKEM{params: &p384mlkem1024Params}, true
+ default:
+ return nil, false
+ }
+}
+
+// IsKEMKeyType reports whether the supplied KeyType is one of the KEM schemes
+// — pure ML-KEM or hybrid PQ/T — that wrap a DEK through FromPublicPEM /
+// FromPrivatePEM rather than the RSA/EC paths. Callers use it as the routing
+// gate before delegating to WrapDEK.
+func IsKEMKeyType(kt KeyType) bool {
+ return IsMLKEMKeyType(kt) || IsHybridKeyType(kt)
+}
+
+// --- mlkemKEM adapter -------------------------------------------------------
+
+type mlkemVariant int
+
+const (
+ mlkem768 mlkemVariant = iota
+ mlkem1024
+)
+
+type mlkemKEM struct {
+ variant mlkemVariant
+}
+
+func (m mlkemKEM) keyType() KeyType {
+ if m.variant == mlkem1024 {
+ return MLKEM1024Key
+ }
+ return MLKEM768Key
+}
+
+func (mlkemKEM) scheme() SchemeType { return MLKEM }
+
+func (m mlkemKEM) pubSize() int {
+ if m.variant == mlkem1024 {
+ return MLKEM1024PublicKeySize
+ }
+ return MLKEM768PublicKeySize
+}
+
+func (m mlkemKEM) privSize() int {
+ if m.variant == mlkem1024 {
+ return MLKEM1024PrivateKeySize
+ }
+ return MLKEM768PrivateKeySize
+}
+
+func (m mlkemKEM) ctSize() int {
+ if m.variant == mlkem1024 {
+ return MLKEM1024CiphertextSize
+ }
+ return MLKEM768CiphertextSize
+}
+
+func (m mlkemKEM) encapsulate(pub []byte) ([]byte, []byte, error) {
+ if len(pub) != m.pubSize() {
+ return nil, nil, fmt.Errorf("invalid %s public key size: got %d want %d", m.keyType(), len(pub), m.pubSize())
+ }
+ if m.variant == mlkem1024 {
+ ek, err := mlkem.NewEncapsulationKey1024(pub)
+ if err != nil {
+ return nil, nil, fmt.Errorf("mlkem.NewEncapsulationKey1024 failed: %w", err)
+ }
+ ss, ct := ek.Encapsulate()
+ return ss, ct, nil
+ }
+ ek, err := mlkem.NewEncapsulationKey768(pub)
+ if err != nil {
+ return nil, nil, fmt.Errorf("mlkem.NewEncapsulationKey768 failed: %w", err)
+ }
+ ss, ct := ek.Encapsulate()
+ return ss, ct, nil
+}
+
+func (m mlkemKEM) decapsulate(priv, ct []byte) ([]byte, error) {
+ if len(priv) != m.privSize() {
+ return nil, fmt.Errorf("invalid %s private key size: got %d want %d", m.keyType(), len(priv), m.privSize())
+ }
+ if m.variant == mlkem1024 {
+ dk, err := mlkem.NewDecapsulationKey1024(priv)
+ if err != nil {
+ return nil, fmt.Errorf("mlkem.NewDecapsulationKey1024 failed: %w", err)
+ }
+ ss, err := dk.Decapsulate(ct)
+ if err != nil {
+ return nil, fmt.Errorf("mlkem1024 decapsulate failed: %w", err)
+ }
+ return ss, nil
+ }
+ dk, err := mlkem.NewDecapsulationKey768(priv)
+ if err != nil {
+ return nil, fmt.Errorf("mlkem.NewDecapsulationKey768 failed: %w", err)
+ }
+ ss, err := dk.Decapsulate(ct)
+ if err != nil {
+ return nil, fmt.Errorf("mlkem768 decapsulate failed: %w", err)
+ }
+ return ss, nil
+}
+
+func (m mlkemKEM) publicKeyPEM(pub []byte) (string, error) {
+ oid := OIDMLKEM768
+ if m.variant == mlkem1024 {
+ oid = OIDMLKEM1024
+ }
+ der, err := marshalKEMPublicSPKI(oid, pub)
+ if err != nil {
+ return "", fmt.Errorf("marshal %s SPKI failed: %w", m.keyType(), err)
+ }
+ return string(pem.EncodeToMemory(&pem.Block{Type: pemBlockPublicKey, Bytes: der})), nil
+}
+
+// wrapKey returns the ML-KEM Decaps output directly as the AES-256 wrap key.
+//
+// FIPS 203 §6.3 / §7.3 specify that ML-KEM Decaps emits a uniformly random
+// 32-byte shared secret K that is suitable for direct use as a symmetric key,
+// and ML-KEM produces a fresh K per encapsulation by construction. salt and
+// info are ignored on purpose so that HSM-backed KAS providers that can only
+// materialize the shared secret as a non-extractable CKK_AES object (e.g.
+// Thales Luna T-Series 7.15.1 in strict-FIPS mode, which rejects HMAC over
+// the Decaps output with CKR_ATTRIBUTE_TYPE_INVALID) can still complete
+// AES-GCM unwrap without an HKDF step.
+func (mlkemKEM) wrapKey(sharedSecret, _ /*salt*/, _ /*info*/ []byte) ([]byte, error) {
+ if len(sharedSecret) != kemWrapKeySize {
+ return nil, fmt.Errorf("invalid ML-KEM shared secret size: got %d want %d", len(sharedSecret), kemWrapKeySize)
+ }
+ return append([]byte(nil), sharedSecret...), nil
+}
+
+// --- wrap / unwrap ----------------------------------------------------------
+
+// wrapDEKWithKEM encapsulates against pub, asks the scheme adapter for an
+// AES-256 wrap key (HKDF for hybrid PQ/T, direct shared-secret for pure
+// ML-KEM), and emits the kemEnvelope ASN.1 DER blob carrying (KEM
+// ciphertext, AES-GCM-encrypted DEK).
+func wrapDEKWithKEM(k kem, pub, dek, salt, info []byte) ([]byte, error) {
+ sharedSecret, ciphertext, err := k.encapsulate(pub)
+ if err != nil {
+ return nil, err
+ }
+
+ wrapKey, err := k.wrapKey(sharedSecret, salt, info)
+ if err != nil {
+ return nil, err
+ }
+
+ gcm, err := NewAESGcm(wrapKey)
+ if err != nil {
+ return nil, fmt.Errorf("NewAESGcm failed: %w", err)
+ }
+
+ encryptedDEK, err := gcm.Encrypt(dek)
+ if err != nil {
+ return nil, fmt.Errorf("AES-GCM encrypt failed: %w", err)
+ }
+
+ wrappedDER, err := asn1.Marshal(kemEnvelope{
+ KEMCiphertext: ciphertext,
+ EncryptedDEK: encryptedDEK,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("asn1.Marshal failed: %w", err)
+ }
+
+ return wrappedDER, nil
+}
+
+// unwrapDEKWithKEM parses the kemEnvelope DER blob, decapsulates with priv to
+// recover the shared secret, asks the scheme adapter for the matching AES-256
+// wrap key, and AES-GCM decrypts the DEK.
+func unwrapDEKWithKEM(k kem, priv, der, salt, info []byte) ([]byte, error) {
+ var env kemEnvelope
+ rest, err := asn1.Unmarshal(der, &env)
+ if err != nil {
+ return nil, fmt.Errorf("asn1.Unmarshal failed: %w", err)
+ }
+ if len(rest) != 0 {
+ return nil, fmt.Errorf("asn1.Unmarshal left %d trailing bytes", len(rest))
+ }
+ if len(env.KEMCiphertext) != k.ctSize() {
+ return nil, fmt.Errorf("invalid %s ciphertext size: got %d want %d", k.keyType(), len(env.KEMCiphertext), k.ctSize())
+ }
+
+ sharedSecret, err := k.decapsulate(priv, env.KEMCiphertext)
+ if err != nil {
+ return nil, err
+ }
+
+ wrapKey, err := k.wrapKey(sharedSecret, salt, info)
+ if err != nil {
+ return nil, err
+ }
+
+ gcm, err := NewAESGcm(wrapKey)
+ if err != nil {
+ return nil, fmt.Errorf("NewAESGcm failed: %w", err)
+ }
+
+ plaintext, err := gcm.Decrypt(env.EncryptedDEK)
+ if err != nil {
+ return nil, fmt.Errorf("AES-GCM decrypt failed: %w", err)
+ }
+
+ return plaintext, nil
+}
+
+// --- unified encryptor / decryptor ------------------------------------------
+
+// kemEncryptor satisfies PublicKeyEncryptor for every KEM family. It replaces
+// the per-variant MLKEMEncryptor*, XWingEncryptor, and HybridNISTEncryptor
+// types behind the FromPublicPEM factory.
+type kemEncryptor struct {
+ k kem
+ publicKey []byte
+ salt []byte
+ info []byte
+}
+
+func newKEMEncryptor(k kem, publicKey, salt, info []byte) (*kemEncryptor, error) {
+ if len(publicKey) != k.pubSize() {
+ return nil, fmt.Errorf("invalid %s public key size: got %d want %d", k.keyType(), len(publicKey), k.pubSize())
+ }
+ return &kemEncryptor{
+ k: k,
+ publicKey: append([]byte(nil), publicKey...),
+ salt: cloneOrNil(salt),
+ info: cloneOrNil(info),
+ }, nil
+}
+
+func (e *kemEncryptor) Encrypt(data []byte) ([]byte, error) {
+ return wrapDEKWithKEM(e.k, e.publicKey, data, e.salt, e.info)
+}
+
+func (e *kemEncryptor) PublicKeyInPemFormat() (string, error) {
+ return e.k.publicKeyPEM(e.publicKey)
+}
+
+func (e *kemEncryptor) Type() SchemeType { return e.k.scheme() }
+func (e *kemEncryptor) KeyType() KeyType { return e.k.keyType() }
+func (e *kemEncryptor) EphemeralKey() []byte { return nil }
+
+func (e *kemEncryptor) Metadata() (map[string]string, error) {
+ return make(map[string]string), nil
+}
+
+// kemDecryptor satisfies PrivateKeyDecryptor for every KEM family. It replaces
+// the per-variant MLKEMDecryptor*, XWingDecryptor, and HybridNISTDecryptor
+// types behind the FromPrivatePEM factory.
+type kemDecryptor struct {
+ k kem
+ privateKey []byte
+ salt []byte
+ info []byte
+}
+
+func newKEMDecryptor(k kem, privateKey, salt, info []byte) (*kemDecryptor, error) {
+ // A negative privSize signals a variable-length encoding (the NIST hybrid's
+ // mlkemSeed||ECPrivateKey DER), whose exact length is validated inside
+ // decapsulate. Fixed-size schemes (ML-KEM, X-Wing) keep the strict check.
+ if k.privSize() >= 0 && len(privateKey) != k.privSize() {
+ return nil, fmt.Errorf("invalid %s private key size: got %d want %d", k.keyType(), len(privateKey), k.privSize())
+ }
+ return &kemDecryptor{
+ k: k,
+ privateKey: append([]byte(nil), privateKey...),
+ salt: cloneOrNil(salt),
+ info: cloneOrNil(info),
+ }, nil
+}
+
+func (d *kemDecryptor) Decrypt(data []byte) ([]byte, error) {
+ return unwrapDEKWithKEM(d.k, d.privateKey, data, d.salt, d.info)
+}
+
+// KeyType reports the KEM scheme this decryptor was built for. It lets callers
+// (e.g. the service layer's assertDecryptorAlgorithm guard) confirm that a PEM
+// dispatched to the scheme they expected.
+func (d *kemDecryptor) KeyType() KeyType { return d.k.keyType() }
diff --git a/lib/ocrypto/key_type.go b/lib/ocrypto/key_type.go
new file mode 100644
index 0000000000..cb050c7ff0
--- /dev/null
+++ b/lib/ocrypto/key_type.go
@@ -0,0 +1,85 @@
+package ocrypto
+
+import "fmt"
+
+type KeyType string
+
+const (
+ RSA2048Key KeyType = "rsa:2048"
+ RSA4096Key KeyType = "rsa:4096"
+ EC256Key KeyType = "ec:secp256r1"
+ EC384Key KeyType = "ec:secp384r1"
+ EC521Key KeyType = "ec:secp521r1"
+ MLKEM768Key KeyType = "mlkem:768"
+ MLKEM1024Key KeyType = "mlkem:1024"
+)
+
+const (
+ RSA2048Size = 2048
+ RSA4096Size = 4096
+)
+
+// ParseKeyType validates a string as a known KeyType, returning an error for
+// unrecognized values.
+func ParseKeyType(alg string) (KeyType, error) {
+ switch KeyType(alg) {
+ case RSA2048Key, RSA4096Key,
+ EC256Key, EC384Key, EC521Key,
+ MLKEM768Key, MLKEM1024Key,
+ HybridXWingKey, HybridSecp256r1MLKEM768Key, HybridSecp384r1MLKEM1024Key:
+ return KeyType(alg), nil
+ default:
+ return "", fmt.Errorf("unrecognized key type: %s", alg)
+ }
+}
+
+func IsECKeyType(kt KeyType) bool {
+ switch kt { //nolint:exhaustive // only handle ec types
+ case EC256Key, EC384Key, EC521Key:
+ return true
+ default:
+ return false
+ }
+}
+
+func IsRSAKeyType(kt KeyType) bool {
+ switch kt { //nolint:exhaustive // only handle rsa types
+ case RSA2048Key, RSA4096Key:
+ return true
+ default:
+ return false
+ }
+}
+
+func IsMLKEMKeyType(kt KeyType) bool {
+ switch kt { //nolint:exhaustive // only handle mlkem types
+ case MLKEM768Key, MLKEM1024Key:
+ return true
+ default:
+ return false
+ }
+}
+
+func ECKeyTypeToMode(kt KeyType) (ECCMode, error) {
+ switch kt { //nolint:exhaustive // only handle ec types
+ case EC256Key:
+ return ECCModeSecp256r1, nil
+ case EC384Key:
+ return ECCModeSecp384r1, nil
+ case EC521Key:
+ return ECCModeSecp521r1, nil
+ default:
+ return 0, fmt.Errorf("unsupported type: %v", kt)
+ }
+}
+
+func RSAKeyTypeToBits(kt KeyType) (int, error) {
+ switch kt { //nolint:exhaustive // only handle rsa types
+ case RSA2048Key:
+ return RSA2048Size, nil
+ case RSA4096Key:
+ return RSA4096Size, nil
+ default:
+ return 0, fmt.Errorf("unsupported type: %v", kt)
+ }
+}
diff --git a/lib/ocrypto/mlkem.go b/lib/ocrypto/mlkem.go
new file mode 100644
index 0000000000..eccb2431bf
--- /dev/null
+++ b/lib/ocrypto/mlkem.go
@@ -0,0 +1,106 @@
+package ocrypto
+
+import (
+ "encoding/asn1"
+ "errors"
+ "fmt"
+)
+
+// errNotKEM is returned by the generic SPKI / PKCS#8 KEM parsers when the
+// supplied DER blob is not a recognised KEM algorithm, signalling the caller
+// to fall through to other algorithm parsers.
+var errNotKEM = errors.New("not a recognised KEM key")
+
+const (
+ MLKEM768PublicKeySize = 1184 // mlkem768 encapsulation key
+ MLKEM768PrivateKeySize = 64 // mlkem768 seed (d || z)
+ MLKEM768CiphertextSize = 1088 // mlkem768 ciphertext
+ MLKEM1024PublicKeySize = 1568 // mlkem1024 encapsulation key
+ MLKEM1024PrivateKeySize = 64 // mlkem1024 seed (d || z)
+ MLKEM1024CiphertextSize = 1568 // mlkem1024 ciphertext
+)
+
+// NIST-assigned OIDs for ML-KEM (FIPS 203).
+var (
+ OIDMLKEM768 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 4, 2}
+ OIDMLKEM1024 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 4, 3}
+)
+
+type kemAlgorithmIdentifier struct {
+ Algorithm asn1.ObjectIdentifier
+}
+
+type kemSPKI struct {
+ Algorithm kemAlgorithmIdentifier
+ PublicKey asn1.BitString
+}
+
+// kemPKCS8 mirrors RFC 5958 OneAsymmetricKey v1.
+type kemPKCS8 struct {
+ Version int
+ Algorithm kemAlgorithmIdentifier
+ PrivateKey []byte
+}
+
+// marshalKEMPublicSPKI encodes a raw KEM encapsulation key as RFC 5280
+// SubjectPublicKeyInfo using the supplied algorithm OID.
+func marshalKEMPublicSPKI(oid asn1.ObjectIdentifier, rawKey []byte) ([]byte, error) {
+ return asn1.Marshal(kemSPKI{
+ Algorithm: kemAlgorithmIdentifier{Algorithm: oid},
+ PublicKey: asn1.BitString{Bytes: rawKey, BitLength: len(rawKey) * bitsPerByte},
+ })
+}
+
+// marshalKEMPrivatePKCS8 encodes a raw KEM seed (or private key) as RFC 5958
+// OneAsymmetricKey, with the inner KEM-PrivateKey CHOICE selected as [0]
+// IMPLICIT OCTET STRING.
+func marshalKEMPrivatePKCS8(oid asn1.ObjectIdentifier, rawSeedOrKey []byte) ([]byte, error) {
+ inner, err := asn1.MarshalWithParams(rawSeedOrKey, "tag:0,implicit")
+ if err != nil {
+ return nil, fmt.Errorf("asn1.MarshalWithParams seed failed: %w", err)
+ }
+ return asn1.Marshal(kemPKCS8{
+ Version: 0,
+ Algorithm: kemAlgorithmIdentifier{Algorithm: oid},
+ PrivateKey: inner,
+ })
+}
+
+// ParseKEMPublicSPKI returns the OID and raw encapsulation key bytes from any
+// SPKI DER blob whose AlgorithmIdentifier has no parameters. If the blob is
+// not a well-formed parameter-less SPKI structure the sentinel errNotKEM is
+// returned so the caller can fall through to other parsers.
+func ParseKEMPublicSPKI(der []byte) (asn1.ObjectIdentifier, []byte, error) {
+ var s kemSPKI
+ rest, err := asn1.Unmarshal(der, &s)
+ if err != nil || len(rest) != 0 {
+ return nil, nil, errNotKEM
+ }
+ if s.PublicKey.BitLength%bitsPerByte != 0 {
+ return nil, nil, errors.New("KEM SPKI bit string is not byte-aligned")
+ }
+ return s.Algorithm.Algorithm, s.PublicKey.RightAlign(), nil
+}
+
+// parseKEMPrivatePKCS8 returns the OID and raw seed bytes from any PKCS#8 DER
+// blob whose AlgorithmIdentifier matches a registered KEM scheme and whose
+// inner private key is encoded as [0] IMPLICIT OCTET STRING. The sentinel
+// errNotKEM is returned for any non-KEM PKCS#8 blob so the caller can fall
+// through to other parsers.
+func parseKEMPrivatePKCS8(der []byte) (asn1.ObjectIdentifier, []byte, error) {
+ var p kemPKCS8
+ rest, err := asn1.Unmarshal(der, &p)
+ if err != nil || len(rest) != 0 {
+ return nil, nil, errNotKEM
+ }
+ if _, ok := kemRegistry[p.Algorithm.Algorithm.String()]; !ok {
+ return nil, nil, errNotKEM
+ }
+
+ var innerSeed []byte
+ innerRest, err := asn1.UnmarshalWithParams(p.PrivateKey, &innerSeed, "tag:0,implicit")
+ if err != nil || len(innerRest) != 0 {
+ return nil, nil, fmt.Errorf("KEM PKCS#8 inner seed parse failed: %w", err)
+ }
+ return p.Algorithm.Algorithm, innerSeed, nil
+}
diff --git a/lib/ocrypto/mlkem_test.go b/lib/ocrypto/mlkem_test.go
new file mode 100644
index 0000000000..355317e33b
--- /dev/null
+++ b/lib/ocrypto/mlkem_test.go
@@ -0,0 +1,355 @@
+package ocrypto
+
+import (
+ "encoding/asn1"
+ "encoding/pem"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestMLKEM768WrapUnwrapRoundTrip(t *testing.T) {
+ keyPair, err := NewMLKEMKeyPair()
+ require.NoError(t, err)
+
+ publicKeyBytes := keyPair.PrivateKey.EncapsulationKey().Bytes()
+ privateKeyBytes := keyPair.PrivateKey.Bytes()
+
+ dek := []byte("0123456789abcdef0123456789abcdef")
+ wrapped, err := wrapDEKWithKEM(mlkemKEM{variant: mlkem768}, publicKeyBytes, dek, nil, nil)
+ require.NoError(t, err)
+
+ plaintext, err := unwrapDEKWithKEM(mlkemKEM{variant: mlkem768}, privateKeyBytes, wrapped, nil, nil)
+ require.NoError(t, err)
+ assert.Equal(t, dek, plaintext)
+}
+
+func TestMLKEM1024WrapUnwrapRoundTrip(t *testing.T) {
+ keyPair, err := NewMLKEM1024KeyPair()
+ require.NoError(t, err)
+
+ publicKeyBytes := keyPair.PrivateKey.EncapsulationKey().Bytes()
+ privateKeyBytes := keyPair.PrivateKey.Bytes()
+
+ dek := []byte("0123456789abcdef0123456789abcdef")
+ wrapped, err := wrapDEKWithKEM(mlkemKEM{variant: mlkem1024}, publicKeyBytes, dek, nil, nil)
+ require.NoError(t, err)
+
+ plaintext, err := unwrapDEKWithKEM(mlkemKEM{variant: mlkem1024}, privateKeyBytes, wrapped, nil, nil)
+ require.NoError(t, err)
+ assert.Equal(t, dek, plaintext)
+}
+
+func TestMLKEM768WrapUnwrapWrongKeyFails(t *testing.T) {
+ keyPair1, err := NewMLKEMKeyPair()
+ require.NoError(t, err)
+ keyPair2, err := NewMLKEMKeyPair()
+ require.NoError(t, err)
+
+ publicKey1 := keyPair1.PrivateKey.EncapsulationKey().Bytes()
+ privateKey2 := keyPair2.PrivateKey.Bytes()
+
+ wrapped, err := wrapDEKWithKEM(mlkemKEM{variant: mlkem768}, publicKey1, []byte("top secret dek"), nil, nil)
+ require.NoError(t, err)
+
+ _, err = unwrapDEKWithKEM(mlkemKEM{variant: mlkem768}, privateKey2, wrapped, nil, nil)
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "AES-GCM decrypt failed")
+}
+
+func TestMLKEM1024WrapUnwrapWrongKeyFails(t *testing.T) {
+ keyPair1, err := NewMLKEM1024KeyPair()
+ require.NoError(t, err)
+ keyPair2, err := NewMLKEM1024KeyPair()
+ require.NoError(t, err)
+
+ publicKey1 := keyPair1.PrivateKey.EncapsulationKey().Bytes()
+ privateKey2 := keyPair2.PrivateKey.Bytes()
+
+ wrapped, err := wrapDEKWithKEM(mlkemKEM{variant: mlkem1024}, publicKey1, []byte("top secret dek"), nil, nil)
+ require.NoError(t, err)
+
+ _, err = unwrapDEKWithKEM(mlkemKEM{variant: mlkem1024}, privateKey2, wrapped, nil, nil)
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "AES-GCM decrypt failed")
+}
+
+func TestKEMEnvelopeASN1RoundTrip(t *testing.T) {
+ original := kemEnvelope{
+ KEMCiphertext: []byte("ciphertext"),
+ EncryptedDEK: []byte("encrypted-dek"),
+ }
+
+ der, err := asn1.Marshal(original)
+ require.NoError(t, err)
+
+ var decoded kemEnvelope
+ rest, err := asn1.Unmarshal(der, &decoded)
+ require.NoError(t, err)
+ assert.Empty(t, rest)
+ assert.Equal(t, original, decoded)
+}
+
+func TestMLKEM768CiphertextSizeValidation(t *testing.T) {
+ keyPair, err := NewMLKEMKeyPair()
+ require.NoError(t, err)
+
+ privateKeyBytes := keyPair.PrivateKey.Bytes()
+
+ invalidWrapped := kemEnvelope{
+ KEMCiphertext: []byte("too-short"),
+ EncryptedDEK: []byte("encrypted-dek"),
+ }
+
+ der, err := asn1.Marshal(invalidWrapped)
+ require.NoError(t, err)
+
+ _, err = unwrapDEKWithKEM(mlkemKEM{variant: mlkem768}, privateKeyBytes, der, nil, nil)
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "ciphertext size")
+}
+
+func TestMLKEM1024CiphertextSizeValidation(t *testing.T) {
+ keyPair, err := NewMLKEM1024KeyPair()
+ require.NoError(t, err)
+
+ privateKeyBytes := keyPair.PrivateKey.Bytes()
+
+ invalidWrapped := kemEnvelope{
+ KEMCiphertext: []byte("too-short"),
+ EncryptedDEK: []byte("encrypted-dek"),
+ }
+
+ der, err := asn1.Marshal(invalidWrapped)
+ require.NoError(t, err)
+
+ _, err = unwrapDEKWithKEM(mlkemKEM{variant: mlkem1024}, privateKeyBytes, der, nil, nil)
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "ciphertext size")
+}
+
+// TestMLKEMSaltInfoIgnored verifies that salt/info passed to the ML-KEM
+// encryptor/decryptor are ignored: an envelope produced with one (salt, info)
+// pair must unwrap correctly under a different (salt, info) pair, because pure
+// ML-KEM uses the Decaps shared secret directly as the AES-GCM wrap key.
+func TestMLKEMSaltInfoIgnored(t *testing.T) {
+ keyPair, err := NewMLKEMKeyPair()
+ require.NoError(t, err)
+
+ publicKeyBytes := keyPair.PrivateKey.EncapsulationKey().Bytes()
+ privateKeyBytes := keyPair.PrivateKey.Bytes()
+
+ encryptor, err := newKEMEncryptor(mlkemKEM{variant: mlkem768}, publicKeyBytes, []byte("salt-A"), []byte("info-A"))
+ require.NoError(t, err)
+
+ // Decrypt with deliberately different salt/info; for ML-KEM both must be no-ops.
+ decryptor, err := newKEMDecryptor(mlkemKEM{variant: mlkem768}, privateKeyBytes, []byte("salt-B"), []byte("info-B"))
+ require.NoError(t, err)
+
+ dek := []byte("test-dek-value-123456")
+ wrapped, err := encryptor.Encrypt(dek)
+ require.NoError(t, err)
+
+ plaintext, err := decryptor.Decrypt(wrapped)
+ require.NoError(t, err)
+ assert.Equal(t, dek, plaintext)
+
+ // Also decrypt with nil salt/info to make the contract explicit.
+ bareDecryptor, err := newKEMDecryptor(mlkemKEM{variant: mlkem768}, privateKeyBytes, nil, nil)
+ require.NoError(t, err)
+ plaintextBare, err := bareDecryptor.Decrypt(wrapped)
+ require.NoError(t, err)
+ assert.Equal(t, dek, plaintextBare)
+}
+
+// TestMLKEMSharedSecretIsAESWrapKey verifies that the AES-GCM-encrypted DEK
+// inside an ML-KEM envelope can be opened by AES-256-GCM using the raw 32-byte
+// shared secret produced by Decaps — i.e. there is no KDF between Decaps and
+// the AES-GCM unwrap key. This is the load-bearing assertion for HSM-backed
+// KAS providers that can only materialize the Decaps output as a non-
+// extractable CKK_AES object.
+func TestMLKEMSharedSecretIsAESWrapKey(t *testing.T) {
+ t.Run("MLKEM768", func(t *testing.T) {
+ assertSharedSecretIsAESWrapKey(t, mlkemKEM{variant: mlkem768}, MLKEM768CiphertextSize)
+ })
+ t.Run("MLKEM1024", func(t *testing.T) {
+ assertSharedSecretIsAESWrapKey(t, mlkemKEM{variant: mlkem1024}, MLKEM1024CiphertextSize)
+ })
+}
+
+func assertSharedSecretIsAESWrapKey(t *testing.T, k mlkemKEM, expectedCtSize int) {
+ t.Helper()
+
+ var (
+ pubBytes []byte
+ privBytes []byte
+ )
+ if k.variant == mlkem1024 {
+ kp, err := NewMLKEM1024KeyPair()
+ require.NoError(t, err)
+ pubBytes = kp.PrivateKey.EncapsulationKey().Bytes()
+ privBytes = kp.PrivateKey.Bytes()
+ } else {
+ kp, err := NewMLKEMKeyPair()
+ require.NoError(t, err)
+ pubBytes = kp.PrivateKey.EncapsulationKey().Bytes()
+ privBytes = kp.PrivateKey.Bytes()
+ }
+
+ dek := []byte("0123456789abcdef0123456789abcdef") // 32-byte DEK
+ wrappedDER, err := wrapDEKWithKEM(k, pubBytes, dek, nil, nil)
+ require.NoError(t, err)
+
+ // Parse the envelope to pull out the KEM ciphertext and the
+ // AES-GCM-wrapped DEK independently of unwrapDEKWithKEM.
+ var env kemEnvelope
+ rest, err := asn1.Unmarshal(wrappedDER, &env)
+ require.NoError(t, err)
+ require.Empty(t, rest)
+ require.Len(t, env.KEMCiphertext, expectedCtSize)
+
+ // Reproduce the wrap key the way an HSM-backed KAS would: Decaps then
+ // straight into AES-256-GCM, no KDF.
+ sharedSecret, err := k.decapsulate(privBytes, env.KEMCiphertext)
+ require.NoError(t, err)
+ require.Len(t, sharedSecret, kemWrapKeySize, "FIPS 203 §6.3/§7.3 mandates a 32-byte shared secret")
+
+ gcm, err := NewAESGcm(sharedSecret)
+ require.NoError(t, err)
+ plaintext, err := gcm.Decrypt(env.EncryptedDEK)
+ require.NoError(t, err)
+ assert.Equal(t, dek, plaintext, "AES-GCM with sharedSecret-as-key must recover the DEK")
+
+ // Also verify the symmetric direction: an AES-GCM seal under the shared
+ // secret must be openable by unwrapDEKWithKEM-style code, i.e. the wrap
+ // key on both sides is exactly the Decaps output.
+ sealed, err := gcm.Encrypt(dek)
+ require.NoError(t, err)
+ roundTrip, err := gcm.Decrypt(sealed)
+ require.NoError(t, err)
+ assert.Equal(t, dek, roundTrip)
+}
+
+func TestMLKEMEncryptorImplementsInterface(t *testing.T) {
+ keyPair, err := NewMLKEMKeyPair()
+ require.NoError(t, err)
+
+ publicKeyBytes := keyPair.PrivateKey.EncapsulationKey().Bytes()
+
+ encryptor, err := newKEMEncryptor(mlkemKEM{variant: mlkem768}, publicKeyBytes, nil, nil)
+ require.NoError(t, err)
+
+ assert.Equal(t, MLKEM, encryptor.Type())
+ assert.Equal(t, MLKEM768Key, encryptor.KeyType())
+ assert.Nil(t, encryptor.EphemeralKey())
+
+ metadata, err := encryptor.Metadata()
+ require.NoError(t, err)
+ assert.Empty(t, metadata)
+}
+
+func TestMLKEM768Encapsulate(t *testing.T) {
+ keyPair, err := NewMLKEMKeyPair()
+ require.NoError(t, err)
+
+ publicKeyBytes := keyPair.PrivateKey.EncapsulationKey().Bytes()
+
+ sharedSecret, ciphertext, err := mlkemKEM{variant: mlkem768}.encapsulate(publicKeyBytes)
+ require.NoError(t, err)
+ assert.Len(t, sharedSecret, 32)
+ assert.Len(t, ciphertext, MLKEM768CiphertextSize)
+}
+
+func TestMLKEM1024Encapsulate(t *testing.T) {
+ keyPair, err := NewMLKEM1024KeyPair()
+ require.NoError(t, err)
+
+ publicKeyBytes := keyPair.PrivateKey.EncapsulationKey().Bytes()
+
+ sharedSecret, ciphertext, err := mlkemKEM{variant: mlkem1024}.encapsulate(publicKeyBytes)
+ require.NoError(t, err)
+ assert.Len(t, sharedSecret, 32)
+ assert.Len(t, ciphertext, MLKEM1024CiphertextSize)
+}
+
+func TestMLKEM768EncapsulateInvalidKeySize(t *testing.T) {
+ _, _, err := mlkemKEM{variant: mlkem768}.encapsulate([]byte("too-short"))
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "public key size")
+}
+
+func TestMLKEM1024EncapsulateInvalidKeySize(t *testing.T) {
+ _, _, err := mlkemKEM{variant: mlkem1024}.encapsulate([]byte("too-short"))
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "public key size")
+}
+
+func TestMLKEM768PEMRoundTrip(t *testing.T) {
+ keyPair, err := NewMLKEMKeyPair()
+ require.NoError(t, err)
+
+ pubPEM, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+ assert.True(t, strings.HasPrefix(pubPEM, "-----BEGIN PUBLIC KEY-----"))
+ pubBlock, _ := pem.Decode([]byte(pubPEM))
+ require.NotNil(t, pubBlock)
+ assert.Equal(t, "PUBLIC KEY", pubBlock.Type)
+
+ privPEM, err := keyPair.PrivateKeyInPemFormat()
+ require.NoError(t, err)
+ assert.True(t, strings.HasPrefix(privPEM, "-----BEGIN PRIVATE KEY-----"))
+ privBlock, _ := pem.Decode([]byte(privPEM))
+ require.NotNil(t, privBlock)
+ assert.Equal(t, "PRIVATE KEY", privBlock.Type)
+
+ enc, err := FromPublicPEM(pubPEM)
+ require.NoError(t, err)
+ assert.Equal(t, MLKEM, enc.Type())
+ assert.Equal(t, MLKEM768Key, enc.KeyType())
+
+ dek := []byte("ml-kem-768 round-trip data")
+ wrapped, err := enc.Encrypt(dek)
+ require.NoError(t, err)
+
+ dec, err := FromPrivatePEM(privPEM)
+ require.NoError(t, err)
+ plaintext, err := dec.Decrypt(wrapped)
+ require.NoError(t, err)
+ assert.Equal(t, dek, plaintext)
+}
+
+func TestMLKEM1024PEMRoundTrip(t *testing.T) {
+ keyPair, err := NewMLKEM1024KeyPair()
+ require.NoError(t, err)
+
+ pubPEM, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+ assert.True(t, strings.HasPrefix(pubPEM, "-----BEGIN PUBLIC KEY-----"))
+ pubBlock, _ := pem.Decode([]byte(pubPEM))
+ require.NotNil(t, pubBlock)
+ assert.Equal(t, "PUBLIC KEY", pubBlock.Type)
+
+ privPEM, err := keyPair.PrivateKeyInPemFormat()
+ require.NoError(t, err)
+ assert.True(t, strings.HasPrefix(privPEM, "-----BEGIN PRIVATE KEY-----"))
+ privBlock, _ := pem.Decode([]byte(privPEM))
+ require.NotNil(t, privBlock)
+ assert.Equal(t, "PRIVATE KEY", privBlock.Type)
+
+ enc, err := FromPublicPEM(pubPEM)
+ require.NoError(t, err)
+ assert.Equal(t, MLKEM, enc.Type())
+ assert.Equal(t, MLKEM1024Key, enc.KeyType())
+
+ dek := []byte("ml-kem-1024 round-trip data")
+ wrapped, err := enc.Encrypt(dek)
+ require.NoError(t, err)
+
+ dec, err := FromPrivatePEM(privPEM)
+ require.NoError(t, err)
+ plaintext, err := dec.Decrypt(wrapped)
+ require.NoError(t, err)
+ assert.Equal(t, dek, plaintext)
+}
diff --git a/lib/ocrypto/xwing.go b/lib/ocrypto/xwing.go
index b92c93fecb..3358522600 100644
--- a/lib/ocrypto/xwing.go
+++ b/lib/ocrypto/xwing.go
@@ -3,7 +3,6 @@ package ocrypto
import (
"crypto/rand"
"crypto/sha256"
- "encoding/asn1"
"encoding/pem"
"fmt"
"io"
@@ -32,31 +31,11 @@ const (
// TODO(DSPX-TBD): swap the primitive to a draft-10 implementation once one
// is available in Go (tracking: upgrade cloudflare/circl xwing to draft-10).
-// XWingWrappedKey is the ASN.1 envelope stored in wrapped_key. The X-Wing
-// drafts define only the KEM; this DEK wrapping envelope is local to OpenTDF
-// and unchanged across draft revisions.
-type XWingWrappedKey struct {
- XWingCiphertext []byte `asn1:"tag:0"`
- EncryptedDEK []byte `asn1:"tag:1"`
-}
-
type XWingKeyPair struct {
publicKey []byte
privateKey []byte
}
-type XWingEncryptor struct {
- publicKey []byte
- salt []byte
- info []byte
-}
-
-type XWingDecryptor struct {
- privateKey []byte
- salt []byte
- info []byte
-}
-
func NewXWingKeyPair() (XWingKeyPair, error) {
sk, pk, err := xwing.GenerateKeyPair(rand.Reader)
if err != nil {
@@ -94,78 +73,37 @@ func (k XWingKeyPair) GetKeyType() KeyType {
return HybridXWingKey
}
-func NewXWingEncryptor(publicKey, salt, info []byte) (*XWingEncryptor, error) {
- if len(publicKey) != XWingPublicKeySize {
- return nil, fmt.Errorf("invalid X-Wing public key size: got %d want %d", len(publicKey), XWingPublicKeySize)
- }
+// xwingKEM adapts the X-Wing KEM onto the shared kem interface so it flows
+// through wrapDEKWithKEM / unwrapDEKWithKEM and the single kemEnvelope wire
+// format, alongside pure ML-KEM and the NIST composite hybrids.
+type xwingKEM struct{}
- return &XWingEncryptor{
- publicKey: append([]byte(nil), publicKey...),
- salt: cloneOrNil(salt),
- info: cloneOrNil(info),
- }, nil
+func (xwingKEM) keyType() KeyType { return HybridXWingKey }
+func (xwingKEM) scheme() SchemeType { return Hybrid }
+func (xwingKEM) pubSize() int { return XWingPublicKeySize }
+func (xwingKEM) privSize() int { return XWingPrivateKeySize }
+func (xwingKEM) ctSize() int { return XWingCiphertextSize }
+
+func (xwingKEM) encapsulate(pub []byte) ([]byte, []byte, error) {
+ return XWingEncapsulate(pub)
}
-func (e *XWingEncryptor) Encrypt(data []byte) ([]byte, error) {
- return xwingWrapDEK(e.publicKey, data, e.salt, e.info)
+func (xwingKEM) decapsulate(priv, ct []byte) ([]byte, error) {
+ return xwing.Decapsulate(ct, priv), nil
}
-func (e *XWingEncryptor) PublicKeyInPemFormat() (string, error) {
- der, err := marshalHybridSPKI(oidXWing, e.publicKey)
+func (xwingKEM) publicKeyPEM(pub []byte) (string, error) {
+ der, err := marshalHybridSPKI(oidXWing, pub)
if err != nil {
return "", err
}
return string(pem.EncodeToMemory(&pem.Block{Type: pemBlockPublicKey, Bytes: der})), nil
}
-func (e *XWingEncryptor) Type() SchemeType {
- return Hybrid
-}
-
-func (e *XWingEncryptor) KeyType() KeyType {
- return HybridXWingKey
-}
-
-func (e *XWingEncryptor) EphemeralKey() []byte {
- return nil
-}
-
-func (e *XWingEncryptor) Metadata() (map[string]string, error) {
- return make(map[string]string), nil
-}
-
-func NewXWingDecryptor(privateKey []byte) (*XWingDecryptor, error) {
- return NewSaltedXWingDecryptor(privateKey, defaultTDFSalt(), nil)
-}
-
-func NewSaltedXWingDecryptor(privateKey, salt, info []byte) (*XWingDecryptor, error) {
- if len(privateKey) != XWingPrivateKeySize {
- return nil, fmt.Errorf("invalid X-Wing private key size: got %d want %d", len(privateKey), XWingPrivateKeySize)
- }
-
- return &XWingDecryptor{
- privateKey: append([]byte(nil), privateKey...),
- salt: cloneOrNil(salt),
- info: cloneOrNil(info),
- }, nil
-}
-
-func (d *XWingDecryptor) Decrypt(data []byte) ([]byte, error) {
- return xwingUnwrapDEK(d.privateKey, data, d.salt, d.info)
-}
-
-// KeyType identifies the hybrid scheme so KAS-layer callers can cross-check
-// the OID-routed decryptor against an asserted algorithm before trusting it.
-func (d *XWingDecryptor) KeyType() KeyType {
- return HybridXWingKey
-}
-
-func XWingWrapDEK(publicKeyRaw, dek []byte) ([]byte, error) {
- return xwingWrapDEK(publicKeyRaw, dek, defaultTDFSalt(), nil)
-}
-
-func XWingUnwrapDEK(privateKeyRaw, wrappedDER []byte) ([]byte, error) {
- return xwingUnwrapDEK(privateKeyRaw, wrappedDER, defaultTDFSalt(), nil)
+// wrapKey derives the AES-256 wrap key from the X-Wing shared secret via
+// HKDF-SHA256 over (salt, info), per the hybrid PQ/T combiner-hygiene contract.
+func (xwingKEM) wrapKey(sharedSecret, salt, info []byte) ([]byte, error) {
+ return deriveXWingWrapKey(sharedSecret, salt, info)
}
// XWingEncapsulate performs the X-Wing KEM encapsulation, returning the shared
@@ -183,75 +121,6 @@ func XWingEncapsulate(publicKeyRaw []byte) ([]byte, []byte, error) {
return sharedSecret, ciphertext, nil
}
-func xwingWrapDEK(publicKeyRaw, dek, salt, info []byte) ([]byte, error) {
- sharedSecret, ciphertext, err := XWingEncapsulate(publicKeyRaw)
- if err != nil {
- return nil, err
- }
-
- wrapKey, err := deriveXWingWrapKey(sharedSecret, salt, info)
- if err != nil {
- return nil, err
- }
-
- gcm, err := NewAESGcm(wrapKey)
- if err != nil {
- return nil, fmt.Errorf("NewAESGcm failed: %w", err)
- }
-
- encryptedDEK, err := gcm.Encrypt(dek)
- if err != nil {
- return nil, fmt.Errorf("AES-GCM encrypt failed: %w", err)
- }
-
- wrappedDER, err := asn1.Marshal(XWingWrappedKey{
- XWingCiphertext: ciphertext,
- EncryptedDEK: encryptedDEK,
- })
- if err != nil {
- return nil, fmt.Errorf("asn1.Marshal failed: %w", err)
- }
-
- return wrappedDER, nil
-}
-
-func xwingUnwrapDEK(privateKeyRaw, wrappedDER, salt, info []byte) ([]byte, error) {
- if len(privateKeyRaw) != XWingPrivateKeySize {
- return nil, fmt.Errorf("invalid X-Wing private key size: got %d want %d", len(privateKeyRaw), XWingPrivateKeySize)
- }
-
- var wrappedKey XWingWrappedKey
- rest, err := asn1.Unmarshal(wrappedDER, &wrappedKey)
- if err != nil {
- return nil, fmt.Errorf("asn1.Unmarshal failed: %w", err)
- }
- if len(rest) != 0 {
- return nil, fmt.Errorf("asn1.Unmarshal left %d trailing bytes", len(rest))
- }
- if len(wrappedKey.XWingCiphertext) != XWingCiphertextSize {
- return nil, fmt.Errorf("invalid X-Wing ciphertext size: got %d want %d", len(wrappedKey.XWingCiphertext), XWingCiphertextSize)
- }
-
- sharedSecret := xwing.Decapsulate(wrappedKey.XWingCiphertext, privateKeyRaw)
-
- wrapKey, err := deriveXWingWrapKey(sharedSecret, salt, info)
- if err != nil {
- return nil, err
- }
-
- gcm, err := NewAESGcm(wrapKey)
- if err != nil {
- return nil, fmt.Errorf("NewAESGcm failed: %w", err)
- }
-
- plaintext, err := gcm.Decrypt(wrappedKey.EncryptedDEK)
- if err != nil {
- return nil, fmt.Errorf("AES-GCM decrypt failed: %w", err)
- }
-
- return plaintext, nil
-}
-
func deriveXWingWrapKey(sharedSecret, salt, info []byte) ([]byte, error) {
if len(salt) == 0 {
salt = defaultTDFSalt()
diff --git a/lib/ocrypto/xwing_test.go b/lib/ocrypto/xwing_test.go
index 1eea9c4e8c..9a5bed1935 100644
--- a/lib/ocrypto/xwing_test.go
+++ b/lib/ocrypto/xwing_test.go
@@ -1,7 +1,6 @@
package ocrypto
import (
- "encoding/asn1"
"encoding/pem"
"testing"
@@ -45,10 +44,10 @@ func TestXWingWrapUnwrapRoundTrip(t *testing.T) {
require.NoError(t, err)
dek := []byte("0123456789abcdef0123456789abcdef")
- wrapped, err := XWingWrapDEK(keyPair.publicKey, dek)
+ wrapped, err := wrapDEKWithKEM(xwingKEM{}, keyPair.publicKey, dek, nil, nil)
require.NoError(t, err)
- plaintext, err := XWingUnwrapDEK(keyPair.privateKey, wrapped)
+ plaintext, err := unwrapDEKWithKEM(xwingKEM{}, keyPair.privateKey, wrapped, nil, nil)
require.NoError(t, err)
assert.Equal(t, dek, plaintext)
}
@@ -59,30 +58,14 @@ func TestXWingWrapUnwrapWrongKeyFails(t *testing.T) {
wrongKeyPair, err := NewXWingKeyPair()
require.NoError(t, err)
- wrapped, err := XWingWrapDEK(keyPair.publicKey, []byte("top secret dek"))
+ wrapped, err := wrapDEKWithKEM(xwingKEM{}, keyPair.publicKey, []byte("top secret dek"), nil, nil)
require.NoError(t, err)
- _, err = XWingUnwrapDEK(wrongKeyPair.privateKey, wrapped)
+ _, err = unwrapDEKWithKEM(xwingKEM{}, wrongKeyPair.privateKey, wrapped, nil, nil)
require.Error(t, err)
assert.Contains(t, err.Error(), "AES-GCM decrypt failed")
}
-func TestXWingWrappedKeyASN1RoundTrip(t *testing.T) {
- original := XWingWrappedKey{
- XWingCiphertext: []byte("ciphertext"),
- EncryptedDEK: []byte("encrypted-dek"),
- }
-
- der, err := asn1.Marshal(original)
- require.NoError(t, err)
-
- var decoded XWingWrappedKey
- rest, err := asn1.Unmarshal(der, &decoded)
- require.NoError(t, err)
- assert.Empty(t, rest)
- assert.Equal(t, original, decoded)
-}
-
func TestXWingPEMDispatch(t *testing.T) {
keyPair, err := NewXWingKeyPair()
require.NoError(t, err)
@@ -98,7 +81,7 @@ func TestXWingPEMDispatch(t *testing.T) {
decryptor, err := FromPrivatePEMWithSalt(privatePEM, []byte("salt"), []byte("info"))
require.NoError(t, err)
- xwingEncryptor, ok := encryptor.(*XWingEncryptor)
+ xwingEncryptor, ok := encryptor.(*kemEncryptor)
require.True(t, ok)
assert.Equal(t, Hybrid, xwingEncryptor.Type())
assert.Equal(t, HybridXWingKey, xwingEncryptor.KeyType())
@@ -108,7 +91,7 @@ func TestXWingPEMDispatch(t *testing.T) {
require.NoError(t, err)
assert.Empty(t, metadata)
- xwingDecryptor, ok := decryptor.(*XWingDecryptor)
+ xwingDecryptor, ok := decryptor.(*kemDecryptor)
require.True(t, ok)
wrapped, err := xwingEncryptor.Encrypt([]byte("dispatch-dek"))
diff --git a/otdfctl/cmd/policy/kasKeys.go b/otdfctl/cmd/policy/kasKeys.go
index b9e4640db8..bdf692d68a 100644
--- a/otdfctl/cmd/policy/kasKeys.go
+++ b/otdfctl/cmd/policy/kasKeys.go
@@ -89,6 +89,10 @@ func generateKeyPair(alg policy.Algorithm) (ocrypto.KeyPair, error) {
key, err = ocrypto.NewKeyPair(ocrypto.HybridSecp256r1MLKEM768Key)
case policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024:
key, err = ocrypto.NewKeyPair(ocrypto.HybridSecp384r1MLKEM1024Key)
+ case policy.Algorithm_ALGORITHM_MLKEM_768:
+ key, err = ocrypto.NewKeyPair(ocrypto.MLKEM768Key)
+ case policy.Algorithm_ALGORITHM_MLKEM_1024:
+ key, err = ocrypto.NewKeyPair(ocrypto.MLKEM1024Key)
case policy.Algorithm_ALGORITHM_UNSPECIFIED:
fallthrough
default:
diff --git a/otdfctl/docs/man/policy/kas-registry/key/create.md b/otdfctl/docs/man/policy/kas-registry/key/create.md
index 76f5a85af9..86d5bc6205 100644
--- a/otdfctl/docs/man/policy/kas-registry/key/create.md
+++ b/otdfctl/docs/man/policy/kas-registry/key/create.md
@@ -75,9 +75,11 @@ otdfctl policy kas-registry key create --key-id "aws-key" --algorithm "rsa:2048"
| `ec:secp256r1` |
| `ec:secp384r1` |
| `ec:secp521r1` |
- | `hpqt:xwing` |
| `hpqt:secp256r1-mlkem768` |
| `hpqt:secp384r1-mlkem1024` |
+ | `hpqt:xwing` |
+ | `mlkem:768` |
+ | `mlkem:1024` |
2. The `"mode"` specifies where the key that is encrypting TDFs is stored. All keys will be encrypted when stored in Virtru's DB, for modes `"local"` and `"provider"`
diff --git a/otdfctl/docs/man/policy/kas-registry/key/import.md b/otdfctl/docs/man/policy/kas-registry/key/import.md
index b08a2ea843..cd4c012f94 100644
--- a/otdfctl/docs/man/policy/kas-registry/key/import.md
+++ b/otdfctl/docs/man/policy/kas-registry/key/import.md
@@ -79,6 +79,8 @@ otdfctl policy kas-registry key import --key-id "imported-key" --algorithm "rsa:
| `ec:secp256r1` |
| `ec:secp384r1` |
| `ec:secp521r1` |
- | `hpqt:xwing` |
| `hpqt:secp256r1-mlkem768` |
| `hpqt:secp384r1-mlkem1024` |
+ | `hpqt:xwing` |
+ | `mlkem:768` |
+ | `mlkem:1024` |
diff --git a/otdfctl/docs/man/policy/kas-registry/key/rotate.md b/otdfctl/docs/man/policy/kas-registry/key/rotate.md
index 726d85f74b..5f65e2cdca 100644
--- a/otdfctl/docs/man/policy/kas-registry/key/rotate.md
+++ b/otdfctl/docs/man/policy/kas-registry/key/rotate.md
@@ -88,9 +88,11 @@ otdfctl policy kas-registry key rotate --key "public-key-old" --kas "Secondary K
| `ec:secp256r1` |
| `ec:secp384r1` |
| `ec:secp521r1` |
- | `hpqt:xwing` |
| `hpqt:secp256r1-mlkem768` |
| `hpqt:secp384r1-mlkem1024` |
+ | `hpqt:xwing` |
+ | `mlkem:768` |
+ | `mlkem:1024` |
2. The `"mode"` specifies where the key that is encrypting TDFs is stored. All keys will be encrypted when stored in Virtru's DB, for modes `"local"` and `"provider"`
diff --git a/otdfctl/e2e/kas-keys.bats b/otdfctl/e2e/kas-keys.bats
index 44cf4359bb..8b813a4268 100644
--- a/otdfctl/e2e/kas-keys.bats
+++ b/otdfctl/e2e/kas-keys.bats
@@ -191,6 +191,48 @@ format_kas_name_as_uri() {
assert_not_equal "$(echo "$output" | jq -r .key.metadata.updated_at)" "null"
}
+@test "kas-keys: create key (local mode, mlkem:768)" {
+ KEY_ID=$(generate_key_id)
+ # Local mode: otdfctl generates the ML-KEM keypair internally, so we assert
+ # the public key is present/non-empty rather than matching a known value.
+ run_otdfctl_key create --kas "${KAS_REGISTRY_ID}" --key-id "${KEY_ID}" --algorithm "mlkem:768" --mode "local" --wrapping-key-id "wrapping-key-1" --wrapping-key "${WRAPPING_KEY}" --json
+ assert_success
+ assert_equal "$(echo "$output" | jq -r .kas_id)" "${KAS_REGISTRY_ID}"
+ assert_equal "$(echo "$output" | jq -r .key.key_id)" "${KEY_ID}"
+ assert_equal "$(echo "$output" | jq -r .key.key_algorithm)" "20" # mlkem:768
+ assert_equal "$(echo "$output" | jq -r .key.key_mode)" "1" # local
+ assert_equal "$(echo "$output" | jq -r .key.key_status)" "1" # active
+ assert_equal "$(echo "$output" | jq -r .key.legacy)" "null"
+ assert_not_equal "$(echo "$output" | jq -r .key.public_key_ctx.pem)" "null"
+ assert_not_equal "$(echo "$output" | jq -r .key.public_key_ctx.pem)" ""
+ assert_equal "$(echo "$output" | jq -r .key.private_key_ctx.key_id)" "wrapping-key-1"
+ assert_not_equal "$(echo "$output" | jq -r .key.private_key_ctx.wrapped_key)" "null"
+ assert_not_equal "$(echo "$output" | jq -r .key.private_key_ctx.wrapped_key)" ""
+ assert_not_equal "$(echo "$output" | jq -r .key.metadata.created_at)" "null"
+ assert_not_equal "$(echo "$output" | jq -r .key.metadata.updated_at)" "null"
+}
+
+@test "kas-keys: create key (local mode, mlkem:1024)" {
+ KEY_ID=$(generate_key_id)
+ # Local mode: otdfctl generates the ML-KEM keypair internally, so we assert
+ # the public key is present/non-empty rather than matching a known value.
+ run_otdfctl_key create --kas "${KAS_REGISTRY_ID}" --key-id "${KEY_ID}" --algorithm "mlkem:1024" --mode "local" --wrapping-key-id "wrapping-key-1" --wrapping-key "${WRAPPING_KEY}" --json
+ assert_success
+ assert_equal "$(echo "$output" | jq -r .kas_id)" "${KAS_REGISTRY_ID}"
+ assert_equal "$(echo "$output" | jq -r .key.key_id)" "${KEY_ID}"
+ assert_equal "$(echo "$output" | jq -r .key.key_algorithm)" "21" # mlkem:1024
+ assert_equal "$(echo "$output" | jq -r .key.key_mode)" "1" # local
+ assert_equal "$(echo "$output" | jq -r .key.key_status)" "1" # active
+ assert_equal "$(echo "$output" | jq -r .key.legacy)" "null"
+ assert_not_equal "$(echo "$output" | jq -r .key.public_key_ctx.pem)" "null"
+ assert_not_equal "$(echo "$output" | jq -r .key.public_key_ctx.pem)" ""
+ assert_equal "$(echo "$output" | jq -r .key.private_key_ctx.key_id)" "wrapping-key-1"
+ assert_not_equal "$(echo "$output" | jq -r .key.private_key_ctx.wrapped_key)" "null"
+ assert_not_equal "$(echo "$output" | jq -r .key.private_key_ctx.wrapped_key)" ""
+ assert_not_equal "$(echo "$output" | jq -r .key.metadata.created_at)" "null"
+ assert_not_equal "$(echo "$output" | jq -r .key.metadata.updated_at)" "null"
+}
+
@test "kas-keys: create key (public_key mode)" {
KEY_ID=$(generate_key_id)
run_otdfctl_key create --kas "${KAS_REGISTRY_ID}" --key-id "${KEY_ID}" --algorithm "rsa:2048" --mode "public_key" --public-key-pem "${PEM_B64}" --json
diff --git a/otdfctl/pkg/cli/sdkHelpers.go b/otdfctl/pkg/cli/sdkHelpers.go
index 943fbbc71e..d88651afa0 100644
--- a/otdfctl/pkg/cli/sdkHelpers.go
+++ b/otdfctl/pkg/cli/sdkHelpers.go
@@ -125,12 +125,16 @@ func KeyAlgToEnum(alg string) (policy.Algorithm, error) {
return policy.Algorithm_ALGORITHM_EC_P384, nil
case "ec:secp521r1":
return policy.Algorithm_ALGORITHM_EC_P521, nil
- case "hpqt:xwing":
- return policy.Algorithm_ALGORITHM_HPQT_XWING, nil
case "hpqt:secp256r1-mlkem768":
return policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768, nil
case "hpqt:secp384r1-mlkem1024":
return policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024, nil
+ case "hpqt:xwing":
+ return policy.Algorithm_ALGORITHM_HPQT_XWING, nil
+ case "mlkem:768":
+ return policy.Algorithm_ALGORITHM_MLKEM_768, nil
+ case "mlkem:1024":
+ return policy.Algorithm_ALGORITHM_MLKEM_1024, nil
default:
return policy.Algorithm_ALGORITHM_UNSPECIFIED, errors.New("invalid algorithm")
}
@@ -148,12 +152,16 @@ func KeyEnumToAlg(enum policy.Algorithm) (string, error) {
return "ec:secp384r1", nil
case policy.Algorithm_ALGORITHM_EC_P521:
return "ec:secp521r1", nil
- case policy.Algorithm_ALGORITHM_HPQT_XWING:
- return "hpqt:xwing", nil
case policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768:
return "hpqt:secp256r1-mlkem768", nil
case policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024:
return "hpqt:secp384r1-mlkem1024", nil
+ case policy.Algorithm_ALGORITHM_HPQT_XWING:
+ return "hpqt:xwing", nil
+ case policy.Algorithm_ALGORITHM_MLKEM_768:
+ return "mlkem:768", nil
+ case policy.Algorithm_ALGORITHM_MLKEM_1024:
+ return "mlkem:1024", nil
default:
return "", errors.New("invalid enum algorithm")
}
diff --git a/otdfctl/pkg/utils/pemvalidate.go b/otdfctl/pkg/utils/pemvalidate.go
index 29fc17f8ef..ab4bda79fb 100644
--- a/otdfctl/pkg/utils/pemvalidate.go
+++ b/otdfctl/pkg/utils/pemvalidate.go
@@ -41,10 +41,6 @@ func ValidatePublicKeyPEM(pemBytes []byte, expected policy.Algorithm) error {
if enc.KeyType() != ocrypto.EC521Key {
return errors.New("algorithm mismatch: expected EC P-521")
}
- case policy.Algorithm_ALGORITHM_HPQT_XWING:
- if enc.KeyType() != ocrypto.HybridXWingKey {
- return errors.New("algorithm mismatch: expected hybrid X-Wing (X25519 + ML-KEM-768)")
- }
case policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768:
if enc.KeyType() != ocrypto.HybridSecp256r1MLKEM768Key {
return errors.New("algorithm mismatch: expected hybrid NIST P-256 + ML-KEM-768")
@@ -53,6 +49,18 @@ func ValidatePublicKeyPEM(pemBytes []byte, expected policy.Algorithm) error {
if enc.KeyType() != ocrypto.HybridSecp384r1MLKEM1024Key {
return errors.New("algorithm mismatch: expected hybrid NIST P-384 + ML-KEM-1024")
}
+ case policy.Algorithm_ALGORITHM_HPQT_XWING:
+ if enc.KeyType() != ocrypto.HybridXWingKey {
+ return errors.New("algorithm mismatch: expected hybrid X-Wing (X25519 + ML-KEM-768)")
+ }
+ case policy.Algorithm_ALGORITHM_MLKEM_768:
+ if enc.KeyType() != ocrypto.MLKEM768Key {
+ return errors.New("algorithm mismatch: expected ML-KEM-768")
+ }
+ case policy.Algorithm_ALGORITHM_MLKEM_1024:
+ if enc.KeyType() != ocrypto.MLKEM1024Key {
+ return errors.New("algorithm mismatch: expected ML-KEM-1024")
+ }
case policy.Algorithm_ALGORITHM_UNSPECIFIED:
fallthrough
default:
diff --git a/protocol/go/policy/kasregistry/key_access_server_registry.pb.go b/protocol/go/policy/kasregistry/key_access_server_registry.pb.go
index c3cd4c7dc2..61fe847fae 100644
--- a/protocol/go/policy/kasregistry/key_access_server_registry.pb.go
+++ b/protocol/go/policy/kasregistry/key_access_server_registry.pb.go
@@ -4297,560 +4297,562 @@ var file_policy_kasregistry_key_access_server_registry_proto_rawDesc = []byte{
0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x3a, 0x02, 0x18, 0x01, 0x22, 0xd5, 0x0c, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61,
+ 0x69, 0x6f, 0x6e, 0x3a, 0x02, 0x18, 0x01, 0x22, 0xdd, 0x0c, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61,
0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x06,
0x6b, 0x61, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48,
0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x52, 0x05, 0x6b, 0x61, 0x73, 0x49, 0x64, 0x12, 0x1e, 0x0a,
0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba,
- 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, 0x12, 0xad, 0x01,
+ 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, 0x12, 0xb5, 0x01,
0x0a, 0x0d, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41,
- 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x42, 0x75, 0xba, 0x48, 0x72, 0xba, 0x01, 0x6f,
+ 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x42, 0x7d, 0xba, 0x48, 0x7a, 0xba, 0x01, 0x77,
0x0a, 0x15, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x5f,
0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x12, 0x34, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79,
0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20,
0x62, 0x65, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65,
- 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x1a, 0x20, 0x74,
+ 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x1a, 0x28, 0x74,
0x68, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x5b, 0x31, 0x2c, 0x20, 0x32, 0x2c, 0x20, 0x33, 0x2c,
- 0x20, 0x34, 0x2c, 0x20, 0x35, 0x2c, 0x20, 0x36, 0x2c, 0x20, 0x37, 0x2c, 0x20, 0x38, 0x5d, 0x52,
- 0x0c, 0x6b, 0x65, 0x79, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x93, 0x01,
- 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e,
- 0x32, 0x0f, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x4d, 0x6f, 0x64,
- 0x65, 0x42, 0x67, 0xba, 0x48, 0x64, 0xba, 0x01, 0x61, 0x0a, 0x10, 0x6b, 0x65, 0x79, 0x5f, 0x6d,
- 0x6f, 0x64, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x12, 0x35, 0x54, 0x68, 0x65,
- 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62,
- 0x65, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x66,
- 0x69, 0x6e, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x28, 0x31, 0x2d, 0x34,
- 0x29, 0x2e, 0x1a, 0x16, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3e, 0x3d, 0x20, 0x31, 0x20, 0x26, 0x26,
- 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3c, 0x3d, 0x20, 0x34, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x4d,
- 0x6f, 0x64, 0x65, 0x12, 0x42, 0x0a, 0x0e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65,
- 0x79, 0x5f, 0x63, 0x74, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x6f,
- 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x43, 0x74,
- 0x78, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x0c, 0x70, 0x75, 0x62, 0x6c, 0x69,
- 0x63, 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x12, 0x3d, 0x0a, 0x0f, 0x70, 0x72, 0x69, 0x76, 0x61,
- 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x15, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74,
- 0x65, 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x52, 0x0d, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
- 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64,
- 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66,
- 0x69, 0x67, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x18, 0x08,
- 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x12, 0x33, 0x0a, 0x08,
- 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17,
- 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
- 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
- 0x61, 0x3a, 0xbb, 0x07, 0xba, 0x48, 0xb7, 0x07, 0x1a, 0x97, 0x03, 0x0a, 0x23, 0x70, 0x72, 0x69,
- 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x5f, 0x6f, 0x70, 0x74,
- 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64,
- 0x12, 0xbc, 0x01, 0x54, 0x68, 0x65, 0x20, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6b,
- 0x65, 0x79, 0x20, 0x69, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x69,
- 0x66, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x4b, 0x45,
- 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x52, 0x4f,
- 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x20, 0x6f, 0x72, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f,
- 0x44, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x44, 0x45, 0x52, 0x5f, 0x52, 0x4f, 0x4f, 0x54,
- 0x5f, 0x4b, 0x45, 0x59, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65,
- 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x65, 0x6d,
- 0x70, 0x74, 0x79, 0x20, 0x69, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20,
- 0x69, 0x73, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x52, 0x45, 0x4d, 0x4f,
- 0x54, 0x45, 0x20, 0x6f, 0x72, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50,
- 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x2e, 0x1a,
- 0xb0, 0x01, 0x28, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64,
- 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6b,
- 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x32, 0x29, 0x20, 0x26, 0x26,
- 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65,
- 0x79, 0x5f, 0x63, 0x74, 0x78, 0x2e, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65,
- 0x79, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x27, 0x29, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x28, 0x74, 0x68,
- 0x69, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x33,
- 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64,
- 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x34, 0x29, 0x20, 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e,
- 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x2e,
- 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x3d, 0x3d, 0x20, 0x27,
- 0x27, 0x29, 0x1a, 0xf4, 0x02, 0x0a, 0x26, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f,
- 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
- 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0xa8, 0x01,
- 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20,
- 0x69, 0x64, 0x20, 0x69, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x69,
- 0x66, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x4b, 0x45,
- 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x44, 0x45, 0x52, 0x5f,
- 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x20, 0x6f, 0x72, 0x20, 0x4b, 0x45, 0x59, 0x5f,
- 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x2e, 0x20, 0x49, 0x74, 0x20,
- 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x66, 0x6f,
- 0x72, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49,
- 0x47, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x4b,
- 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b,
- 0x45, 0x59, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x2e, 0x1a, 0x9e, 0x01, 0x28, 0x28, 0x74, 0x68, 0x69,
- 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20,
- 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65,
- 0x20, 0x3d, 0x3d, 0x20, 0x34, 0x29, 0x20, 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x70,
+ 0x20, 0x34, 0x2c, 0x20, 0x35, 0x2c, 0x20, 0x36, 0x2c, 0x20, 0x37, 0x2c, 0x20, 0x38, 0x2c, 0x20,
+ 0x32, 0x30, 0x2c, 0x20, 0x32, 0x31, 0x5d, 0x52, 0x0c, 0x6b, 0x65, 0x79, 0x41, 0x6c, 0x67, 0x6f,
+ 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x93, 0x01, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f,
+ 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63,
+ 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x42, 0x67, 0xba, 0x48, 0x64, 0xba, 0x01,
+ 0x61, 0x0a, 0x10, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69,
+ 0x6e, 0x65, 0x64, 0x12, 0x35, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64,
+ 0x65, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x6f, 0x66,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c,
+ 0x75, 0x65, 0x73, 0x20, 0x28, 0x31, 0x2d, 0x34, 0x29, 0x2e, 0x1a, 0x16, 0x74, 0x68, 0x69, 0x73,
+ 0x20, 0x3e, 0x3d, 0x20, 0x31, 0x20, 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3c, 0x3d,
+ 0x20, 0x34, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x42, 0x0a, 0x0e, 0x70,
+ 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x18, 0x05, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x75, 0x62,
+ 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01,
+ 0x01, 0x52, 0x0c, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x12,
+ 0x3d, 0x0a, 0x0f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63,
+ 0x74, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63,
+ 0x79, 0x2e, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x52,
+ 0x0d, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x12, 0x2c,
+ 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
+ 0x67, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x76,
+ 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06,
+ 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, 0x65,
+ 0x67, 0x61, 0x63, 0x79, 0x12, 0x33, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+ 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
+ 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52,
+ 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0xbb, 0x07, 0xba, 0x48, 0xb7, 0x07,
+ 0x1a, 0x97, 0x03, 0x0a, 0x23, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79,
+ 0x5f, 0x63, 0x74, 0x78, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x6c, 0x79, 0x5f,
+ 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0xbc, 0x01, 0x54, 0x68, 0x65, 0x20, 0x77,
+ 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x69, 0x73, 0x20, 0x72, 0x65,
+ 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x69, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f,
+ 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x43,
+ 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x20, 0x6f,
+ 0x72, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x56, 0x49,
+ 0x44, 0x45, 0x52, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x2e, 0x20, 0x54, 0x68,
+ 0x65, 0x20, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x6d, 0x75,
+ 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x69, 0x66, 0x20, 0x6b,
+ 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d,
+ 0x4f, 0x44, 0x45, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x20, 0x6f, 0x72, 0x20, 0x4b, 0x45,
+ 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45,
+ 0x59, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x2e, 0x1a, 0xb0, 0x01, 0x28, 0x28, 0x74, 0x68, 0x69, 0x73,
+ 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x7c,
+ 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20,
+ 0x3d, 0x3d, 0x20, 0x32, 0x29, 0x20, 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x70, 0x72,
+ 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x2e, 0x77, 0x72,
+ 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x27, 0x29,
+ 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d,
+ 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x33, 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73,
+ 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x34, 0x29, 0x20,
+ 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f,
+ 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x2e, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f,
+ 0x6b, 0x65, 0x79, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x27, 0x29, 0x1a, 0xf4, 0x02, 0x0a, 0x26, 0x70,
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69,
- 0x64, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x27, 0x29, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x28, 0x74, 0x68,
- 0x69, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x32,
- 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64,
- 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x33, 0x29, 0x20, 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e,
- 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f,
- 0x69, 0x64, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x27, 0x29, 0x1a, 0xa3, 0x01, 0x0a, 0x23, 0x70, 0x72,
- 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x5f, 0x66, 0x6f,
- 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6f, 0x6e, 0x6c,
- 0x79, 0x12, 0x48, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63,
- 0x74, 0x78, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x73,
- 0x65, 0x74, 0x20, 0x69, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x69,
- 0x73, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49,
- 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x2e, 0x1a, 0x32, 0x21, 0x28, 0x74,
- 0x68, 0x69, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20,
- 0x34, 0x20, 0x26, 0x26, 0x20, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x70, 0x72,
- 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x29, 0x29, 0x22,
- 0x3c, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x07, 0x6b, 0x61, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b,
- 0x61, 0x73, 0x4b, 0x65, 0x79, 0x52, 0x06, 0x6b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x22, 0x7a, 0x0a,
- 0x0d, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a,
- 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72,
- 0x03, 0xb0, 0x01, 0x01, 0x48, 0x00, 0x52, 0x02, 0x69, 0x64, 0x12, 0x38, 0x0a, 0x03, 0x6b, 0x65,
- 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,
- 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4b, 0x61, 0x73,
- 0x4b, 0x65, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x48, 0x00, 0x52,
- 0x03, 0x6b, 0x65, 0x79, 0x42, 0x13, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69,
- 0x65, 0x72, 0x12, 0x05, 0xba, 0x48, 0x02, 0x08, 0x01, 0x22, 0x39, 0x0a, 0x0e, 0x47, 0x65, 0x74,
- 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x07, 0x6b,
- 0x61, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70,
- 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x52, 0x06, 0x6b, 0x61,
- 0x73, 0x4b, 0x65, 0x79, 0x22, 0x86, 0x04, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79,
- 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xb0, 0x01, 0x0a, 0x0d, 0x6b, 0x65, 0x79,
- 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
- 0x32, 0x11, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69,
- 0x74, 0x68, 0x6d, 0x42, 0x78, 0xba, 0x48, 0x75, 0xba, 0x01, 0x72, 0x0a, 0x15, 0x6b, 0x65, 0x79,
- 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e,
- 0x65, 0x64, 0x12, 0x34, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x6c, 0x67, 0x6f,
- 0x72, 0x69, 0x74, 0x68, 0x6d, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x6f, 0x6e,
- 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64,
- 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x1a, 0x23, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69,
- 0x6e, 0x20, 0x5b, 0x30, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x32, 0x2c, 0x20, 0x33, 0x2c, 0x20, 0x34,
- 0x2c, 0x20, 0x35, 0x2c, 0x20, 0x36, 0x2c, 0x20, 0x37, 0x2c, 0x20, 0x38, 0x5d, 0x52, 0x0c, 0x6b,
- 0x65, 0x79, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x21, 0x0a, 0x06, 0x6b,
- 0x61, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05,
- 0x72, 0x03, 0xb0, 0x01, 0x01, 0x48, 0x00, 0x52, 0x05, 0x6b, 0x61, 0x73, 0x49, 0x64, 0x12, 0x24,
- 0x0a, 0x08, 0x6b, 0x61, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
- 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x48, 0x00, 0x52, 0x07, 0x6b, 0x61, 0x73,
- 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x07, 0x6b, 0x61, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x18,
- 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0x72, 0x05, 0x10, 0x01, 0x88, 0x01,
- 0x01, 0x48, 0x00, 0x52, 0x06, 0x6b, 0x61, 0x73, 0x55, 0x72, 0x69, 0x12, 0x1b, 0x0a, 0x06, 0x6c,
- 0x65, 0x67, 0x61, 0x63, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x48, 0x01, 0x52, 0x06, 0x6c,
- 0x65, 0x67, 0x61, 0x63, 0x79, 0x88, 0x01, 0x01, 0x12, 0x33, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69,
- 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70,
- 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
- 0x74, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3d, 0x0a,
- 0x04, 0x73, 0x6f, 0x72, 0x74, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x6f,
- 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79,
- 0x2e, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x73, 0x53, 0x6f, 0x72, 0x74, 0x42, 0x08, 0xba, 0x48,
- 0x05, 0x92, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x73, 0x6f, 0x72, 0x74, 0x12, 0x26, 0x0a, 0x06,
- 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70,
- 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x06, 0x73, 0x65,
- 0x61, 0x72, 0x63, 0x68, 0x42, 0x0c, 0x0a, 0x0a, 0x6b, 0x61, 0x73, 0x5f, 0x66, 0x69, 0x6c, 0x74,
- 0x65, 0x72, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x22, 0x73, 0x0a,
- 0x10, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
- 0x65, 0x12, 0x29, 0x0a, 0x08, 0x6b, 0x61, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20,
- 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61, 0x73,
- 0x4b, 0x65, 0x79, 0x52, 0x07, 0x6b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x34, 0x0a, 0x0a,
- 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65,
- 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x22, 0x86, 0x03, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79,
- 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x52, 0x02, 0x69,
- 0x64, 0x12, 0x33, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74,
- 0x61, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x08, 0x6d, 0x65,
- 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x54, 0x0a, 0x18, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
- 0x74, 0x61, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69,
- 0x6f, 0x72, 0x18, 0x65, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
- 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
- 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x16, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70,
- 0x64, 0x61, 0x74, 0x65, 0x42, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x3a, 0xcc, 0x01, 0xba,
- 0x48, 0xc8, 0x01, 0x1a, 0xc5, 0x01, 0x0a, 0x18, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
- 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72,
- 0x12, 0x52, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74,
- 0x65, 0x20, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20,
- 0x62, 0x65, 0x20, 0x65, 0x69, 0x74, 0x68, 0x65, 0x72, 0x20, 0x41, 0x50, 0x50, 0x45, 0x4e, 0x44,
- 0x20, 0x6f, 0x72, 0x20, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x2c, 0x20, 0x77, 0x68, 0x65,
- 0x6e, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64,
- 0x61, 0x74, 0x61, 0x2e, 0x1a, 0x55, 0x28, 0x28, 0x21, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68, 0x69,
- 0x73, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x29, 0x29, 0x20, 0x7c, 0x7c, 0x20,
- 0x28, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
- 0x74, 0x61, 0x29, 0x20, 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x65, 0x74, 0x61,
- 0x64, 0x61, 0x74, 0x61, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x62, 0x65, 0x68, 0x61,
- 0x76, 0x69, 0x6f, 0x72, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x29, 0x22, 0x3c, 0x0a, 0x11, 0x55,
- 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
- 0x12, 0x27, 0x0a, 0x07, 0x6b, 0x61, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x4b, 0x65,
- 0x79, 0x52, 0x06, 0x6b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x22, 0xa4, 0x01, 0x0a, 0x10, 0x4b, 0x61,
- 0x73, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x21,
- 0x0a, 0x06, 0x6b, 0x61, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08,
- 0xba, 0x48, 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x48, 0x00, 0x52, 0x05, 0x6b, 0x61, 0x73, 0x49,
- 0x64, 0x12, 0x1d, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42,
- 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
- 0x12, 0x1e, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba,
- 0x48, 0x07, 0x72, 0x05, 0x10, 0x01, 0x88, 0x01, 0x01, 0x48, 0x00, 0x52, 0x03, 0x75, 0x72, 0x69,
- 0x12, 0x19, 0x0a, 0x03, 0x6b, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba,
- 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x03, 0x6b, 0x69, 0x64, 0x42, 0x13, 0x0a, 0x0a, 0x69,
- 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x05, 0xba, 0x48, 0x02, 0x08, 0x01,
- 0x22, 0xee, 0x0e, 0x0a, 0x10, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65,
- 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x48, 0x00, 0x52, 0x02, 0x69,
- 0x64, 0x12, 0x38, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24,
- 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73,
- 0x74, 0x72, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69,
- 0x66, 0x69, 0x65, 0x72, 0x48, 0x00, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x44, 0x0a, 0x07, 0x6e,
- 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70,
- 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
- 0x79, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65,
- 0x73, 0x74, 0x2e, 0x4e, 0x65, 0x77, 0x4b, 0x65, 0x79, 0x52, 0x06, 0x6e, 0x65, 0x77, 0x4b, 0x65,
- 0x79, 0x1a, 0xd8, 0x04, 0x0a, 0x06, 0x4e, 0x65, 0x77, 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x06,
- 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48,
- 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, 0x12, 0xa6, 0x01, 0x0a,
- 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e,
- 0x32, 0x11, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69,
- 0x74, 0x68, 0x6d, 0x42, 0x75, 0xba, 0x48, 0x72, 0xba, 0x01, 0x6f, 0x0a, 0x15, 0x6b, 0x65, 0x79,
- 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e,
- 0x65, 0x64, 0x12, 0x34, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x6c, 0x67, 0x6f,
- 0x72, 0x69, 0x74, 0x68, 0x6d, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x6f, 0x6e,
- 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64,
- 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x1a, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69,
- 0x6e, 0x20, 0x5b, 0x31, 0x2c, 0x20, 0x32, 0x2c, 0x20, 0x33, 0x2c, 0x20, 0x34, 0x2c, 0x20, 0x35,
- 0x2c, 0x20, 0x36, 0x2c, 0x20, 0x37, 0x2c, 0x20, 0x38, 0x5d, 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f,
- 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x9e, 0x01, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f,
- 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63,
- 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x42, 0x72, 0xba, 0x48, 0x6f, 0xba, 0x01,
- 0x67, 0x0a, 0x14, 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f,
- 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x12, 0x39, 0x54, 0x68, 0x65, 0x20, 0x6e, 0x65, 0x77,
- 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62,
- 0x65, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x66,
- 0x69, 0x6e, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x28, 0x31, 0x2d, 0x34,
- 0x29, 0x2e, 0x1a, 0x14, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x5b, 0x31, 0x2c, 0x20,
- 0x32, 0x2c, 0x20, 0x33, 0x2c, 0x20, 0x34, 0x5d, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x6b,
- 0x65, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x42, 0x0a, 0x0e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
- 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14,
- 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65,
- 0x79, 0x43, 0x74, 0x78, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x0c, 0x70, 0x75,
- 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x12, 0x3d, 0x0a, 0x0f, 0x70, 0x72,
- 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x18, 0x05, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x72, 0x69,
- 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x52, 0x0d, 0x70, 0x72, 0x69, 0x76,
- 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x72, 0x6f,
- 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 0x18,
- 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43,
- 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x64, 0x12, 0x33, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64,
- 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
- 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x75, 0x74, 0x61, 0x62,
- 0x6c, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0xcd, 0x08, 0xba,
- 0x48, 0xc9, 0x08, 0x1a, 0xd8, 0x03, 0x0a, 0x23, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f,
- 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c,
- 0x6c, 0x79, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0xcd, 0x01, 0x46, 0x6f,
- 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x6b, 0x65, 0x79, 0x2c, 0x20, 0x74,
- 0x68, 0x65, 0x20, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x69,
- 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x69, 0x66, 0x20, 0x6b, 0x65,
- 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f,
- 0x44, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b,
- 0x45, 0x59, 0x20, 0x6f, 0x72, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50,
+ 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x72, 0x65, 0x71,
+ 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0xa8, 0x01, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
+ 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, 0x69, 0x64, 0x20, 0x69, 0x73, 0x20, 0x72, 0x65,
+ 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x69, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f,
+ 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50,
0x52, 0x4f, 0x56, 0x49, 0x44, 0x45, 0x52, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59,
- 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65,
- 0x79, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x20,
- 0x69, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x4b,
- 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x20, 0x6f,
- 0x72, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49,
- 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x2e, 0x1a, 0xe0, 0x01, 0x28, 0x28,
- 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x6b, 0x65, 0x79,
- 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68,
- 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d,
- 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x32, 0x29, 0x20, 0x26, 0x26, 0x20, 0x74, 0x68, 0x69,
- 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74,
- 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x2e, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65,
- 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x27, 0x29, 0x20, 0x7c, 0x7c, 0x20,
- 0x28, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x6b,
- 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x33, 0x20, 0x7c, 0x7c, 0x20,
- 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x6b, 0x65, 0x79,
- 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x34, 0x29, 0x20, 0x26, 0x26, 0x20, 0x74,
- 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x69, 0x76,
- 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x2e, 0x77, 0x72, 0x61, 0x70,
- 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x27, 0x29, 0x1a, 0xb5,
- 0x03, 0x0a, 0x26, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66,
- 0x69, 0x67, 0x5f, 0x69, 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x6c, 0x79,
- 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0xb9, 0x01, 0x46, 0x6f, 0x72, 0x20,
- 0x74, 0x68, 0x65, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x6b, 0x65, 0x79, 0x2c, 0x20, 0x70, 0x72, 0x6f,
- 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, 0x69, 0x64, 0x20,
- 0x69, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x69, 0x66, 0x20, 0x6b,
- 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d,
- 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x44, 0x45, 0x52, 0x5f, 0x52, 0x4f, 0x4f,
- 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x20, 0x6f, 0x72, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44,
- 0x45, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x2e, 0x20, 0x49, 0x74, 0x20, 0x6d, 0x75, 0x73,
- 0x74, 0x20, 0x62, 0x65, 0x20, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x4b,
- 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x52,
- 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x4b, 0x45, 0x59, 0x5f,
- 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f,
- 0x4f, 0x4e, 0x4c, 0x59, 0x2e, 0x1a, 0xce, 0x01, 0x28, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e,
- 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20,
- 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77,
- 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d,
- 0x20, 0x34, 0x29, 0x20, 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5f,
- 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e,
- 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x27, 0x29, 0x20, 0x7c, 0x7c,
- 0x20, 0x28, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e,
- 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x32, 0x20, 0x7c, 0x7c,
+ 0x20, 0x6f, 0x72, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x52, 0x45, 0x4d,
+ 0x4f, 0x54, 0x45, 0x2e, 0x20, 0x49, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20,
+ 0x65, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f,
+ 0x44, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b,
+ 0x45, 0x59, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f,
+ 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x2e,
+ 0x1a, 0x9e, 0x01, 0x28, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f,
+ 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e,
+ 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x34, 0x29, 0x20, 0x26,
+ 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f,
+ 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x27, 0x29,
+ 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d,
+ 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x32, 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73,
+ 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x33, 0x29, 0x20,
+ 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
+ 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x27,
+ 0x29, 0x1a, 0xa3, 0x01, 0x0a, 0x23, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65,
+ 0x79, 0x5f, 0x63, 0x74, 0x78, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
+ 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x12, 0x48, 0x70, 0x72, 0x69, 0x76, 0x61,
+ 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20,
+ 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x74, 0x20, 0x69, 0x66, 0x20, 0x6b, 0x65,
+ 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f,
+ 0x44, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x4e,
+ 0x4c, 0x59, 0x2e, 0x1a, 0x32, 0x21, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f,
+ 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x34, 0x20, 0x26, 0x26, 0x20, 0x68, 0x61, 0x73,
+ 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65,
+ 0x79, 0x5f, 0x63, 0x74, 0x78, 0x29, 0x29, 0x22, 0x3c, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74,
+ 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x07,
+ 0x6b, 0x61, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e,
+ 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x52, 0x06, 0x6b,
+ 0x61, 0x73, 0x4b, 0x65, 0x79, 0x22, 0x7a, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x48, 0x00, 0x52, 0x02,
+ 0x69, 0x64, 0x12, 0x38, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69,
+ 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74,
+ 0x69, 0x66, 0x69, 0x65, 0x72, 0x48, 0x00, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x42, 0x13, 0x0a, 0x0a,
+ 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x05, 0xba, 0x48, 0x02, 0x08,
+ 0x01, 0x22, 0x39, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x07, 0x6b, 0x61, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61,
+ 0x73, 0x4b, 0x65, 0x79, 0x52, 0x06, 0x6b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x22, 0x8f, 0x04, 0x0a,
+ 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x12, 0xb9, 0x01, 0x0a, 0x0d, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74,
+ 0x68, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63,
+ 0x79, 0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x42, 0x80, 0x01, 0xba, 0x48,
+ 0x7d, 0xba, 0x01, 0x7a, 0x0a, 0x15, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69,
+ 0x74, 0x68, 0x6d, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x12, 0x34, 0x54, 0x68, 0x65,
+ 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x20, 0x6d,
+ 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73,
+ 0x2e, 0x1a, 0x2b, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x5b, 0x30, 0x2c, 0x20, 0x31,
+ 0x2c, 0x20, 0x32, 0x2c, 0x20, 0x33, 0x2c, 0x20, 0x34, 0x2c, 0x20, 0x35, 0x2c, 0x20, 0x36, 0x2c,
+ 0x20, 0x37, 0x2c, 0x20, 0x38, 0x2c, 0x20, 0x32, 0x30, 0x2c, 0x20, 0x32, 0x31, 0x5d, 0x52, 0x0c,
+ 0x6b, 0x65, 0x79, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x21, 0x0a, 0x06,
+ 0x6b, 0x61, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48,
+ 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x48, 0x00, 0x52, 0x05, 0x6b, 0x61, 0x73, 0x49, 0x64, 0x12,
+ 0x24, 0x0a, 0x08, 0x6b, 0x61, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x48, 0x00, 0x52, 0x07, 0x6b, 0x61,
+ 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x07, 0x6b, 0x61, 0x73, 0x5f, 0x75, 0x72, 0x69,
+ 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0x72, 0x05, 0x10, 0x01, 0x88,
+ 0x01, 0x01, 0x48, 0x00, 0x52, 0x06, 0x6b, 0x61, 0x73, 0x55, 0x72, 0x69, 0x12, 0x1b, 0x0a, 0x06,
+ 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x48, 0x01, 0x52, 0x06,
+ 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x88, 0x01, 0x01, 0x12, 0x33, 0x0a, 0x0a, 0x70, 0x61, 0x67,
+ 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e,
+ 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3d,
+ 0x0a, 0x04, 0x73, 0x6f, 0x72, 0x74, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70,
+ 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
+ 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x73, 0x53, 0x6f, 0x72, 0x74, 0x42, 0x08, 0xba,
+ 0x48, 0x05, 0x92, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x73, 0x6f, 0x72, 0x74, 0x12, 0x26, 0x0a,
+ 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e,
+ 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x06, 0x73,
+ 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x0c, 0x0a, 0x0a, 0x6b, 0x61, 0x73, 0x5f, 0x66, 0x69, 0x6c,
+ 0x74, 0x65, 0x72, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x22, 0x73,
+ 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x12, 0x29, 0x0a, 0x08, 0x6b, 0x61, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01,
+ 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61,
+ 0x73, 0x4b, 0x65, 0x79, 0x52, 0x07, 0x6b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x34, 0x0a,
+ 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x22, 0x86, 0x03, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65,
+ 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x52, 0x02,
+ 0x69, 0x64, 0x12, 0x33, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x08, 0x6d,
+ 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x54, 0x0a, 0x18, 0x6d, 0x65, 0x74, 0x61, 0x64,
+ 0x61, 0x74, 0x61, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76,
+ 0x69, 0x6f, 0x72, 0x18, 0x65, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
+ 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74,
+ 0x65, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x16, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55,
+ 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x3a, 0xcc, 0x01,
+ 0xba, 0x48, 0xc8, 0x01, 0x1a, 0xc5, 0x01, 0x0a, 0x18, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
+ 0x61, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f,
+ 0x72, 0x12, 0x52, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x75, 0x70, 0x64, 0x61,
+ 0x74, 0x65, 0x20, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74,
+ 0x20, 0x62, 0x65, 0x20, 0x65, 0x69, 0x74, 0x68, 0x65, 0x72, 0x20, 0x41, 0x50, 0x50, 0x45, 0x4e,
+ 0x44, 0x20, 0x6f, 0x72, 0x20, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x2c, 0x20, 0x77, 0x68,
+ 0x65, 0x6e, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x65, 0x74, 0x61,
+ 0x64, 0x61, 0x74, 0x61, 0x2e, 0x1a, 0x55, 0x28, 0x28, 0x21, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68,
+ 0x69, 0x73, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x29, 0x29, 0x20, 0x7c, 0x7c,
+ 0x20, 0x28, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x64,
+ 0x61, 0x74, 0x61, 0x29, 0x20, 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x62, 0x65, 0x68,
+ 0x61, 0x76, 0x69, 0x6f, 0x72, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x29, 0x22, 0x3c, 0x0a, 0x11,
+ 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x12, 0x27, 0x0a, 0x07, 0x6b, 0x61, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x4b,
+ 0x65, 0x79, 0x52, 0x06, 0x6b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x22, 0xa4, 0x01, 0x0a, 0x10, 0x4b,
+ 0x61, 0x73, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12,
+ 0x21, 0x0a, 0x06, 0x6b, 0x61, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42,
+ 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x48, 0x00, 0x52, 0x05, 0x6b, 0x61, 0x73,
+ 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+ 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x61, 0x6d,
+ 0x65, 0x12, 0x1e, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a,
+ 0xba, 0x48, 0x07, 0x72, 0x05, 0x10, 0x01, 0x88, 0x01, 0x01, 0x48, 0x00, 0x52, 0x03, 0x75, 0x72,
+ 0x69, 0x12, 0x19, 0x0a, 0x03, 0x6b, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07,
+ 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x03, 0x6b, 0x69, 0x64, 0x42, 0x13, 0x0a, 0x0a,
+ 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x05, 0xba, 0x48, 0x02, 0x08,
+ 0x01, 0x22, 0xf6, 0x0e, 0x0a, 0x10, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x48, 0x00, 0x52, 0x02,
+ 0x69, 0x64, 0x12, 0x38, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69,
+ 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74,
+ 0x69, 0x66, 0x69, 0x65, 0x72, 0x48, 0x00, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x44, 0x0a, 0x07,
+ 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e,
+ 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74,
+ 0x72, 0x79, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x2e, 0x4e, 0x65, 0x77, 0x4b, 0x65, 0x79, 0x52, 0x06, 0x6e, 0x65, 0x77, 0x4b,
+ 0x65, 0x79, 0x1a, 0xe0, 0x04, 0x0a, 0x06, 0x4e, 0x65, 0x77, 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x0a,
+ 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba,
+ 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, 0x12, 0xae, 0x01,
+ 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x0e, 0x32, 0x11, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x72,
+ 0x69, 0x74, 0x68, 0x6d, 0x42, 0x7d, 0xba, 0x48, 0x7a, 0xba, 0x01, 0x77, 0x0a, 0x15, 0x6b, 0x65,
+ 0x79, 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x5f, 0x64, 0x65, 0x66, 0x69,
+ 0x6e, 0x65, 0x64, 0x12, 0x34, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x6c, 0x67,
+ 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x6f,
+ 0x6e, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65,
+ 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x1a, 0x28, 0x74, 0x68, 0x69, 0x73, 0x20,
+ 0x69, 0x6e, 0x20, 0x5b, 0x31, 0x2c, 0x20, 0x32, 0x2c, 0x20, 0x33, 0x2c, 0x20, 0x34, 0x2c, 0x20,
+ 0x35, 0x2c, 0x20, 0x36, 0x2c, 0x20, 0x37, 0x2c, 0x20, 0x38, 0x2c, 0x20, 0x32, 0x30, 0x2c, 0x20,
+ 0x32, 0x31, 0x5d, 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x9e,
+ 0x01, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x0e, 0x32, 0x0f, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x4d, 0x6f,
+ 0x64, 0x65, 0x42, 0x72, 0xba, 0x48, 0x6f, 0xba, 0x01, 0x67, 0x0a, 0x14, 0x6e, 0x65, 0x77, 0x5f,
+ 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64,
+ 0x12, 0x39, 0x54, 0x68, 0x65, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f,
+ 0x64, 0x65, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x6f,
+ 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x73, 0x20, 0x28, 0x31, 0x2d, 0x34, 0x29, 0x2e, 0x1a, 0x14, 0x74, 0x68, 0x69,
+ 0x73, 0x20, 0x69, 0x6e, 0x20, 0x5b, 0x31, 0x2c, 0x20, 0x32, 0x2c, 0x20, 0x33, 0x2c, 0x20, 0x34,
+ 0x5d, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12,
+ 0x42, 0x0a, 0x0e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74,
+ 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,
+ 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x42, 0x06, 0xba,
+ 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x0c, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79,
+ 0x43, 0x74, 0x78, 0x12, 0x3d, 0x0a, 0x0f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b,
+ 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70,
+ 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79,
+ 0x43, 0x74, 0x78, 0x52, 0x0d, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x43,
+ 0x74, 0x78, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x63,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10,
+ 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x64,
+ 0x12, 0x33, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61,
+ 0x64, 0x61, 0x74, 0x61, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0xcd, 0x08, 0xba, 0x48, 0xc9, 0x08, 0x1a, 0xd8, 0x03, 0x0a,
+ 0x23, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78,
+ 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x72, 0x65, 0x71, 0x75,
+ 0x69, 0x72, 0x65, 0x64, 0x12, 0xcd, 0x01, 0x46, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e,
+ 0x65, 0x77, 0x20, 0x6b, 0x65, 0x79, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x72, 0x61, 0x70,
+ 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x69, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69,
+ 0x72, 0x65, 0x64, 0x20, 0x69, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20,
+ 0x69, 0x73, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46,
+ 0x49, 0x47, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x20, 0x6f, 0x72, 0x20, 0x4b,
+ 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x44, 0x45, 0x52,
+ 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x77,
+ 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20,
+ 0x62, 0x65, 0x20, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x69, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x5f,
+ 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45,
+ 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x20, 0x6f, 0x72, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d,
+ 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f,
+ 0x4e, 0x4c, 0x59, 0x2e, 0x1a, 0xe0, 0x01, 0x28, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65,
+ 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d,
+ 0x3d, 0x20, 0x31, 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5f,
+ 0x6b, 0x65, 0x79, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20,
+ 0x32, 0x29, 0x20, 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5f, 0x6b,
+ 0x65, 0x79, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63,
+ 0x74, 0x78, 0x2e, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x21,
+ 0x3d, 0x20, 0x27, 0x27, 0x29, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e,
+ 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65,
+ 0x20, 0x3d, 0x3d, 0x20, 0x33, 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65,
+ 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d,
+ 0x3d, 0x20, 0x34, 0x29, 0x20, 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77,
+ 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79,
+ 0x5f, 0x63, 0x74, 0x78, 0x2e, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79,
+ 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x27, 0x29, 0x1a, 0xb5, 0x03, 0x0a, 0x26, 0x70, 0x72, 0x6f, 0x76,
+ 0x69, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 0x5f, 0x6f,
+ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72,
+ 0x65, 0x64, 0x12, 0xb9, 0x01, 0x46, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x65, 0x77,
+ 0x20, 0x6b, 0x65, 0x79, 0x2c, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x63,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, 0x69, 0x64, 0x20, 0x69, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75,
+ 0x69, 0x72, 0x65, 0x64, 0x20, 0x69, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65,
+ 0x20, 0x69, 0x73, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x52, 0x4f,
+ 0x56, 0x49, 0x44, 0x45, 0x52, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x20, 0x6f,
+ 0x72, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54,
+ 0x45, 0x2e, 0x20, 0x49, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x65, 0x6d,
+ 0x70, 0x74, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45,
+ 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59,
+ 0x20, 0x61, 0x6e, 0x64, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x55,
+ 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x2e, 0x1a, 0xce,
+ 0x01, 0x28, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e,
+ 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x7c, 0x7c,
0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x6b, 0x65,
- 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x33, 0x29, 0x20, 0x26, 0x26, 0x20,
+ 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x34, 0x29, 0x20, 0x26, 0x26, 0x20,
0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f,
0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 0x20,
- 0x21, 0x3d, 0x20, 0x27, 0x27, 0x29, 0x1a, 0xb3, 0x01, 0x0a, 0x23, 0x70, 0x72, 0x69, 0x76, 0x61,
- 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x70,
- 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x12, 0x48,
- 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x20,
- 0x6d, 0x75, 0x73, 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x74, 0x20,
- 0x69, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x4b,
- 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b,
- 0x45, 0x59, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x2e, 0x1a, 0x42, 0x21, 0x28, 0x74, 0x68, 0x69, 0x73,
+ 0x3d, 0x3d, 0x20, 0x27, 0x27, 0x29, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x28, 0x74, 0x68, 0x69, 0x73,
0x2e, 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64,
- 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x34, 0x20, 0x26, 0x26, 0x20, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68,
- 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61,
- 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x29, 0x29, 0x42, 0x13, 0x0a, 0x0a,
- 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x12, 0x05, 0xba, 0x48, 0x02, 0x08,
- 0x01, 0x22, 0x32, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x61, 0x70, 0x70, 0x69,
- 0x6e, 0x67, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x71, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x03, 0x66, 0x71, 0x6e, 0x22, 0xe3, 0x02, 0x0a, 0x10, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65,
- 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x36, 0x0a, 0x0f, 0x72, 0x6f,
- 0x74, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x75, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61, 0x73,
- 0x4b, 0x65, 0x79, 0x52, 0x0d, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x4f, 0x75, 0x74, 0x4b,
- 0x65, 0x79, 0x12, 0x66, 0x0a, 0x1d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f,
- 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69,
- 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x6f, 0x6c, 0x69,
- 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x43,
- 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x1b, 0x61,
- 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69,
- 0x6f, 0x6e, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x5c, 0x0a, 0x18, 0x61, 0x74,
- 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x6d, 0x61,
- 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70,
- 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
- 0x79, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73,
- 0x52, 0x16, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65,
- 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x51, 0x0a, 0x12, 0x6e, 0x61, 0x6d, 0x65,
- 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04,
- 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61,
- 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65,
- 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x11, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70,
- 0x61, 0x63, 0x65, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x8f, 0x01, 0x0a, 0x11,
- 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
- 0x65, 0x12, 0x27, 0x0a, 0x07, 0x6b, 0x61, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x4b,
- 0x65, 0x79, 0x52, 0x06, 0x6b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x51, 0x0a, 0x11, 0x72, 0x6f,
- 0x74, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b,
- 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74,
- 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x10, 0x72, 0x6f, 0x74,
- 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, 0x7e, 0x0a,
- 0x11, 0x53, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65,
- 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08,
- 0xba, 0x48, 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x48, 0x00, 0x52, 0x02, 0x69, 0x64, 0x12, 0x38,
- 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x6f,
- 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79,
- 0x2e, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65,
- 0x72, 0x48, 0x00, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x42, 0x13, 0x0a, 0x0a, 0x61, 0x63, 0x74, 0x69,
- 0x76, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x12, 0x05, 0xba, 0x48, 0x02, 0x08, 0x01, 0x22, 0x13, 0x0a,
- 0x11, 0x47, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65,
- 0x73, 0x74, 0x22, 0x45, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79,
- 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x08, 0x62, 0x61, 0x73, 0x65,
- 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c,
- 0x69, 0x63, 0x79, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79,
- 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x22, 0x8e, 0x01, 0x0a, 0x12, 0x53, 0x65,
- 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
- 0x12, 0x36, 0x0a, 0x0c, 0x6e, 0x65, 0x77, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x6b, 0x65, 0x79,
- 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,
- 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x52, 0x0a, 0x6e, 0x65,
- 0x77, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x40, 0x0a, 0x11, 0x70, 0x72, 0x65, 0x76,
- 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20,
+ 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x32, 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e,
+ 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20,
+ 0x3d, 0x3d, 0x20, 0x33, 0x29, 0x20, 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65,
+ 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x63,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x27, 0x29, 0x1a,
+ 0xb3, 0x01, 0x0a, 0x23, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f,
+ 0x63, 0x74, 0x78, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b,
+ 0x65, 0x79, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x12, 0x48, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
+ 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x6e, 0x6f,
+ 0x74, 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x74, 0x20, 0x69, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x5f,
+ 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45,
+ 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x4e, 0x4c, 0x59,
+ 0x2e, 0x1a, 0x42, 0x21, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65,
+ 0x79, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x34, 0x20,
+ 0x26, 0x26, 0x20, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5f,
+ 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f,
+ 0x63, 0x74, 0x78, 0x29, 0x29, 0x42, 0x13, 0x0a, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f,
+ 0x6b, 0x65, 0x79, 0x12, 0x05, 0xba, 0x48, 0x02, 0x08, 0x01, 0x22, 0x32, 0x0a, 0x0e, 0x43, 0x68,
+ 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x0e, 0x0a, 0x02,
+ 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03,
+ 0x66, 0x71, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x66, 0x71, 0x6e, 0x22, 0xe3,
+ 0x02, 0x0a, 0x10, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
+ 0x63, 0x65, 0x73, 0x12, 0x36, 0x0a, 0x0f, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x6f,
+ 0x75, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70,
+ 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x52, 0x0d, 0x72, 0x6f,
+ 0x74, 0x61, 0x74, 0x65, 0x64, 0x4f, 0x75, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x66, 0x0a, 0x1d, 0x61,
+ 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74,
+ 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03,
+ 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72,
+ 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x61,
+ 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x1b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
+ 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x70, 0x70, 0x69,
+ 0x6e, 0x67, 0x73, 0x12, 0x5c, 0x0a, 0x18, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
+ 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18,
+ 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b,
+ 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67,
+ 0x65, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x16, 0x61, 0x74, 0x74, 0x72, 0x69,
+ 0x62, 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67,
+ 0x73, 0x12, 0x51, 0x0a, 0x12, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6d,
+ 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e,
+ 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74,
+ 0x72, 0x79, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67,
+ 0x73, 0x52, 0x11, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4d, 0x61, 0x70, 0x70,
+ 0x69, 0x6e, 0x67, 0x73, 0x22, 0x8f, 0x01, 0x0a, 0x11, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x4b,
+ 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x07, 0x6b, 0x61,
+ 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f,
+ 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x52, 0x06, 0x6b, 0x61, 0x73,
+ 0x4b, 0x65, 0x79, 0x12, 0x51, 0x0a, 0x11, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x72,
+ 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24,
+ 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73,
+ 0x74, 0x72, 0x79, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75,
+ 0x72, 0x63, 0x65, 0x73, 0x52, 0x10, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, 0x7e, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x42, 0x61, 0x73,
+ 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x69,
+ 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0xb0, 0x01,
+ 0x01, 0x48, 0x00, 0x52, 0x02, 0x69, 0x64, 0x12, 0x38, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61,
+ 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79,
+ 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x48, 0x00, 0x52, 0x03, 0x6b, 0x65,
+ 0x79, 0x42, 0x13, 0x0a, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x12,
+ 0x05, 0xba, 0x48, 0x02, 0x08, 0x01, 0x22, 0x13, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x42, 0x61, 0x73,
+ 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x45, 0x0a, 0x12, 0x47,
+ 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x12, 0x2f, 0x0a, 0x08, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x69, 0x6d,
- 0x70, 0x6c, 0x65, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x70, 0x72, 0x65, 0x76, 0x69,
- 0x6f, 0x75, 0x73, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x22, 0x36, 0x0a, 0x12, 0x4d, 0x61,
- 0x70, 0x70, 0x65, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74,
- 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
- 0x12, 0x10, 0x0a, 0x03, 0x66, 0x71, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x66,
- 0x71, 0x6e, 0x22, 0xb4, 0x02, 0x0a, 0x0a, 0x4b, 0x65, 0x79, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e,
- 0x67, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
- 0x6b, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x6b, 0x61, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x02,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6b, 0x61, 0x73, 0x55, 0x72, 0x69, 0x12, 0x55, 0x0a, 0x12,
- 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e,
- 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63,
+ 0x70, 0x6c, 0x65, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x4b,
+ 0x65, 0x79, 0x22, 0x8e, 0x01, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65,
+ 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x0c, 0x6e, 0x65, 0x77,
+ 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4b,
+ 0x61, 0x73, 0x4b, 0x65, 0x79, 0x52, 0x0a, 0x6e, 0x65, 0x77, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65,
+ 0x79, 0x12, 0x40, 0x0a, 0x11, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x62, 0x61,
+ 0x73, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70,
+ 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4b, 0x61, 0x73, 0x4b,
+ 0x65, 0x79, 0x52, 0x0f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x42, 0x61, 0x73, 0x65,
+ 0x4b, 0x65, 0x79, 0x22, 0x36, 0x0a, 0x12, 0x4d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x50, 0x6f, 0x6c,
+ 0x69, 0x63, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x71, 0x6e,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x66, 0x71, 0x6e, 0x22, 0xb4, 0x02, 0x0a, 0x0a,
+ 0x4b, 0x65, 0x79, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x69,
+ 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07,
+ 0x6b, 0x61, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6b,
+ 0x61, 0x73, 0x55, 0x72, 0x69, 0x12, 0x55, 0x0a, 0x12, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
+ 0x63, 0x65, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
+ 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65,
+ 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x50, 0x6f, 0x6c,
+ 0x69, 0x63, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x11, 0x6e, 0x61, 0x6d, 0x65, 0x73,
+ 0x70, 0x61, 0x63, 0x65, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x55, 0x0a, 0x12,
+ 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e,
+ 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63,
0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x61,
0x70, 0x70, 0x65, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74,
- 0x52, 0x11, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4d, 0x61, 0x70, 0x70, 0x69,
- 0x6e, 0x67, 0x73, 0x12, 0x55, 0x0a, 0x12, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
- 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
- 0x26, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69,
- 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63,
- 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x11, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
- 0x74, 0x65, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4d, 0x0a, 0x0e, 0x76, 0x61,
- 0x6c, 0x75, 0x65, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03,
- 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72,
- 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x50, 0x6f,
- 0x6c, 0x69, 0x63, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x0d, 0x76, 0x61, 0x6c, 0x75,
- 0x65, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x22, 0xb8, 0x01, 0x0a, 0x16, 0x4c, 0x69,
- 0x73, 0x74, 0x4b, 0x65, 0x79, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
- 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x48, 0x00, 0x52, 0x02, 0x69, 0x64,
- 0x12, 0x38, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e,
- 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74,
- 0x72, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66,
- 0x69, 0x65, 0x72, 0x48, 0x00, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x33, 0x0a, 0x0a, 0x70, 0x61,
- 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13,
- 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75,
- 0x65, 0x73, 0x74, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42,
- 0x13, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x05, 0xba,
- 0x48, 0x02, 0x08, 0x00, 0x22, 0x92, 0x01, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79,
- 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
- 0x12, 0x41, 0x0a, 0x0c, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73,
- 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,
- 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x4d,
- 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x6b, 0x65, 0x79, 0x4d, 0x61, 0x70, 0x70, 0x69,
- 0x6e, 0x67, 0x73, 0x12, 0x34, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,
- 0x2e, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0a, 0x70,
- 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2a, 0xef, 0x01, 0x0a, 0x18, 0x53, 0x6f,
- 0x72, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65,
- 0x72, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2c, 0x0a, 0x28, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b,
- 0x45, 0x59, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52,
- 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49,
- 0x45, 0x44, 0x10, 0x00, 0x12, 0x25, 0x0a, 0x21, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x45, 0x59,
+ 0x52, 0x11, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x4d, 0x61, 0x70, 0x70, 0x69,
+ 0x6e, 0x67, 0x73, 0x12, 0x4d, 0x0a, 0x0e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x6d, 0x61, 0x70,
+ 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x6f,
+ 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79,
+ 0x2e, 0x4d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4f, 0x62, 0x6a,
+ 0x65, 0x63, 0x74, 0x52, 0x0d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e,
+ 0x67, 0x73, 0x22, 0xb8, 0x01, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x4d, 0x61,
+ 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a,
+ 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03,
+ 0xb0, 0x01, 0x01, 0x48, 0x00, 0x52, 0x02, 0x69, 0x64, 0x12, 0x38, 0x0a, 0x03, 0x6b, 0x65, 0x79,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,
+ 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x4b,
+ 0x65, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x48, 0x00, 0x52, 0x03,
+ 0x6b, 0x65, 0x79, 0x12, 0x33, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,
+ 0x2e, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0a, 0x70, 0x61,
+ 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x13, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e,
+ 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x05, 0xba, 0x48, 0x02, 0x08, 0x00, 0x22, 0x92, 0x01,
+ 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67,
+ 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x6b, 0x65, 0x79,
+ 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+ 0x1e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69,
+ 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52,
+ 0x0b, 0x6b, 0x65, 0x79, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x34, 0x0a, 0x0a,
+ 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x2a, 0xef, 0x01, 0x0a, 0x18, 0x53, 0x6f, 0x72, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63,
+ 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12,
+ 0x2c, 0x0a, 0x28, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x43, 0x43, 0x45,
+ 0x53, 0x53, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f,
+ 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x25, 0x0a,
+ 0x21, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53,
+ 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4e, 0x41,
+ 0x4d, 0x45, 0x10, 0x01, 0x12, 0x24, 0x0a, 0x20, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x45, 0x59,
0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x53, 0x5f,
- 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4e, 0x41, 0x4d, 0x45, 0x10, 0x01, 0x12, 0x24, 0x0a, 0x20, 0x53,
- 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x53,
- 0x45, 0x52, 0x56, 0x45, 0x52, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x52, 0x49, 0x10,
- 0x02, 0x12, 0x2b, 0x0a, 0x27, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x43,
- 0x43, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x53, 0x5f, 0x54, 0x59, 0x50,
- 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x41, 0x54, 0x10, 0x03, 0x12, 0x2b,
- 0x0a, 0x27, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53,
- 0x53, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55,
- 0x50, 0x44, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x41, 0x54, 0x10, 0x04, 0x2a, 0x9a, 0x01, 0x0a, 0x0f,
- 0x53, 0x6f, 0x72, 0x74, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12,
- 0x22, 0x0a, 0x1e, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x41, 0x53, 0x5f, 0x4b, 0x45, 0x59, 0x53,
- 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45,
- 0x44, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x41, 0x53, 0x5f,
- 0x4b, 0x45, 0x59, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x49, 0x44,
- 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x41, 0x53, 0x5f, 0x4b,
- 0x45, 0x59, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44,
- 0x5f, 0x41, 0x54, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x41,
- 0x53, 0x5f, 0x4b, 0x45, 0x59, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x50, 0x44, 0x41,
- 0x54, 0x45, 0x44, 0x5f, 0x41, 0x54, 0x10, 0x03, 0x32, 0x99, 0x0c, 0x0a, 0x1e, 0x4b, 0x65, 0x79,
- 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69,
- 0x73, 0x74, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7e, 0x0a, 0x14, 0x4c,
- 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76,
- 0x65, 0x72, 0x73, 0x12, 0x2f, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73,
- 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79,
- 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61,
- 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65,
- 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x52, 0x65,
- 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x78, 0x0a, 0x12, 0x47,
+ 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x52, 0x49, 0x10, 0x02, 0x12, 0x2b, 0x0a, 0x27, 0x53, 0x4f,
+ 0x52, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x45,
+ 0x52, 0x56, 0x45, 0x52, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54,
+ 0x45, 0x44, 0x5f, 0x41, 0x54, 0x10, 0x03, 0x12, 0x2b, 0x0a, 0x27, 0x53, 0x4f, 0x52, 0x54, 0x5f,
+ 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45,
+ 0x52, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x44, 0x5f,
+ 0x41, 0x54, 0x10, 0x04, 0x2a, 0x9a, 0x01, 0x0a, 0x0f, 0x53, 0x6f, 0x72, 0x74, 0x4b, 0x61, 0x73,
+ 0x4b, 0x65, 0x79, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x1e, 0x53, 0x4f, 0x52, 0x54,
+ 0x5f, 0x4b, 0x41, 0x53, 0x5f, 0x4b, 0x45, 0x59, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55,
+ 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19,
+ 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x41, 0x53, 0x5f, 0x4b, 0x45, 0x59, 0x53, 0x5f, 0x54, 0x59,
+ 0x50, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x49, 0x44, 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x53,
+ 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x41, 0x53, 0x5f, 0x4b, 0x45, 0x59, 0x53, 0x5f, 0x54, 0x59, 0x50,
+ 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x41, 0x54, 0x10, 0x02, 0x12, 0x21,
+ 0x0a, 0x1d, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x41, 0x53, 0x5f, 0x4b, 0x45, 0x59, 0x53, 0x5f,
+ 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x41, 0x54, 0x10,
+ 0x03, 0x32, 0x99, 0x0c, 0x0a, 0x1e, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53,
+ 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x53, 0x65, 0x72,
+ 0x76, 0x69, 0x63, 0x65, 0x12, 0x7e, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41,
+ 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x2f, 0x2e, 0x70,
+ 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
+ 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53,
+ 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e,
+ 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74,
+ 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73,
+ 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
+ 0x03, 0x90, 0x02, 0x01, 0x12, 0x78, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63,
+ 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x2d, 0x2e, 0x70, 0x6f, 0x6c,
+ 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e,
+ 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76,
+ 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x70, 0x6f, 0x6c, 0x69,
+ 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x47,
0x65, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65,
- 0x72, 0x12, 0x2d, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65,
- 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63,
- 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
- 0x1a, 0x2e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67,
- 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65,
- 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
- 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x7e, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b,
- 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x30,
- 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73,
- 0x74, 0x72, 0x79, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63,
- 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
- 0x1a, 0x31, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67,
- 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41,
- 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f,
- 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b,
- 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x30,
- 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73,
- 0x74, 0x72, 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63,
- 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
- 0x1a, 0x31, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67,
- 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41,
- 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f,
- 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b,
- 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x30,
- 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73,
- 0x74, 0x72, 0x79, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63,
- 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
- 0x1a, 0x31, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67,
- 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41,
- 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f,
- 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x90, 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65,
- 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x47, 0x72, 0x61,
- 0x6e, 0x74, 0x73, 0x12, 0x34, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73,
- 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79,
- 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e,
- 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x70, 0x6f, 0x6c, 0x69,
- 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c,
- 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76,
- 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
- 0x22, 0x06, 0x88, 0x02, 0x01, 0x90, 0x02, 0x01, 0x12, 0x5a, 0x0a, 0x09, 0x43, 0x72, 0x65, 0x61,
- 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b,
- 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74,
- 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x6f,
- 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79,
- 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
- 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x21,
+ 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x7e,
+ 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73,
+ 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x30, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,
+ 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x43, 0x72, 0x65,
+ 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76,
+ 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x70, 0x6f, 0x6c, 0x69,
+ 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x43,
+ 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65,
+ 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e,
+ 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73,
+ 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x30, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,
+ 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x55, 0x70, 0x64,
+ 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76,
+ 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x70, 0x6f, 0x6c, 0x69,
+ 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x55,
+ 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65,
+ 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e,
+ 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73,
+ 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x30, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,
+ 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x44, 0x65, 0x6c,
+ 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76,
+ 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x70, 0x6f, 0x6c, 0x69,
+ 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x44,
+ 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65,
+ 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x90,
+ 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73,
+ 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x34, 0x2e, 0x70,
+ 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
+ 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53,
+ 0x65, 0x72, 0x76, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72,
+ 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41,
+ 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74,
+ 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0x88, 0x02, 0x01, 0x90, 0x02,
+ 0x01, 0x12, 0x5a, 0x0a, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x24,
0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73,
- 0x74, 0x72, 0x79, 0x2e, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
- 0x74, 0x1a, 0x22, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65,
- 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73,
- 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x57, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x4b,
- 0x65, 0x79, 0x73, 0x12, 0x23, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73,
- 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79,
- 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63,
- 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69,
- 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
- 0x12, 0x5a, 0x0a, 0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x2e,
- 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74,
- 0x72, 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75,
- 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73,
- 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b,
- 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x09,
- 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69,
- 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x52,
- 0x6f, 0x74, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+ 0x74, 0x72, 0x79, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61,
+ 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
+ 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a,
+ 0x06, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,
+ 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x47, 0x65, 0x74,
+ 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x70, 0x6f, 0x6c,
+ 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e,
+ 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
+ 0x12, 0x57, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x23, 0x2e, 0x70,
+ 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
+ 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x1a, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65,
+ 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x09, 0x55, 0x70, 0x64,
+ 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,
+ 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61,
+ 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70,
+ 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
+ 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x09, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x4b,
+ 0x65, 0x79, 0x12, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72,
+ 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x4b, 0x65,
+ 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63,
+ 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x52, 0x6f,
+ 0x74, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
+ 0x00, 0x12, 0x5d, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x12,
0x25, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69,
- 0x73, 0x74, 0x72, 0x79, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65,
- 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x42,
- 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,
+ 0x73, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,
0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x42,
- 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e,
- 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74,
- 0x72, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73,
- 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x42, 0x61,
- 0x73, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b,
+ 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
+ 0x12, 0x5d, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x25,
+ 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73,
+ 0x74, 0x72, 0x79, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b,
0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61,
- 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70,
- 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
- 0x79, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65,
- 0x79, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x2a, 0x2e, 0x70, 0x6f, 0x6c, 0x69,
- 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c,
- 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65,
- 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b,
- 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b,
- 0x65, 0x79, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
- 0x73, 0x65, 0x22, 0x00, 0x42, 0xdb, 0x01, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6c,
- 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x42,
- 0x1c, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
- 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a,
- 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e,
- 0x74, 0x64, 0x66, 0x2f, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2f,
- 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0xa2, 0x02, 0x03, 0x50, 0x4b,
- 0x58, 0xaa, 0x02, 0x12, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x72, 0x65,
- 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0xca, 0x02, 0x12, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5c,
- 0x4b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0xe2, 0x02, 0x1e, 0x50, 0x6f,
- 0x6c, 0x69, 0x63, 0x79, 0x5c, 0x4b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79,
- 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x13, 0x50,
- 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x3a, 0x3a, 0x4b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74,
- 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
+ 0x6c, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e,
+ 0x67, 0x73, 0x12, 0x2a, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72,
+ 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x4d,
+ 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b,
+ 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73,
+ 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x4d, 0x61, 0x70, 0x70, 0x69,
+ 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0xdb, 0x01,
+ 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73,
+ 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x42, 0x1c, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63,
+ 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
+ 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x64, 0x66, 0x2f, 0x70, 0x6c, 0x61,
+ 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x67,
+ 0x6f, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2f, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69,
+ 0x73, 0x74, 0x72, 0x79, 0xa2, 0x02, 0x03, 0x50, 0x4b, 0x58, 0xaa, 0x02, 0x12, 0x50, 0x6f, 0x6c,
+ 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0xca,
+ 0x02, 0x12, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5c, 0x4b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69,
+ 0x73, 0x74, 0x72, 0x79, 0xe2, 0x02, 0x1e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5c, 0x4b, 0x61,
+ 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x13, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x3a, 0x3a,
+ 0x4b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x33,
}
var (
diff --git a/protocol/go/policy/objects.pb.go b/protocol/go/policy/objects.pb.go
index e7f4f3eaed..7ef5a16e4d 100644
--- a/protocol/go/policy/objects.pb.go
+++ b/protocol/go/policy/objects.pb.go
@@ -364,6 +364,8 @@ const (
KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING KasPublicKeyAlgEnum = 10
KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768 KasPublicKeyAlgEnum = 11
KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024 KasPublicKeyAlgEnum = 12
+ KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768 KasPublicKeyAlgEnum = 20
+ KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 KasPublicKeyAlgEnum = 21
)
// Enum value maps for KasPublicKeyAlgEnum.
@@ -378,6 +380,8 @@ var (
10: "KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING",
11: "KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768",
12: "KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024",
+ 20: "KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768",
+ 21: "KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024",
}
KasPublicKeyAlgEnum_value = map[string]int32{
"KAS_PUBLIC_KEY_ALG_ENUM_UNSPECIFIED": 0,
@@ -389,6 +393,8 @@ var (
"KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING": 10,
"KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768": 11,
"KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024": 12,
+ "KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768": 20,
+ "KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024": 21,
}
)
@@ -432,20 +438,24 @@ const (
Algorithm_ALGORITHM_HPQT_XWING Algorithm = 6
Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768 Algorithm = 7
Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024 Algorithm = 8
+ Algorithm_ALGORITHM_MLKEM_768 Algorithm = 20
+ Algorithm_ALGORITHM_MLKEM_1024 Algorithm = 21
)
// Enum value maps for Algorithm.
var (
Algorithm_name = map[int32]string{
- 0: "ALGORITHM_UNSPECIFIED",
- 1: "ALGORITHM_RSA_2048",
- 2: "ALGORITHM_RSA_4096",
- 3: "ALGORITHM_EC_P256",
- 4: "ALGORITHM_EC_P384",
- 5: "ALGORITHM_EC_P521",
- 6: "ALGORITHM_HPQT_XWING",
- 7: "ALGORITHM_HPQT_SECP256R1_MLKEM768",
- 8: "ALGORITHM_HPQT_SECP384R1_MLKEM1024",
+ 0: "ALGORITHM_UNSPECIFIED",
+ 1: "ALGORITHM_RSA_2048",
+ 2: "ALGORITHM_RSA_4096",
+ 3: "ALGORITHM_EC_P256",
+ 4: "ALGORITHM_EC_P384",
+ 5: "ALGORITHM_EC_P521",
+ 6: "ALGORITHM_HPQT_XWING",
+ 7: "ALGORITHM_HPQT_SECP256R1_MLKEM768",
+ 8: "ALGORITHM_HPQT_SECP384R1_MLKEM1024",
+ 20: "ALGORITHM_MLKEM_768",
+ 21: "ALGORITHM_MLKEM_1024",
}
Algorithm_value = map[string]int32{
"ALGORITHM_UNSPECIFIED": 0,
@@ -457,6 +467,8 @@ var (
"ALGORITHM_HPQT_XWING": 6,
"ALGORITHM_HPQT_SECP256R1_MLKEM768": 7,
"ALGORITHM_HPQT_SECP384R1_MLKEM1024": 8,
+ "ALGORITHM_MLKEM_768": 20,
+ "ALGORITHM_MLKEM_1024": 21,
}
)
@@ -4174,7 +4186,7 @@ var file_policy_objects_proto_rawDesc = []byte{
0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x4f,
0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e,
0x41, 0x4c, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54,
- 0x59, 0x50, 0x45, 0x5f, 0x45, 0x58, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x02, 0x2a, 0x9b,
+ 0x59, 0x50, 0x45, 0x5f, 0x45, 0x58, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x02, 0x2a, 0xea,
0x03, 0x0a, 0x13, 0x4b, 0x61, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x41,
0x6c, 0x67, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x27, 0x0a, 0x23, 0x4b, 0x41, 0x53, 0x5f, 0x50, 0x55,
0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x5f, 0x45, 0x4e, 0x55,
@@ -4200,47 +4212,56 @@ var file_policy_objects_proto_rawDesc = []byte{
0x4d, 0x37, 0x36, 0x38, 0x10, 0x0b, 0x12, 0x34, 0x0a, 0x30, 0x4b, 0x41, 0x53, 0x5f, 0x50, 0x55,
0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x5f, 0x45, 0x4e, 0x55,
0x4d, 0x5f, 0x48, 0x50, 0x51, 0x54, 0x5f, 0x53, 0x45, 0x43, 0x50, 0x33, 0x38, 0x34, 0x52, 0x31,
- 0x5f, 0x4d, 0x4c, 0x4b, 0x45, 0x4d, 0x31, 0x30, 0x32, 0x34, 0x10, 0x0c, 0x2a, 0x84, 0x02, 0x0a,
- 0x09, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x4c,
- 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46,
- 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54,
- 0x48, 0x4d, 0x5f, 0x52, 0x53, 0x41, 0x5f, 0x32, 0x30, 0x34, 0x38, 0x10, 0x01, 0x12, 0x16, 0x0a,
- 0x12, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x52, 0x53, 0x41, 0x5f, 0x34,
- 0x30, 0x39, 0x36, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54,
- 0x48, 0x4d, 0x5f, 0x45, 0x43, 0x5f, 0x50, 0x32, 0x35, 0x36, 0x10, 0x03, 0x12, 0x15, 0x0a, 0x11,
- 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x45, 0x43, 0x5f, 0x50, 0x33, 0x38,
- 0x34, 0x10, 0x04, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d,
- 0x5f, 0x45, 0x43, 0x5f, 0x50, 0x35, 0x32, 0x31, 0x10, 0x05, 0x12, 0x18, 0x0a, 0x14, 0x41, 0x4c,
- 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x48, 0x50, 0x51, 0x54, 0x5f, 0x58, 0x57, 0x49,
- 0x4e, 0x47, 0x10, 0x06, 0x12, 0x25, 0x0a, 0x21, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48,
- 0x4d, 0x5f, 0x48, 0x50, 0x51, 0x54, 0x5f, 0x53, 0x45, 0x43, 0x50, 0x32, 0x35, 0x36, 0x52, 0x31,
- 0x5f, 0x4d, 0x4c, 0x4b, 0x45, 0x4d, 0x37, 0x36, 0x38, 0x10, 0x07, 0x12, 0x26, 0x0a, 0x22, 0x41,
- 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x48, 0x50, 0x51, 0x54, 0x5f, 0x53, 0x45,
- 0x43, 0x50, 0x33, 0x38, 0x34, 0x52, 0x31, 0x5f, 0x4d, 0x4c, 0x4b, 0x45, 0x4d, 0x31, 0x30, 0x32,
- 0x34, 0x10, 0x08, 0x2a, 0x56, 0x0a, 0x09, 0x4b, 0x65, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
- 0x12, 0x1a, 0x0a, 0x16, 0x4b, 0x45, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55,
- 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11,
- 0x4b, 0x45, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56,
- 0x45, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x4b, 0x45, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55,
- 0x53, 0x5f, 0x52, 0x4f, 0x54, 0x41, 0x54, 0x45, 0x44, 0x10, 0x02, 0x2a, 0x94, 0x01, 0x0a, 0x07,
- 0x4b, 0x65, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x4b, 0x45, 0x59, 0x5f, 0x4d,
- 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10,
- 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x43, 0x4f,
- 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x01, 0x12,
- 0x1e, 0x0a, 0x1a, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x56,
- 0x49, 0x44, 0x45, 0x52, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x02, 0x12,
- 0x13, 0x0a, 0x0f, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x52, 0x45, 0x4d, 0x4f,
- 0x54, 0x45, 0x10, 0x03, 0x12, 0x1c, 0x0a, 0x18, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45,
- 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x4e, 0x4c, 0x59,
- 0x10, 0x04, 0x42, 0x82, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63,
- 0x79, 0x42, 0x0c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50,
- 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70,
- 0x65, 0x6e, 0x74, 0x64, 0x66, 0x2f, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x70,
- 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63,
- 0x79, 0xa2, 0x02, 0x03, 0x50, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79,
- 0xca, 0x02, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0xe2, 0x02, 0x12, 0x50, 0x6f, 0x6c, 0x69,
- 0x63, 0x79, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02,
- 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x5f, 0x4d, 0x4c, 0x4b, 0x45, 0x4d, 0x31, 0x30, 0x32, 0x34, 0x10, 0x0c, 0x12, 0x25, 0x0a, 0x21,
+ 0x4b, 0x41, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41,
+ 0x4c, 0x47, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x4d, 0x4c, 0x4b, 0x45, 0x4d, 0x5f, 0x37, 0x36,
+ 0x38, 0x10, 0x14, 0x12, 0x26, 0x0a, 0x22, 0x4b, 0x41, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49,
+ 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x4d,
+ 0x4c, 0x4b, 0x45, 0x4d, 0x5f, 0x31, 0x30, 0x32, 0x34, 0x10, 0x15, 0x2a, 0xb7, 0x02, 0x0a, 0x09,
+ 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x4c, 0x47,
+ 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49,
+ 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48,
+ 0x4d, 0x5f, 0x52, 0x53, 0x41, 0x5f, 0x32, 0x30, 0x34, 0x38, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12,
+ 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x52, 0x53, 0x41, 0x5f, 0x34, 0x30,
+ 0x39, 0x36, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48,
+ 0x4d, 0x5f, 0x45, 0x43, 0x5f, 0x50, 0x32, 0x35, 0x36, 0x10, 0x03, 0x12, 0x15, 0x0a, 0x11, 0x41,
+ 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x45, 0x43, 0x5f, 0x50, 0x33, 0x38, 0x34,
+ 0x10, 0x04, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f,
+ 0x45, 0x43, 0x5f, 0x50, 0x35, 0x32, 0x31, 0x10, 0x05, 0x12, 0x18, 0x0a, 0x14, 0x41, 0x4c, 0x47,
+ 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x48, 0x50, 0x51, 0x54, 0x5f, 0x58, 0x57, 0x49, 0x4e,
+ 0x47, 0x10, 0x06, 0x12, 0x25, 0x0a, 0x21, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d,
+ 0x5f, 0x48, 0x50, 0x51, 0x54, 0x5f, 0x53, 0x45, 0x43, 0x50, 0x32, 0x35, 0x36, 0x52, 0x31, 0x5f,
+ 0x4d, 0x4c, 0x4b, 0x45, 0x4d, 0x37, 0x36, 0x38, 0x10, 0x07, 0x12, 0x26, 0x0a, 0x22, 0x41, 0x4c,
+ 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x48, 0x50, 0x51, 0x54, 0x5f, 0x53, 0x45, 0x43,
+ 0x50, 0x33, 0x38, 0x34, 0x52, 0x31, 0x5f, 0x4d, 0x4c, 0x4b, 0x45, 0x4d, 0x31, 0x30, 0x32, 0x34,
+ 0x10, 0x08, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f,
+ 0x4d, 0x4c, 0x4b, 0x45, 0x4d, 0x5f, 0x37, 0x36, 0x38, 0x10, 0x14, 0x12, 0x18, 0x0a, 0x14, 0x41,
+ 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x4d, 0x4c, 0x4b, 0x45, 0x4d, 0x5f, 0x31,
+ 0x30, 0x32, 0x34, 0x10, 0x15, 0x2a, 0x56, 0x0a, 0x09, 0x4b, 0x65, 0x79, 0x53, 0x74, 0x61, 0x74,
+ 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x16, 0x4b, 0x45, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53,
+ 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15,
+ 0x0a, 0x11, 0x4b, 0x45, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, 0x43, 0x54,
+ 0x49, 0x56, 0x45, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x4b, 0x45, 0x59, 0x5f, 0x53, 0x54, 0x41,
+ 0x54, 0x55, 0x53, 0x5f, 0x52, 0x4f, 0x54, 0x41, 0x54, 0x45, 0x44, 0x10, 0x02, 0x2a, 0x94, 0x01,
+ 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x4b, 0x45, 0x59,
+ 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45,
+ 0x44, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f,
+ 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x10,
+ 0x01, 0x12, 0x1e, 0x0a, 0x1a, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x52,
+ 0x4f, 0x56, 0x49, 0x44, 0x45, 0x52, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x10,
+ 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x52, 0x45,
+ 0x4d, 0x4f, 0x54, 0x45, 0x10, 0x03, 0x12, 0x1c, 0x0a, 0x18, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f,
+ 0x44, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x4e,
+ 0x4c, 0x59, 0x10, 0x04, 0x42, 0x82, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6c,
+ 0x69, 0x63, 0x79, 0x42, 0x0c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x50, 0x72, 0x6f, 0x74,
+ 0x6f, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+ 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x64, 0x66, 0x2f, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d,
+ 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x6f, 0x6c,
+ 0x69, 0x63, 0x79, 0xa2, 0x02, 0x03, 0x50, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x50, 0x6f, 0x6c, 0x69,
+ 0x63, 0x79, 0xca, 0x02, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0xe2, 0x02, 0x12, 0x50, 0x6f,
+ 0x6c, 0x69, 0x63, 0x79, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+ 0xea, 0x02, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x33,
}
var (
diff --git a/sdk/basekey.go b/sdk/basekey.go
index 96f43f927c..a445729acd 100644
--- a/sdk/basekey.go
+++ b/sdk/basekey.go
@@ -46,6 +46,10 @@ func KeyTypeToPolicyAlgorithm(kt ocrypto.KeyType) (policy.Algorithm, error) {
return policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768, nil
case ocrypto.HybridSecp384r1MLKEM1024Key:
return policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024, nil
+ case ocrypto.MLKEM768Key:
+ return policy.Algorithm_ALGORITHM_MLKEM_768, nil
+ case ocrypto.MLKEM1024Key:
+ return policy.Algorithm_ALGORITHM_MLKEM_1024, nil
default:
return policy.Algorithm_ALGORITHM_UNSPECIFIED, fmt.Errorf("unknown key type: %s", kt)
}
@@ -69,6 +73,10 @@ func PolicyAlgorithmToKeyType(alg policy.Algorithm) (ocrypto.KeyType, error) {
return ocrypto.HybridSecp256r1MLKEM768Key, nil
case policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024:
return ocrypto.HybridSecp384r1MLKEM1024Key, nil
+ case policy.Algorithm_ALGORITHM_MLKEM_768:
+ return ocrypto.MLKEM768Key, nil
+ case policy.Algorithm_ALGORITHM_MLKEM_1024:
+ return ocrypto.MLKEM1024Key, nil
case policy.Algorithm_ALGORITHM_UNSPECIFIED:
fallthrough
default:
diff --git a/sdk/experimental/tdf/key_access.go b/sdk/experimental/tdf/key_access.go
index 3974b06cf4..ad849c739c 100644
--- a/sdk/experimental/tdf/key_access.go
+++ b/sdk/experimental/tdf/key_access.go
@@ -165,8 +165,8 @@ func wrapKeyWithPublicKey(symKey []byte, pubKeyInfo keysplit.KASPublicKey) (stri
// Determine key type based on algorithm
ktype := ocrypto.KeyType(pubKeyInfo.Algorithm)
- if ocrypto.IsHybridKeyType(ktype) {
- return wrapKeyWithHybrid(ktype, pubKeyInfo.PEM, symKey)
+ if ocrypto.IsKEMKeyType(ktype) {
+ return wrapKeyWithKEM(ktype, pubKeyInfo.PEM, symKey)
}
if ocrypto.IsECKeyType(ktype) {
// Handle EC key wrapping
@@ -249,10 +249,18 @@ func wrapKeyWithRSA(kasPublicKeyPEM string, symKey []byte) (string, error) {
return string(ocrypto.Base64Encode(encryptedKey)), nil
}
-func wrapKeyWithHybrid(ktype ocrypto.KeyType, kasPublicKeyPEM string, symKey []byte) (string, string, string, error) {
- wrappedDER, err := ocrypto.HybridWrapDEK(ktype, kasPublicKeyPEM, symKey)
+// wrapKeyWithKEM wraps a DEK with any KEM scheme — pure ML-KEM or hybrid
+// (X-Wing, NIST PQ/T). Returns the base64-encoded envelope, the manifest
+// scheme name (`hybrid-wrapped` or `mlkem-wrapped`), and an empty ephemeral
+// key string (KEMs do not emit one in this profile).
+func wrapKeyWithKEM(ktype ocrypto.KeyType, kasPublicKeyPEM string, symKey []byte) (string, string, string, error) {
+ wrappedDER, err := ocrypto.WrapDEK(ktype, kasPublicKeyPEM, symKey)
if err != nil {
- return "", "", "", fmt.Errorf("hybrid wrap failed: %w", err)
+ return "", "", "", fmt.Errorf("kem wrap failed: %w", err)
}
- return string(ocrypto.Base64Encode(wrappedDER)), "hybrid-wrapped", "", nil
+ scheme := "hybrid-wrapped"
+ if ocrypto.IsMLKEMKeyType(ktype) {
+ scheme = "mlkem-wrapped"
+ }
+ return string(ocrypto.Base64Encode(wrappedDER)), scheme, "", nil
}
diff --git a/sdk/experimental/tdf/keysplit/attributes.go b/sdk/experimental/tdf/keysplit/attributes.go
index 27cc1e386f..f21fab3824 100644
--- a/sdk/experimental/tdf/keysplit/attributes.go
+++ b/sdk/experimental/tdf/keysplit/attributes.go
@@ -213,6 +213,10 @@ func convertAlgEnum2Simple(a policy.KasPublicKeyAlgEnum) policy.Algorithm {
return policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768
case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024:
return policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768:
+ return policy.Algorithm_ALGORITHM_MLKEM_768
+ case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024:
+ return policy.Algorithm_ALGORITHM_MLKEM_1024
case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_UNSPECIFIED:
return policy.Algorithm_ALGORITHM_UNSPECIFIED
default:
diff --git a/sdk/granter.go b/sdk/granter.go
index ede578cc17..571616efa0 100644
--- a/sdk/granter.go
+++ b/sdk/granter.go
@@ -292,6 +292,10 @@ func convertAlgEnum2Simple(a policy.KasPublicKeyAlgEnum) policy.Algorithm {
return policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768
case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024:
return policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768:
+ return policy.Algorithm_ALGORITHM_MLKEM_768
+ case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024:
+ return policy.Algorithm_ALGORITHM_MLKEM_1024
case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_UNSPECIFIED:
return policy.Algorithm_ALGORITHM_UNSPECIFIED
default:
@@ -484,6 +488,10 @@ func algProto2String(e policy.KasPublicKeyAlgEnum) string {
return string(ocrypto.HybridSecp256r1MLKEM768Key)
case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024:
return string(ocrypto.HybridSecp384r1MLKEM1024Key)
+ case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768:
+ return string(ocrypto.MLKEM768Key)
+ case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024:
+ return string(ocrypto.MLKEM1024Key)
case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_UNSPECIFIED:
return ""
}
diff --git a/sdk/idp_access_token_source.go b/sdk/idp_access_token_source.go
index 9b84b4022f..7290be61dc 100644
--- a/sdk/idp_access_token_source.go
+++ b/sdk/idp_access_token_source.go
@@ -37,10 +37,14 @@ func getNewDPoPKey(dpopKeyPair *ocrypto.RsaKeyPair) (string, jwk.Key, *ocrypto.A
return "", nil, nil, fmt.Errorf("error setting the key algorithm: %w", err)
}
- asymDecryption, err := ocrypto.NewAsymDecryption(dpopPrivateKeyPEM)
+ decryptor, err := ocrypto.FromPrivatePEM(dpopPrivateKeyPEM)
if err != nil {
return "", nil, nil, fmt.Errorf("error creating asymmetric decryptor: %w", err)
}
+ asymDecryption, ok := decryptor.(ocrypto.AsymDecryption)
+ if !ok {
+ return "", nil, nil, fmt.Errorf("DPoP key is not an RSA private key: %T", decryptor)
+ }
return dpopPublicKeyPEM, dpopKey, &asymDecryption, nil
}
diff --git a/sdk/kas_client.go b/sdk/kas_client.go
index bb2b1f7f3a..b9c0374f99 100644
--- a/sdk/kas_client.go
+++ b/sdk/kas_client.go
@@ -273,9 +273,13 @@ func (k *KASClient) handleRSAKeyResponse(response *kas.RewrapResponse) (map[stri
return nil, fmt.Errorf("ocrypto.PrivateKeyInPemFormat failed: %w", err)
}
- asymDecryption, err := ocrypto.NewAsymDecryption(clientPrivateKey)
+ decryptor, err := ocrypto.FromPrivatePEM(clientPrivateKey)
if err != nil {
- return nil, fmt.Errorf("ocrypto.NewAsymDecryption failed: %w", err)
+ return nil, fmt.Errorf("ocrypto.FromPrivatePEM failed: %w", err)
+ }
+ asymDecryption, ok := decryptor.(ocrypto.AsymDecryption)
+ if !ok {
+ return nil, fmt.Errorf("session key is not an RSA private key: %T", decryptor)
}
return k.processRSAResponse(response, asymDecryption)
diff --git a/sdk/kas_client_test.go b/sdk/kas_client_test.go
index 7fd4b6b60c..2d2df7e167 100644
--- a/sdk/kas_client_test.go
+++ b/sdk/kas_client_test.go
@@ -42,7 +42,10 @@ func (fake FakeAccessTokenSource) MakeToken(tokenMaker func(jwk.Key) ([]byte, er
func getTokenSource(t *testing.T) FakeAccessTokenSource {
dpopKey, _ := ocrypto.NewRSAKeyPair(2048)
dpopPEM, _ := dpopKey.PrivateKeyInPemFormat()
- decryption, _ := ocrypto.NewAsymDecryption(dpopPEM)
+ dpopDecryptor, err := ocrypto.FromPrivatePEM(dpopPEM)
+ require.NoError(t, err)
+ decryption, ok := dpopDecryptor.(ocrypto.AsymDecryption)
+ require.True(t, ok, "expected RSA decryptor, got %T", dpopDecryptor)
dpopPEMPublic, _ := dpopKey.PublicKeyInPemFormat()
encryption, _ := ocrypto.FromPublicPEM(dpopPEMPublic)
dpopJWK, err := jwk.ParseKey([]byte(dpopPEM), jwk.WithPEM(true))
@@ -130,7 +133,8 @@ func TestCreatingRequest(t *testing.T) {
}
func Test_StoreKASKeys(t *testing.T) {
- s, err := New("http://localhost:8080",
+ s, err := New(
+ "http://localhost:8080",
WithPlatformConfiguration(PlatformConfiguration{
"idp": map[string]interface{}{
"issuer": "https://example.org",
@@ -457,8 +461,10 @@ func Test_processRSAResponse(t *testing.T) {
require.NoError(t, err)
privateKeyPEM, err := mockPrivateKey.PrivateKeyInPemFormat()
require.NoError(t, err)
- mockDecryptor, err := ocrypto.NewAsymDecryption(privateKeyPEM)
+ mockPrivateDecryptor, err := ocrypto.FromPrivatePEM(privateKeyPEM)
require.NoError(t, err)
+ mockDecryptor, ok := mockPrivateDecryptor.(ocrypto.AsymDecryption)
+ require.True(t, ok)
// Create a mock AsymEncryption to create the wrapped key
publicKeyPEM, err := mockPrivateKey.PublicKeyInPemFormat()
diff --git a/sdk/tdf.go b/sdk/tdf.go
index 1d6ef1182c..ce42099603 100644
--- a/sdk/tdf.go
+++ b/sdk/tdf.go
@@ -44,6 +44,7 @@ const (
kWrapped = "wrapped"
kECWrapped = "ec-wrapped"
kHybridWrapped = "hybrid-wrapped"
+ kMLKEMWrapped = "mlkem-wrapped"
kKasProtocol = "kas"
kSplitKeyType = "split"
kGCMCipherAlgorithm = "AES-256-GCM"
@@ -676,12 +677,12 @@ func createKeyAccess(kasInfo KASInfo, symKey []byte, policyBinding PolicyBinding
ktype := ocrypto.KeyType(kasInfo.Algorithm)
switch {
- case ocrypto.IsHybridKeyType(ktype):
- wrappedKey, err := generateWrapKeyWithHybrid(kasInfo.Algorithm, kasInfo.PublicKey, symKey)
+ case ocrypto.IsKEMKeyType(ktype):
+ wrappedKey, scheme, err := generateWrapKeyWithKEM(ktype, kasInfo.PublicKey, symKey)
if err != nil {
return KeyAccess{}, err
}
- keyAccess.KeyType = kHybridWrapped
+ keyAccess.KeyType = scheme
keyAccess.WrappedKey = wrappedKey
case ocrypto.IsECKeyType(ktype):
mode, err := ocrypto.ECKeyTypeToMode(ktype)
@@ -770,12 +771,19 @@ func generateWrapKeyWithRSA(publicKey string, symKey []byte) (string, error) {
return string(ocrypto.Base64Encode(wrappedKey)), nil
}
-func generateWrapKeyWithHybrid(algorithm, publicKeyPEM string, symKey []byte) (string, error) {
- wrappedDER, err := ocrypto.HybridWrapDEK(ocrypto.KeyType(algorithm), publicKeyPEM, symKey)
+// generateWrapKeyWithKEM wraps a DEK with any KEM scheme — pure ML-KEM or
+// hybrid (X-Wing, NIST PQ/T). Returns the base64-encoded envelope and the
+// wire scheme name (`hybrid-wrapped` or `mlkem-wrapped`) for the manifest.
+func generateWrapKeyWithKEM(ktype ocrypto.KeyType, publicKeyPEM string, symKey []byte) (string, string, error) {
+ wrappedDER, err := ocrypto.WrapDEK(ktype, publicKeyPEM, symKey)
if err != nil {
- return "", fmt.Errorf("generateWrapKeyWithHybrid: %w", err)
+ return "", "", fmt.Errorf("generateWrapKeyWithKEM: %w", err)
}
- return string(ocrypto.Base64Encode(wrappedDER)), nil
+ scheme := kHybridWrapped
+ if ocrypto.IsMLKEMKeyType(ktype) {
+ scheme = kMLKEMWrapped
+ }
+ return string(ocrypto.Base64Encode(wrappedDER)), scheme, nil
}
// create policy object
@@ -1247,7 +1255,7 @@ func createRewrapRequest(_ context.Context, r *Reader) (map[string]*kas.Unsigned
invalidPolicy = !ok
alg, ok = policyBinding["alg"].(string)
invalidPolicy = invalidPolicy || !ok
- case (PolicyBinding):
+ case PolicyBinding:
hash = policyBinding.Hash
alg = policyBinding.Alg
default:
diff --git a/sdk/tdf_test.go b/sdk/tdf_test.go
index de75b9a8d2..2124c97003 100644
--- a/sdk/tdf_test.go
+++ b/sdk/tdf_test.go
@@ -3127,8 +3127,8 @@ func (f *FakeKas) getRewrapResponse(rewrapRequest string, fulfillableObligations
kasPrivateKey = strings.ReplaceAll(lk.private, "\n\t", "\n")
}
- asymDecrypt, err := ocrypto.NewAsymDecryption(kasPrivateKey)
- f.s.Require().NoError(err, "ocrypto.NewAsymDecryption failed")
+ asymDecrypt, err := ocrypto.FromPrivatePEM(kasPrivateKey)
+ f.s.Require().NoError(err, "ocrypto.FromPrivatePEM failed")
symmetricKey, err := asymDecrypt.Decrypt(wrappedKey)
f.s.Require().NoError(err, "ocrypto.Decrypt failed for kao:[%s # %s (%s)] kas:[%s # %s (%s)]", kao.GetKasUrl(), kao.GetKid(), kao.GetSplitId(), f.URL, f.KID, f.Algorithm)
asymEncrypt, err := ocrypto.FromPublicPEM(bodyData.GetClientPublicKey())
diff --git a/service/cmd/keygen/main.go b/service/cmd/keygen/main.go
index 721191e286..f182339e6e 100644
--- a/service/cmd/keygen/main.go
+++ b/service/cmd/keygen/main.go
@@ -1,4 +1,4 @@
-// Package main generates hybrid post-quantum KAS key pairs (X-Wing, P256+ML-KEM-768, P384+ML-KEM-1024)
+// Package main generates post-quantum KAS key pairs (X-Wing, P256+ML-KEM-768, P384+ML-KEM-1024, ML-KEM-768, ML-KEM-1024)
// as PEM files for use with the OpenTDF platform.
package main
@@ -45,6 +45,18 @@ func main() {
privateOut: "kas-p384mlkem1024-private.pem",
publicOut: "kas-p384mlkem1024-public.pem",
},
+ {
+ name: "ML-KEM-768",
+ newKeyPair: generateMLKEM768,
+ privateOut: "kas-mlkem768-private.pem",
+ publicOut: "kas-mlkem768-public.pem",
+ },
+ {
+ name: "ML-KEM-1024",
+ newKeyPair: generateMLKEM1024,
+ privateOut: "kas-mlkem1024-private.pem",
+ publicOut: "kas-mlkem1024-public.pem",
+ },
}
for _, s := range specs {
@@ -114,3 +126,35 @@ func generateP384MLKEM1024() (string, string, error) {
}
return priv, pub, nil
}
+
+func generateMLKEM768() (string, string, error) {
+ kp, err := ocrypto.NewMLKEMKeyPair()
+ if err != nil {
+ return "", "", err
+ }
+ priv, err := kp.PrivateKeyInPemFormat()
+ if err != nil {
+ return "", "", err
+ }
+ pub, err := kp.PublicKeyInPemFormat()
+ if err != nil {
+ return "", "", err
+ }
+ return priv, pub, nil
+}
+
+func generateMLKEM1024() (string, string, error) {
+ kp, err := ocrypto.NewMLKEM1024KeyPair()
+ if err != nil {
+ return "", "", err
+ }
+ priv, err := kp.PrivateKeyInPemFormat()
+ if err != nil {
+ return "", "", err
+ }
+ pub, err := kp.PublicKeyInPemFormat()
+ if err != nil {
+ return "", "", err
+ }
+ return priv, pub, nil
+}
diff --git a/service/internal/security/basic_manager.go b/service/internal/security/basic_manager.go
index 12443eaa25..d746e06917 100644
--- a/service/internal/security/basic_manager.go
+++ b/service/internal/security/basic_manager.go
@@ -38,6 +38,8 @@ var BasicManagerSupportedAlgorithms = []ocrypto.KeyType{
ocrypto.HybridXWingKey,
ocrypto.HybridSecp256r1MLKEM768Key,
ocrypto.HybridSecp384r1MLKEM1024Key,
+ ocrypto.MLKEM768Key,
+ ocrypto.MLKEM1024Key,
}
type BasicManager struct {
@@ -82,17 +84,14 @@ func (b *BasicManager) Decrypt(ctx context.Context, keyDetails trust.KeyDetails,
return nil, fmt.Errorf("failed to create decryptor from private PEM: %w", err)
}
- switch keyDetails.Algorithm() {
+ alg := keyDetails.Algorithm()
+ switch alg { //nolint:exhaustive // KEM key types are handled by the IsKEMKeyType branch below
case ocrypto.RSA2048Key, ocrypto.RSA4096Key:
plaintext, err := decrypter.Decrypt(ciphertext)
if err != nil {
return nil, fmt.Errorf("failed to decrypt with RSA: %w", err)
}
- protectedKey, err := ocrypto.NewAESProtectedKey(plaintext)
- if err != nil {
- return nil, fmt.Errorf("failed to create protected key: %w", err)
- }
- return protectedKey, nil
+ return ocrypto.NewAESProtectedKey(plaintext)
case ocrypto.EC256Key, ocrypto.EC384Key, ocrypto.EC521Key:
ecPrivKey, err := ocrypto.ECPrivateKeyFromPem(privKey)
if err != nil {
@@ -106,34 +105,27 @@ func (b *BasicManager) Decrypt(ctx context.Context, keyDetails trust.KeyDetails,
if err != nil {
return nil, fmt.Errorf("failed to decrypt with ephemeral key: %w", err)
}
- protectedKey, err := ocrypto.NewAESProtectedKey(plaintext)
- if err != nil {
- return nil, fmt.Errorf("failed to create protected key: %w", err)
- }
- return protectedKey, nil
- case ocrypto.HybridXWingKey, ocrypto.HybridSecp256r1MLKEM768Key, ocrypto.HybridSecp384r1MLKEM1024Key:
+ return ocrypto.NewAESProtectedKey(plaintext)
+ }
+
+ if ocrypto.IsKEMKeyType(alg) {
if len(ephemeralPublicKey) > 0 {
- return nil, errors.New("ephemeral public key should not be provided for hybrid decryption")
+ return nil, fmt.Errorf("ephemeral public key should not be provided for %s decryption", alg)
}
- // FromPrivatePEM routes by the OID inside the PKCS#8 envelope. Cross-
- // check the routed decryptor against the algorithm the key record
- // claims; a mismatch means the stored PEM does not match its metadata.
- kt, ok := decrypter.(interface{ KeyType() ocrypto.KeyType })
- if !ok || kt.KeyType() != keyDetails.Algorithm() {
- return nil, fmt.Errorf("hybrid key %s algorithm mismatch: PEM dispatched away from %s", keyDetails.ID(), keyDetails.Algorithm())
+ // FromPrivatePEM routes by the OID inside the SPKI/PKCS#8 envelope. Cross-
+ // check the routed decryptor against the algorithm the key record claims;
+ // a mismatch means the stored PEM does not match its metadata.
+ if kt, ok := decrypter.(interface{ KeyType() ocrypto.KeyType }); !ok || kt.KeyType() != alg {
+ return nil, fmt.Errorf("KEM key %s algorithm mismatch: PEM dispatched away from %s", keyDetails.ID(), alg)
}
plaintext, err := decrypter.Decrypt(ciphertext)
if err != nil {
- return nil, fmt.Errorf("failed to decrypt with hybrid [%s]: %w", keyDetails.Algorithm(), err)
- }
- protectedKey, err := ocrypto.NewAESProtectedKey(plaintext)
- if err != nil {
- return nil, fmt.Errorf("failed to create protected key: %w", err)
+ return nil, fmt.Errorf("failed to decrypt with %s: %w", alg, err)
}
- return protectedKey, nil
+ return ocrypto.NewAESProtectedKey(plaintext)
}
- return nil, fmt.Errorf("unsupported algorithm: %s", keyDetails.Algorithm())
+ return nil, fmt.Errorf("unsupported algorithm: %s", alg)
}
func (b *BasicManager) DeriveKey(ctx context.Context, keyDetails trust.KeyDetails, ephemeralPublicKeyBytes []byte, curve elliptic.Curve) (ocrypto.ProtectedKey, error) {
diff --git a/service/internal/security/crypto_provider.go b/service/internal/security/crypto_provider.go
index dcbe1ae5a1..4a0b9a28ec 100644
--- a/service/internal/security/crypto_provider.go
+++ b/service/internal/security/crypto_provider.go
@@ -18,4 +18,8 @@ const (
// Used for hybrid NIST EC + ML-KEM wrapping of the KAO
AlgorithmHPQTSecp256r1MLKEM768 = "hpqt:secp256r1-mlkem768"
AlgorithmHPQTSecp384r1MLKEM1024 = "hpqt:secp384r1-mlkem1024"
+
+ // Used for encryption with ML-KEM of the KAO
+ AlgorithmMLKEM768 = "mlkem:768"
+ AlgorithmMLKEM1024 = "mlkem:1024"
)
diff --git a/service/internal/security/in_process_provider.go b/service/internal/security/in_process_provider.go
index 7d4b624e22..bf1d99c3c8 100644
--- a/service/internal/security/in_process_provider.go
+++ b/service/internal/security/in_process_provider.go
@@ -27,6 +27,8 @@ var InProcessSupportedAlgorithms = []ocrypto.KeyType{
ocrypto.HybridXWingKey,
ocrypto.HybridSecp256r1MLKEM768Key,
ocrypto.HybridSecp384r1MLKEM1024Key,
+ ocrypto.MLKEM768Key,
+ ocrypto.MLKEM1024Key,
}
func convertPEMToJWK(_ string) (string, error) {
@@ -96,11 +98,8 @@ func (k *KeyDetailsAdapter) ExportPublicKey(_ context.Context, format trust.KeyT
if rsaKey, err := k.cryptoProvider.RSAPublicKey(kid); err == nil {
return rsaKey, nil
}
- if hybridKey, err := k.cryptoProvider.HybridPublicKey(kid); err == nil {
- return hybridKey, nil
- }
- if xwingKey, err := k.cryptoProvider.XWingPublicKey(kid); err == nil {
- return xwingKey, nil
+ if kemKey, err := k.cryptoProvider.KEMPublicKey(kid); err == nil {
+ return kemKey, nil
}
return k.cryptoProvider.ECPublicKey(kid)
default:
@@ -274,6 +273,12 @@ func (a *InProcessProvider) Decrypt(ctx context.Context, keyDetails trust.KeyDet
}
return a.cryptoProvider.Decrypt(ctx, trust.KeyIdentifier(kid), ciphertext, nil)
+ case AlgorithmMLKEM768, AlgorithmMLKEM1024:
+ if len(ephemeralPublicKey) > 0 {
+ return nil, errors.New("ephemeral public key should not be provided for ML-KEM decryption")
+ }
+ return a.cryptoProvider.Decrypt(ctx, trust.KeyIdentifier(kid), ciphertext, nil)
+
default:
return nil, errors.New("unsupported key algorithm")
}
@@ -360,9 +365,7 @@ func (a *InProcessProvider) determineKeyType(kid string) (string, error) {
return key.Algorithm, nil
case StandardECCrypto:
return key.Algorithm, nil
- case StandardXWingCrypto:
- return key.Algorithm, nil
- case StandardHybridCrypto:
+ case StandardKEMCrypto:
return key.Algorithm, nil
}
diff --git a/service/internal/security/in_process_provider_test.go b/service/internal/security/in_process_provider_test.go
index 9870ad53bb..e56eca2cfc 100644
--- a/service/internal/security/in_process_provider_test.go
+++ b/service/internal/security/in_process_provider_test.go
@@ -229,3 +229,29 @@ func TestInProcessProviderDetermineKeyType(t *testing.T) {
_, err = provider.determineKeyType("missing")
require.Error(t, err)
}
+
+func TestInProcessProviderDetermineKeyTypeMLKEM(t *testing.T) {
+ cryptoProvider, material := newStandardCryptoWithMLKEMForTest(t)
+ providerIface := NewSecurityProviderAdapter(cryptoProvider, nil, nil)
+ provider, ok := providerIface.(*InProcessProvider)
+ require.True(t, ok)
+
+ keyType, err := provider.determineKeyType(material.mlkem768Kid)
+ require.NoError(t, err)
+ assert.Equal(t, AlgorithmMLKEM768, keyType)
+
+ keyType, err = provider.determineKeyType(material.mlkem1024Kid)
+ require.NoError(t, err)
+ assert.Equal(t, AlgorithmMLKEM1024, keyType)
+
+ details, err := provider.FindKeyByID(t.Context(), trust.KeyIdentifier(material.mlkem768Kid))
+ require.NoError(t, err)
+ assert.Equal(t, ocrypto.KeyType(AlgorithmMLKEM768), details.Algorithm())
+
+ details, err = provider.FindKeyByID(t.Context(), trust.KeyIdentifier(material.mlkem1024Kid))
+ require.NoError(t, err)
+ assert.Equal(t, ocrypto.KeyType(AlgorithmMLKEM1024), details.Algorithm())
+
+ _, err = provider.determineKeyType("missing")
+ require.Error(t, err)
+}
diff --git a/service/internal/security/standard_crypto.go b/service/internal/security/standard_crypto.go
index cbc3d1cdf0..8713712678 100644
--- a/service/internal/security/standard_crypto.go
+++ b/service/internal/security/standard_crypto.go
@@ -67,16 +67,14 @@ type StandardECCrypto struct {
sk *ecdh.PrivateKey
}
-type StandardXWingCrypto struct {
+// StandardKEMCrypto holds any KEM-based key (X-Wing, NIST hybrid PQ/T,
+// or pure ML-KEM). The decryptor is created at load time so per-call
+// dispatch reduces to decryptor.Decrypt(ciphertext).
+type StandardKEMCrypto struct {
KeyPairInfo
- xwingPrivateKeyPem string
- xwingPublicKeyPem string
-}
-
-type StandardHybridCrypto struct {
- KeyPairInfo
- hybridPrivateKeyPem string
- hybridPublicKeyPem string
+ privateKeyPem string
+ publicKeyPem string
+ decryptor ocrypto.PrivateKeyDecryptor
}
// List of keys by identifier
@@ -163,36 +161,33 @@ func loadKey(k KeyPairInfo) (any, error) {
ecPrivateKeyPem: string(privatePEM),
ecCertificatePEM: string(certPEM),
}, nil
- case AlgorithmHPQTXWing:
- dec, err := ocrypto.FromPrivatePEM(string(privatePEM))
+ case AlgorithmHPQTXWing,
+ AlgorithmHPQTSecp256r1MLKEM768, AlgorithmHPQTSecp384r1MLKEM1024,
+ AlgorithmMLKEM768, AlgorithmMLKEM1024:
+ decryptor, err := ocrypto.FromPrivatePEM(string(privatePEM))
if err != nil {
- return nil, fmt.Errorf("failed to parse X-Wing private key: %w", err)
+ return nil, fmt.Errorf("ocrypto.FromPrivatePEM (%s) failed: %w", k.Algorithm, err)
}
- if err := assertDecryptorAlgorithm(dec, k.Algorithm, k.KID); err != nil {
+ // Confirm the PEM dispatched to the scheme this KAS key claims, so a
+ // mislabeled key fails fast at load instead of producing garbage on
+ // unwrap. Covers both the hybrid PQ/T and pure ML-KEM decryptors.
+ if err := assertDecryptorAlgorithm(decryptor, k.Algorithm, k.KID); err != nil {
return nil, err
}
- return StandardXWingCrypto{
- KeyPairInfo: k,
- xwingPrivateKeyPem: string(privatePEM),
- xwingPublicKeyPem: string(certPEM),
- }, nil
- case AlgorithmHPQTSecp256r1MLKEM768, AlgorithmHPQTSecp384r1MLKEM1024:
- dec, err := ocrypto.FromPrivatePEM(string(privatePEM))
- if err != nil {
- return nil, fmt.Errorf("failed to parse hybrid private key: %w", err)
- }
- if err := assertDecryptorAlgorithm(dec, k.Algorithm, k.KID); err != nil {
- return nil, err
- }
- return StandardHybridCrypto{
- KeyPairInfo: k,
- hybridPrivateKeyPem: string(privatePEM),
- hybridPublicKeyPem: string(certPEM),
+ return StandardKEMCrypto{
+ KeyPairInfo: k,
+ privateKeyPem: string(privatePEM),
+ publicKeyPem: string(certPEM),
+ decryptor: decryptor,
}, nil
case AlgorithmRSA2048, AlgorithmRSA4096:
- asymDecryption, err := ocrypto.NewAsymDecryption(string(privatePEM))
+ decryptor, err := ocrypto.FromPrivatePEM(string(privatePEM))
if err != nil {
- return nil, fmt.Errorf("ocrypto.NewAsymDecryption failed: %w", err)
+ return nil, fmt.Errorf("ocrypto.FromPrivatePEM failed: %w", err)
+ }
+ asymDecryption, ok := decryptor.(ocrypto.AsymDecryption)
+ if !ok {
+ return nil, fmt.Errorf("unexpected private key decryptor type: %T", decryptor)
}
publicKeyEncryptor, err := ocrypto.FromPublicPEM(string(certPEM))
if err != nil {
@@ -229,9 +224,13 @@ func loadDeprecatedKeys(rsaKeys map[string]StandardKeyInfo, ecKeys map[string]St
return nil, fmt.Errorf("failed to rsa private key file: %w", err)
}
- asymDecryption, err := ocrypto.NewAsymDecryption(string(privatePemData))
+ decryptor, err := ocrypto.FromPrivatePEM(string(privatePemData))
if err != nil {
- return nil, fmt.Errorf("ocrypto.NewAsymDecryption failed: %w", err)
+ return nil, fmt.Errorf("ocrypto.FromPrivatePEM failed: %w", err)
+ }
+ asymDecryption, ok := decryptor.(ocrypto.AsymDecryption)
+ if !ok {
+ return nil, fmt.Errorf("unexpected private key decryptor type: %T", decryptor)
}
publicPemData, err := os.ReadFile(kasInfo.PublicKeyPath)
@@ -369,40 +368,21 @@ func (s StandardCrypto) ECPublicKey(kid string) (string, error) {
return string(pemBytes), nil
}
-func (s StandardCrypto) XWingPublicKey(kid string) (string, error) {
+// KEMPublicKey returns the public-key PEM for any KEM-based key
+// (X-Wing, NIST hybrid PQ/T, or pure ML-KEM).
+func (s StandardCrypto) KEMPublicKey(kid string) (string, error) {
k, ok := s.keysByID[kid]
if !ok {
- return "", fmt.Errorf("no xwing key with id [%s]: %w", kid, ErrCertNotFound)
+ return "", fmt.Errorf("no key with id [%s]: %w", kid, ErrCertNotFound)
}
- xw, ok := k.(StandardXWingCrypto)
+ kem, ok := k.(StandardKEMCrypto)
if !ok {
- return "", fmt.Errorf("key with id [%s] is not an X-Wing key: %w", kid, ErrCertNotFound)
+ return "", fmt.Errorf("key with id [%s] is not a KEM key: %w", kid, ErrCertNotFound)
}
- if xw.xwingPublicKeyPem == "" {
- return "", fmt.Errorf("no X-Wing public key with id [%s]: %w", kid, ErrCertNotFound)
- }
- return xw.xwingPublicKeyPem, nil
-}
-
-func (s StandardCrypto) HybridPublicKey(kid string) (string, error) {
- k, ok := s.keysByID[kid]
- if !ok {
- return "", fmt.Errorf("no hybrid key with id [%s]: %w", kid, ErrCertNotFound)
- }
- switch h := k.(type) {
- case StandardXWingCrypto:
- if h.xwingPublicKeyPem == "" {
- return "", fmt.Errorf("no hybrid public key with id [%s]: %w", kid, ErrCertNotFound)
- }
- return h.xwingPublicKeyPem, nil
- case StandardHybridCrypto:
- if h.hybridPublicKeyPem == "" {
- return "", fmt.Errorf("no hybrid public key with id [%s]: %w", kid, ErrCertNotFound)
- }
- return h.hybridPublicKeyPem, nil
- default:
- return "", fmt.Errorf("key with id [%s] is not a hybrid key: %w", kid, ErrCertNotFound)
+ if kem.publicKeyPem == "" {
+ return "", fmt.Errorf("no public key with id [%s]: %w", kid, ErrCertNotFound)
}
+ return kem.publicKeyPem, nil
}
func (s StandardCrypto) RSADecrypt(_ crypto.Hash, kid string, _ string, ciphertext []byte) ([]byte, error) {
@@ -515,38 +495,14 @@ func (s *StandardCrypto) Decrypt(_ context.Context, keyID trust.KeyIdentifier, c
return nil, fmt.Errorf("error decrypting data: %w", err)
}
- case StandardXWingCrypto:
+ case StandardKEMCrypto:
if len(ephemeralPublicKey) > 0 {
- return nil, errors.New("ephemeral public key should not be provided for X-Wing decryption")
+ return nil, fmt.Errorf("ephemeral public key should not be provided for %s decryption", key.Algorithm)
}
- dec, err := ocrypto.FromPrivatePEM(key.xwingPrivateKeyPem)
- if err != nil {
- return nil, fmt.Errorf("failed to parse X-Wing private key: %w", err)
- }
- if err := assertDecryptorAlgorithm(dec, key.Algorithm, kid); err != nil {
- return nil, err
- }
- rawKey, err = dec.Decrypt(ciphertext)
- if err != nil {
- return nil, fmt.Errorf("failed to decrypt with X-Wing: %w", err)
- }
-
- case StandardHybridCrypto:
- if len(ephemeralPublicKey) > 0 {
- return nil, errors.New("ephemeral public key should not be provided for hybrid decryption")
- }
-
- dec, err := ocrypto.FromPrivatePEM(key.hybridPrivateKeyPem)
- if err != nil {
- return nil, fmt.Errorf("failed to parse hybrid private key: %w", err)
- }
- if err := assertDecryptorAlgorithm(dec, key.Algorithm, kid); err != nil {
- return nil, err
- }
- rawKey, err = dec.Decrypt(ciphertext)
+ rawKey, err = key.decryptor.Decrypt(ciphertext)
if err != nil {
- return nil, fmt.Errorf("failed to decrypt with hybrid [%s]: %w", key.Algorithm, err)
+ return nil, fmt.Errorf("failed to decrypt with %s: %w", key.Algorithm, err)
}
default:
diff --git a/service/internal/security/test_helpers_test.go b/service/internal/security/test_helpers_test.go
index f3736529b7..f15144a1f1 100644
--- a/service/internal/security/test_helpers_test.go
+++ b/service/internal/security/test_helpers_test.go
@@ -17,6 +17,14 @@ type testKeyMaterial struct {
ecKid string
ecPrivatePEM string
ecPublicPEM string
+
+ mlkem768Kid string
+ mlkem768PrivatePEM string
+ mlkem768PublicPEM string
+
+ mlkem1024Kid string
+ mlkem1024PrivatePEM string
+ mlkem1024PublicPEM string
}
func writeTempFile(t *testing.T, dir, name, contents string) string {
@@ -83,6 +91,55 @@ func newStandardCryptoForTest(t *testing.T, includeRSA, includeEC bool) (*Standa
return crypto, material
}
+func newStandardCryptoWithMLKEMForTest(t *testing.T) (*StandardCrypto, testKeyMaterial) {
+ t.Helper()
+
+ dir := t.TempDir()
+ var keys []KeyPairInfo
+ var material testKeyMaterial
+
+ kp768, err := ocrypto.NewMLKEMKeyPair()
+ require.NoError(t, err)
+ mlkem768Private, err := kp768.PrivateKeyInPemFormat()
+ require.NoError(t, err)
+ mlkem768Public, err := kp768.PublicKeyInPemFormat()
+ require.NoError(t, err)
+
+ material.mlkem768Kid = "mlkem768-test-key"
+ material.mlkem768PrivatePEM = mlkem768Private
+ material.mlkem768PublicPEM = mlkem768Public
+
+ keys = append(keys, KeyPairInfo{
+ Algorithm: AlgorithmMLKEM768,
+ KID: material.mlkem768Kid,
+ Private: writeTempFile(t, dir, "mlkem768-private.pem", mlkem768Private),
+ Certificate: writeTempFile(t, dir, "mlkem768-public.pem", mlkem768Public),
+ })
+
+ kp1024, err := ocrypto.NewMLKEM1024KeyPair()
+ require.NoError(t, err)
+ mlkem1024Private, err := kp1024.PrivateKeyInPemFormat()
+ require.NoError(t, err)
+ mlkem1024Public, err := kp1024.PublicKeyInPemFormat()
+ require.NoError(t, err)
+
+ material.mlkem1024Kid = "mlkem1024-test-key"
+ material.mlkem1024PrivatePEM = mlkem1024Private
+ material.mlkem1024PublicPEM = mlkem1024Public
+
+ keys = append(keys, KeyPairInfo{
+ Algorithm: AlgorithmMLKEM1024,
+ KID: material.mlkem1024Kid,
+ Private: writeTempFile(t, dir, "mlkem1024-private.pem", mlkem1024Private),
+ Certificate: writeTempFile(t, dir, "mlkem1024-public.pem", mlkem1024Public),
+ })
+
+ crypto, err := NewStandardCrypto(StandardConfig{Keys: keys})
+ require.NoError(t, err)
+
+ return crypto, material
+}
+
func exportProtectedKey(t *testing.T, key ocrypto.ProtectedKey) []byte {
t.Helper()
raw, err := (&noOpEncapsulator{}).Encapsulate(key)
diff --git a/service/kas/access/provider.go b/service/kas/access/provider.go
index 89f90b5e85..f5d00f69a6 100644
--- a/service/kas/access/provider.go
+++ b/service/kas/access/provider.go
@@ -52,15 +52,25 @@ type KASConfig struct {
// Enabling is required to parse KAOs with the `ec-wrapped` type,
// and (currently) also enables responding with ECIES encrypted responses.
ECTDFEnabled bool `mapstructure:"ec_tdf_enabled" json:"ec_tdf_enabled"`
- HybridTDFEnabled bool `mapstructure:"hybrid_tdf_enabled" json:"hybrid_tdf_enabled"`
Preview Preview `mapstructure:"preview" json:"preview"`
RegisteredKASURI string `mapstructure:"registered_kas_uri" json:"registered_kas_uri"`
}
type Preview struct {
- ECTDFEnabled bool `mapstructure:"ec_tdf_enabled" json:"ec_tdf_enabled"`
+ ECTDFEnabled bool `mapstructure:"ec_tdf_enabled" json:"ec_tdf_enabled"`
+ // HybridTDFEnabled is a preview feature that enables support for hybrid rewrap in TDFs.
+ // Enabling is required to parse KAOs with the `hybrid-wrapped` type,
+ // and (currently) also enables responding with hybrid encrypted responses.
+ // This feature is experimental and may be removed or changed in future releases.
+ // Enabling this also enables ML-KEM rewrap support; it cannot be enabled
+ // while ML-KEM is disabled (see normalizePreview).
HybridTDFEnabled bool `mapstructure:"hybrid_tdf_enabled" json:"hybrid_tdf_enabled"`
- KeyManagement bool `mapstructure:"key_management" json:"key_management"`
+ // MLKEMTDFEnabled is a preview feature that enables support for ML-KEM rewrap in TDFs.
+ // Enabling is required to parse KAOs with the `mlkem-wrapped` type,
+ // and (currently) also enables responding with ML-KEM encrypted responses.
+ // This feature is experimental and may be removed or changed in future releases.
+ MLKEMTDFEnabled bool `mapstructure:"mlkem_tdf_enabled" json:"mlkem_tdf_enabled"`
+ KeyManagement bool `mapstructure:"key_management" json:"key_management"`
}
// Specifies the preferred/default key for a given algorithm type.
@@ -82,11 +92,13 @@ func (p *Provider) IsReady(ctx context.Context) error {
// overrides, and emits a warning when the configured clock skew exceeds the default.
func (p *Provider) ApplyConfig(cfg KASConfig, securityCfg *config.SecurityConfig) {
p.KASConfig = cfg
+ p.normalizePreview()
p.securityConfig = securityCfg
if p.Logger != nil {
if skew := p.acceptableSkew(); skew > config.DefaultUnsafeClockSkew {
- p.Logger.Warn("configured SRT acceptable skew exceeds default",
+ p.Logger.Warn(
+ "configured SRT acceptable skew exceeds default",
slog.Duration("configured_skew", skew),
slog.Duration("default_skew", config.DefaultUnsafeClockSkew),
)
@@ -145,14 +157,13 @@ func (kasCfg KASConfig) String() string {
}
return fmt.Sprintf(
- "KASConfig{Keyring:%v, ECCertID:%q, RSACertID:%q, RootKey:%s, KeyCacheExpiration:%s, ECTDFEnabled:%t, HybridTDFEnabled:%t, Preview:%+v, RegisteredKASURI:%q}",
+ "KASConfig{Keyring:%v, ECCertID:%q, RSACertID:%q, RootKey:%s, KeyCacheExpiration:%s, ECTDFEnabled:%t, Preview:%+v, RegisteredKASURI:%q}",
kasCfg.Keyring,
kasCfg.ECCertID,
kasCfg.RSACertID,
rootKeySummary,
kasCfg.KeyCacheExpiration,
kasCfg.ECTDFEnabled,
- kasCfg.HybridTDFEnabled,
kasCfg.Preview,
kasCfg.RegisteredKASURI,
)
@@ -171,12 +182,19 @@ func (kasCfg KASConfig) LogValue() slog.Value {
slog.String("root_key", rootKeyVal),
slog.Duration("key_cache_expiration", kasCfg.KeyCacheExpiration),
slog.Bool("ec_tdf_enabled", kasCfg.ECTDFEnabled),
- slog.Bool("hybrid_tdf_enabled", kasCfg.HybridTDFEnabled),
slog.Any("preview", kasCfg.Preview),
slog.String("registered_kas_uri", kasCfg.RegisteredKASURI),
)
}
+// normalizePreview applies implied preview settings. Enabling the hybrid
+// preview also enables ML-KEM rewrap support (see Preview.HybridTDFEnabled).
+func (kasCfg *KASConfig) normalizePreview() {
+ if kasCfg.Preview.HybridTDFEnabled {
+ kasCfg.Preview.MLKEMTDFEnabled = true
+ }
+}
+
// If there exists *any* legacy keys, returns empty list.
// Otherwise, create a copy with legacy=true for all values
func inferLegacyKeys(keys []CurrentKeyFor) []CurrentKeyFor {
diff --git a/service/kas/access/provider_test.go b/service/kas/access/provider_test.go
index bd7872c451..56e4a18861 100644
--- a/service/kas/access/provider_test.go
+++ b/service/kas/access/provider_test.go
@@ -11,6 +11,45 @@ func TestInferLegacyKeys_empty(t *testing.T) {
assert.Empty(t, inferLegacyKeys(nil))
}
+func TestApplyConfig_NormalizesHybridToMLKEM(t *testing.T) {
+ tests := []struct {
+ name string
+ preview Preview
+ wantMLKEM bool
+ }{
+ {
+ name: "hybrid on enables mlkem",
+ preview: Preview{HybridTDFEnabled: true},
+ wantMLKEM: true,
+ },
+ {
+ name: "hybrid and mlkem on stays on",
+ preview: Preview{HybridTDFEnabled: true, MLKEMTDFEnabled: true},
+ wantMLKEM: true,
+ },
+ {
+ name: "mlkem on without hybrid is untouched",
+ preview: Preview{MLKEMTDFEnabled: true},
+ wantMLKEM: true,
+ },
+ {
+ name: "both off stays off",
+ preview: Preview{},
+ wantMLKEM: false,
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ p := &Provider{}
+ p.ApplyConfig(KASConfig{Preview: tc.preview}, nil)
+ assert.Equal(t, tc.wantMLKEM, p.Preview.MLKEMTDFEnabled)
+ // HybridTDFEnabled is never altered by normalization.
+ assert.Equal(t, tc.preview.HybridTDFEnabled, p.Preview.HybridTDFEnabled)
+ })
+ }
+}
+
func TestInferLegacyKeys_singles(t *testing.T) {
one := []CurrentKeyFor{
{
diff --git a/service/kas/access/publicKey.go b/service/kas/access/publicKey.go
index d7f381c307..14c6dd8a05 100644
--- a/service/kas/access/publicKey.go
+++ b/service/kas/access/publicKey.go
@@ -77,7 +77,8 @@ func (p *Provider) LegacyPublicKey(ctx context.Context, req *connect.Request[kas
return nil, connect.NewError(connect.CodeInternal, errors.Join(ErrConfig, errors.New("configuration error")))
}
case security.AlgorithmRSA2048, security.AlgorithmHPQTXWing,
- security.AlgorithmHPQTSecp256r1MLKEM768, security.AlgorithmHPQTSecp384r1MLKEM1024, "":
+ security.AlgorithmHPQTSecp256r1MLKEM768, security.AlgorithmHPQTSecp384r1MLKEM1024,
+ security.AlgorithmMLKEM768, security.AlgorithmMLKEM1024, "":
// For RSA keys, return the public key in PKCS8 format
pem, err = keyDetails.ExportPublicKey(ctx, trust.KeyTypePKCS8)
if err != nil {
@@ -154,7 +155,9 @@ func (p *Provider) PublicKey(ctx context.Context, req *connect.Request[kaspb.Pub
return r(ecPublicKeyPem, kid, err)
case security.AlgorithmHPQTXWing,
security.AlgorithmHPQTSecp256r1MLKEM768,
- security.AlgorithmHPQTSecp384r1MLKEM1024:
+ security.AlgorithmHPQTSecp384r1MLKEM1024,
+ security.AlgorithmMLKEM768,
+ security.AlgorithmMLKEM1024:
switch fmt {
case "pkcs8", "":
publicKeyPEM, err := keyDetails.ExportPublicKey(ctx, trust.KeyTypePKCS8)
diff --git a/service/kas/access/rewrap.go b/service/kas/access/rewrap.go
index 67a0e33690..2aa93f34e3 100644
--- a/service/kas/access/rewrap.go
+++ b/service/kas/access/rewrap.go
@@ -760,7 +760,7 @@ func (p *Provider) verifyRewrapRequests(ctx context.Context, req *kaspb.Unsigned
continue
}
case "hybrid-wrapped":
- if !p.HybridTDFEnabled && !p.Preview.HybridTDFEnabled {
+ if !p.Preview.HybridTDFEnabled {
p.Logger.WarnContext(ctx, "hybrid-wrapped not enabled")
failedKAORewrap(results, kao, err400("bad request"))
continue
@@ -773,6 +773,20 @@ func (p *Provider) verifyRewrapRequests(ctx context.Context, req *kaspb.Unsigned
failedKAORewrap(results, kao, err400("bad request"))
continue
}
+ case "mlkem-wrapped":
+ if !p.Preview.MLKEMTDFEnabled {
+ p.Logger.WarnContext(ctx, "mlkem-wrapped not enabled")
+ failedKAORewrap(results, kao, err400("bad request"))
+ continue
+ }
+
+ kid := trust.KeyIdentifier(kao.GetKeyAccessObject().GetKid())
+ dek, err = p.KeyDelegator.Decrypt(ctx, kid, kao.GetKeyAccessObject().GetWrappedKey(), nil)
+ if err != nil {
+ p.Logger.WarnContext(ctx, "failed to decrypt ML-KEM key", slog.Any("error", err))
+ failedKAORewrap(results, kao, err400("bad request"))
+ continue
+ }
case "wrapped":
var kidsToCheck []trust.KeyIdentifier
if kao.GetKeyAccessObject().GetKid() != "" {
diff --git a/service/kas/kas.go b/service/kas/kas.go
index 77d0bbffcf..3c2e073132 100644
--- a/service/kas/kas.go
+++ b/service/kas/kas.go
@@ -29,8 +29,8 @@ func OnConfigUpdate(p *access.Provider) serviceregistry.OnConfigUpdateHook {
}
p.ApplyConfig(kasCfg, p.SecurityConfig())
- p.Logger.TraceContext(ctx, "kas config reloaded", slog.Any("config", kasCfg))
- logSupportedMechanisms(ctx, p.Logger, p.KeyDelegator, &kasCfg)
+ p.Logger.TraceContext(ctx, "kas config reloaded", slog.Any("config", p.KASConfig))
+ logSupportedMechanisms(ctx, p.Logger, p.KeyDelegator, &p.KASConfig)
return nil
}
@@ -115,8 +115,8 @@ func NewRegistration() *serviceregistry.Service[kasconnect.AccessServiceHandler]
p.ApplyConfig(kasCfg, srp.Security)
p.Tracer = srp.Tracer
- srp.Logger.Debug("kas config loaded", slog.Any("config", kasCfg))
- logSupportedMechanisms(context.Background(), srp.Logger, p.KeyDelegator, &kasCfg)
+ srp.Logger.Debug("kas config loaded", slog.Any("config", p.KASConfig))
+ logSupportedMechanisms(context.Background(), srp.Logger, p.KeyDelegator, &p.KASConfig)
if err := srp.RegisterReadinessCheck("kas", p.IsReady); err != nil {
srp.Logger.Error("failed to register kas readiness check", slog.String("error", err.Error()))
@@ -198,17 +198,18 @@ func logSupportedMechanisms(ctx context.Context, l *logger.Logger, kd *trust.Del
// filterMechanismsByPreview drops algorithms whose corresponding rewrap path is
// disabled. Keep aligned with the gating in service/kas/access/rewrap.go for
-// "ec-wrapped" and "hybrid-wrapped" key access objects.
+// "ec-wrapped", "hybrid-wrapped", and "mlkem-wrapped" key access objects.
func filterMechanismsByPreview(algs []ocrypto.KeyType, kasCfg *access.KASConfig) []ocrypto.KeyType {
ecEnabled := kasCfg.ECTDFEnabled || kasCfg.Preview.ECTDFEnabled
- hybridEnabled := kasCfg.HybridTDFEnabled || kasCfg.Preview.HybridTDFEnabled
out := make([]ocrypto.KeyType, 0, len(algs))
for _, a := range algs {
switch {
case !ecEnabled && ocrypto.IsECKeyType(a):
continue
- case !hybridEnabled && ocrypto.IsHybridKeyType(a):
+ case !kasCfg.Preview.HybridTDFEnabled && ocrypto.IsHybridKeyType(a):
+ continue
+ case !kasCfg.Preview.MLKEMTDFEnabled && ocrypto.IsMLKEMKeyType(a):
continue
}
out = append(out, a)
diff --git a/service/kas/kas_test.go b/service/kas/kas_test.go
index 4772de138b..a6947cfbd3 100644
--- a/service/kas/kas_test.go
+++ b/service/kas/kas_test.go
@@ -53,12 +53,6 @@ func TestFilterMechanismsByPreview(t *testing.T) {
cfg: &access.KASConfig{Preview: access.Preview{ECTDFEnabled: true}},
want: []ocrypto.KeyType{"rsa:2048", "rsa:4096", "ec:secp256r1", "ec:secp384r1"},
},
- {
- name: "top-level hybrid flag on keeps hpqt only",
- algs: allAlgs,
- cfg: &access.KASConfig{HybridTDFEnabled: true},
- want: []ocrypto.KeyType{"rsa:2048", "rsa:4096", "hpqt:xwing", "hpqt:secp256r1-mlkem768"},
- },
{
name: "preview hybrid flag on keeps hpqt only",
algs: allAlgs,
@@ -68,7 +62,7 @@ func TestFilterMechanismsByPreview(t *testing.T) {
{
name: "both flags on keeps everything",
algs: allAlgs,
- cfg: &access.KASConfig{ECTDFEnabled: true, HybridTDFEnabled: true},
+ cfg: &access.KASConfig{Preview: access.Preview{ECTDFEnabled: true, HybridTDFEnabled: true, MLKEMTDFEnabled: true}},
want: allAlgs,
},
{
@@ -77,13 +71,14 @@ func TestFilterMechanismsByPreview(t *testing.T) {
cfg: &access.KASConfig{Preview: access.Preview{
ECTDFEnabled: true,
HybridTDFEnabled: true,
+ MLKEMTDFEnabled: true,
}},
want: allAlgs,
},
{
name: "empty input returns empty",
algs: []ocrypto.KeyType{},
- cfg: &access.KASConfig{ECTDFEnabled: true, HybridTDFEnabled: true},
+ cfg: &access.KASConfig{Preview: access.Preview{ECTDFEnabled: true, HybridTDFEnabled: true, MLKEMTDFEnabled: true}},
want: []ocrypto.KeyType{},
},
{
@@ -92,6 +87,28 @@ func TestFilterMechanismsByPreview(t *testing.T) {
cfg: &access.KASConfig{},
want: []ocrypto.KeyType{"rsa:2048"},
},
+ {
+ // (HybridTDFEnabled=true, MLKEMTDFEnabled=false) is unreachable at
+ // runtime because normalizePreview forces ML-KEM on whenever hybrid
+ // is enabled, so this asserts the negative gating via a reachable
+ // all-off config instead.
+ name: "all preview flags off drops pure mlkem and hybrid",
+ algs: []ocrypto.KeyType{"rsa:2048", "hpqt:xwing", "mlkem:768", "mlkem:1024"},
+ cfg: &access.KASConfig{},
+ want: []ocrypto.KeyType{"rsa:2048"},
+ },
+ {
+ name: "mlkem on keeps pure mlkem",
+ algs: []ocrypto.KeyType{"rsa:2048", "hpqt:xwing", "mlkem:768", "mlkem:1024"},
+ cfg: &access.KASConfig{Preview: access.Preview{HybridTDFEnabled: true, MLKEMTDFEnabled: true}},
+ want: []ocrypto.KeyType{"rsa:2048", "hpqt:xwing", "mlkem:768", "mlkem:1024"},
+ },
+ {
+ name: "mlkem on without hybrid keeps pure mlkem but drops hybrid",
+ algs: []ocrypto.KeyType{"rsa:2048", "hpqt:xwing", "mlkem:768", "mlkem:1024"},
+ cfg: &access.KASConfig{Preview: access.Preview{MLKEMTDFEnabled: true}},
+ want: []ocrypto.KeyType{"rsa:2048", "mlkem:768", "mlkem:1024"},
+ },
}
for _, tc := range tests {
@@ -171,7 +188,7 @@ func TestLogSupportedMechanisms_EmitsInfoLine(t *testing.T) {
},
{
name: "both preview flags",
- cfg: &access.KASConfig{Preview: access.Preview{ECTDFEnabled: true, HybridTDFEnabled: true}},
+ cfg: &access.KASConfig{Preview: access.Preview{ECTDFEnabled: true, HybridTDFEnabled: true, MLKEMTDFEnabled: true}},
wantMechanisms: []string{"ec:secp256r1", "hpqt:xwing", "rsa:2048"},
},
}
diff --git a/service/policy/db/grant_mappings.go b/service/policy/db/grant_mappings.go
index 7cd8830f92..2d1683c56e 100644
--- a/service/policy/db/grant_mappings.go
+++ b/service/policy/db/grant_mappings.go
@@ -28,6 +28,10 @@ func mapAlgorithmToKasPublicKeyAlg(alg policy.Algorithm) policy.KasPublicKeyAlgE
return policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
case policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024:
return policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
+ case policy.Algorithm_ALGORITHM_MLKEM_768:
+ return policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768
+ case policy.Algorithm_ALGORITHM_MLKEM_1024:
+ return policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024
case policy.Algorithm_ALGORITHM_UNSPECIFIED:
return policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_UNSPECIFIED
default:
diff --git a/service/policy/kasregistry/key_access_server_registry.proto b/service/policy/kasregistry/key_access_server_registry.proto
index 86e9fbc9a6..4b40df67cf 100644
--- a/service/policy/kasregistry/key_access_server_registry.proto
+++ b/service/policy/kasregistry/key_access_server_registry.proto
@@ -436,7 +436,7 @@ message CreateKeyRequest {
Algorithm key_algorithm = 3 [(buf.validate.field).cel = {
id: "key_algorithm_defined"
message: "The key_algorithm must be one of the defined values."
- expression: "this in [1, 2, 3, 4, 5, 6, 7, 8]" // Allow ALGORITHM_RSA_2048, ALGORITHM_RSA_4096, ALGORITHM_EC_P256, ALGORITHM_EC_P384, ALGORITHM_EC_P521, ALGORITHM_HPQT_XWING, ALGORITHM_HPQT_SECP256R1_MLKEM768, ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ expression: "this in [1, 2, 3, 4, 5, 6, 7, 8, 20, 21]" // Allow ALGORITHM_RSA_2048, ALGORITHM_RSA_4096, ALGORITHM_EC_P256, ALGORITHM_EC_P384, ALGORITHM_EC_P521, ALGORITHM_HPQT_XWING, ALGORITHM_HPQT_SECP256R1_MLKEM768, ALGORITHM_HPQT_SECP384R1_MLKEM1024, ALGORITHM_MLKEM_768, ALGORITHM_MLKEM_1024
}]; // The algorithm to be used for the key
// Required
KeyMode key_mode = 4 [(buf.validate.field).cel = {
@@ -480,7 +480,7 @@ message ListKeysRequest {
Algorithm key_algorithm = 1 [(buf.validate.field).cel = {
id: "key_algorithm_defined"
message: "The key_algorithm must be one of the defined values."
- expression: "this in [0, 1, 2, 3, 4, 5, 6, 7, 8]" // Allow unspecified and all supported algorithm values
+ expression: "this in [0, 1, 2, 3, 4, 5, 6, 7, 8, 20, 21]" // Allow unspecified and all supported algorithm values, including ALGORITHM_MLKEM_768 and ALGORITHM_MLKEM_1024
}]; // Filter keys by algorithm
oneof kas_filter {
@@ -593,7 +593,7 @@ message RotateKeyRequest {
Algorithm algorithm = 2 [(buf.validate.field).cel = {
id: "key_algorithm_defined"
message: "The key_algorithm must be one of the defined values."
- expression: "this in [1, 2, 3, 4, 5, 6, 7, 8]" // Allow ALGORITHM_RSA_2048, ALGORITHM_RSA_4096, ALGORITHM_EC_P256, ALGORITHM_EC_P384, ALGORITHM_EC_P521, ALGORITHM_HPQT_XWING, ALGORITHM_HPQT_SECP256R1_MLKEM768, ALGORITHM_HPQT_SECP384R1_MLKEM1024
+ expression: "this in [1, 2, 3, 4, 5, 6, 7, 8, 20, 21]" // Allow ALGORITHM_RSA_2048, ALGORITHM_RSA_4096, ALGORITHM_EC_P256, ALGORITHM_EC_P384, ALGORITHM_EC_P521, ALGORITHM_HPQT_XWING, ALGORITHM_HPQT_SECP256R1_MLKEM768, ALGORITHM_HPQT_SECP384R1_MLKEM1024, ALGORITHM_MLKEM_768, ALGORITHM_MLKEM_1024
}];
// Required
KeyMode key_mode = 3 [
diff --git a/service/policy/objects.proto b/service/policy/objects.proto
index 5a241e72ea..7a474fffce 100644
--- a/service/policy/objects.proto
+++ b/service/policy/objects.proto
@@ -490,6 +490,8 @@ enum KasPublicKeyAlgEnum {
KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING = 10;
KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768 = 11;
KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024 = 12;
+ KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768 = 20;
+ KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 = 21;
}
// Deprecated
@@ -663,6 +665,8 @@ enum Algorithm {
ALGORITHM_HPQT_XWING = 6;
ALGORITHM_HPQT_SECP256R1_MLKEM768 = 7;
ALGORITHM_HPQT_SECP384R1_MLKEM1024 = 8;
+ ALGORITHM_MLKEM_768 = 20;
+ ALGORITHM_MLKEM_1024 = 21;
}
// The status of the key
diff --git a/test/tdf-roundtrips.bats b/test/tdf-roundtrips.bats
index e6f63f4fca..cd16a6c84c 100755
--- a/test/tdf-roundtrips.bats
+++ b/test/tdf-roundtrips.bats
@@ -89,6 +89,48 @@
printf '%s\n' "$output" | grep "Hello P384+ML-KEM-1024 wrappers!"
}
+@test "examples: roundtrip Z-TDF with ML-KEM-768 wrapped KAO" {
+ echo "[INFO] create a tdf3 format file"
+ run go run ./examples encrypt -o sensitive-with-mlkem768.txt.tdf --autoconfigure=false -A "mlkem:768" "Hello ML-KEM-768 wrappers!"
+ echo "[INFO] echoing output; if successful, this is just the manifest"
+ echo "$output"
+
+ echo "[INFO] Validate the manifest lists the expected type in its KAO"
+ kaotype=$(jq -r '.encryptionInformation.keyAccess[0].type' <<<"${output}")
+ echo "$kaotype"
+ [ "$kaotype" = mlkem-wrapped ]
+
+ kid=$(jq -r '.encryptionInformation.keyAccess[0].kid' <<<"${output}")
+ echo "kao.kid=$kid"
+ [ "$kid" = m1 ]
+
+ echo "[INFO] decrypting..."
+ run go run ./examples decrypt sensitive-with-mlkem768.txt.tdf
+ echo "$output"
+ printf '%s\n' "$output" | grep "Hello ML-KEM-768 wrappers!"
+}
+
+@test "examples: roundtrip Z-TDF with ML-KEM-1024 wrapped KAO" {
+ echo "[INFO] create a tdf3 format file"
+ run go run ./examples encrypt -o sensitive-with-mlkem1024.txt.tdf --autoconfigure=false -A "mlkem:1024" "Hello ML-KEM-1024 wrappers!"
+ echo "[INFO] echoing output; if successful, this is just the manifest"
+ echo "$output"
+
+ echo "[INFO] Validate the manifest lists the expected type in its KAO"
+ kaotype=$(jq -r '.encryptionInformation.keyAccess[0].type' <<<"${output}")
+ echo "$kaotype"
+ [ "$kaotype" = mlkem-wrapped ]
+
+ kid=$(jq -r '.encryptionInformation.keyAccess[0].kid' <<<"${output}")
+ echo "kao.kid=$kid"
+ [ "$kid" = m2 ]
+
+ echo "[INFO] decrypting..."
+ run go run ./examples decrypt sensitive-with-mlkem1024.txt.tdf
+ echo "$output"
+ printf '%s\n' "$output" | grep "Hello ML-KEM-1024 wrappers!"
+}
+
@test "examples: legacy key support Z-TDF" {
echo "[INFO] validating default key is r1"
echo "[INFO] default key result: $(grpcurl "localhost:8080" "kas.AccessService/PublicKey")"
@@ -272,6 +314,10 @@ services:
alg: hpqt:secp256r1-mlkem768
- kid: h2
alg: hpqt:secp384r1-mlkem1024
+ - kid: m1
+ alg: mlkem:768
+ - kid: m2
+ alg: mlkem:1024
policy:
enabled: true
authorization:
@@ -331,6 +377,14 @@ server:
alg: hpqt:secp384r1-mlkem1024
private: kas-p384mlkem1024-private.pem
cert: kas-p384mlkem1024-public.pem
+ - kid: m1
+ alg: mlkem:768
+ private: kas-mlkem768-private.pem
+ cert: kas-mlkem768-public.pem
+ - kid: m2
+ alg: mlkem:1024
+ private: kas-mlkem1024-private.pem
+ cert: kas-mlkem1024-public.pem
port: 8080
opa:
embedded: true
diff --git a/tests-bdd/cukes/utils/utils_genKeys.go b/tests-bdd/cukes/utils/utils_genKeys.go
index 3ad0b57599..5a3d344b95 100644
--- a/tests-bdd/cukes/utils/utils_genKeys.go
+++ b/tests-bdd/cukes/utils/utils_genKeys.go
@@ -207,7 +207,7 @@ func createJavaKeystore(ctx context.Context, certPath, keystorePath string) {
log.Printf("Java keystore generated successfully: %s", keystorePath)
}
-// generateHybridKeys creates X-Wing, P256+ML-KEM-768, and P384+ML-KEM-1024 key pairs.
+// generateHybridKeys creates post-quantum key pairs: X-Wing, P256+ML-KEM-768, P384+ML-KEM-1024, ML-KEM-768, and ML-KEM-1024.
func generateHybridKeys(outputPath string) {
specs := []struct {
name string
@@ -218,6 +218,8 @@ func generateHybridKeys(outputPath string) {
{"X-Wing", generateXWingKeyPair, "kas-xwing-private.pem", "kas-xwing-public.pem"},
{"P256+ML-KEM-768", generateP256MLKEM768KeyPair, "kas-p256mlkem768-private.pem", "kas-p256mlkem768-public.pem"},
{"P384+ML-KEM-1024", generateP384MLKEM1024KeyPair, "kas-p384mlkem1024-private.pem", "kas-p384mlkem1024-public.pem"},
+ {"ML-KEM-768", generateMLKEM768KeyPair, "kas-mlkem768-private.pem", "kas-mlkem768-public.pem"},
+ {"ML-KEM-1024", generateMLKEM1024KeyPair, "kas-mlkem1024-private.pem", "kas-mlkem1024-public.pem"},
}
for _, s := range specs {
@@ -289,3 +291,35 @@ func generateP384MLKEM1024KeyPair() (string, string, error) {
}
return priv, pub, nil
}
+
+func generateMLKEM768KeyPair() (string, string, error) {
+ kp, err := ocrypto.NewMLKEMKeyPair()
+ if err != nil {
+ return "", "", err
+ }
+ priv, err := kp.PrivateKeyInPemFormat()
+ if err != nil {
+ return "", "", err
+ }
+ pub, err := kp.PublicKeyInPemFormat()
+ if err != nil {
+ return "", "", err
+ }
+ return priv, pub, nil
+}
+
+func generateMLKEM1024KeyPair() (string, string, error) {
+ kp, err := ocrypto.NewMLKEM1024KeyPair()
+ if err != nil {
+ return "", "", err
+ }
+ priv, err := kp.PrivateKeyInPemFormat()
+ if err != nil {
+ return "", "", err
+ }
+ pub, err := kp.PublicKeyInPemFormat()
+ if err != nil {
+ return "", "", err
+ }
+ return priv, pub, nil
+}