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 c3c252a786..af3b2301d5 100644
--- a/docs/grpc/index.html
+++ b/docs/grpc/index.html
@@ -4147,6 +4147,18 @@
Algorithm
|
+
+ | ALGORITHM_MLKEM_768 |
+ 20 |
+ |
+
+
+
+ | ALGORITHM_MLKEM_1024 |
+ 21 |
+ |
+
+
@@ -4276,6 +4288,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 da57657292..69a29f3504 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
@@ -235,6 +237,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 cbdde67a8c..104c4a4702 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
@@ -754,6 +756,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 00630c5163..819df15b55 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
@@ -53,6 +55,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 562045f797..fe4758bf1a 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
@@ -585,6 +587,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 ca41d4841e..84ae4a909b 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
@@ -445,6 +447,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 a11306bc24..f393b21637 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
@@ -445,6 +447,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 4c78ec9f8d..2762d4cffa 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
@@ -481,6 +483,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 09ebdf2e85..0fd9822b2f 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
@@ -419,6 +421,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 1cbfbfc943..9fa66860ae 100644
--- a/lib/ocrypto/asym_decryption.go
+++ b/lib/ocrypto/asym_decryption.go
@@ -45,11 +45,20 @@ func FromPrivatePEMWithSalt(privateKeyInPem string, salt, info []byte) (PrivateK
}
switch block.Type {
case PEMBlockXWingPrivateKey:
- return NewSaltedXWingDecryptor(block.Bytes, salt, info)
+ return newKEMDecryptor(xwingKEM{}, block.Bytes, salt, info)
case PEMBlockP256MLKEM768PrivateKey:
- return NewSaltedP256MLKEM768Decryptor(block.Bytes, salt, info)
+ return newKEMDecryptor(nistHybridKEM{params: &p256mlkem768Params}, block.Bytes, salt, info)
case PEMBlockP384MLKEM1024PrivateKey:
- return NewSaltedP384MLKEM1024Decryptor(block.Bytes, salt, info)
+ return newKEMDecryptor(nistHybridKEM{params: &p384mlkem1024Params}, block.Bytes, salt, info)
+ }
+
+ 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
}
priv, err := x509.ParsePKCS8PrivateKey(block.Bytes)
diff --git a/lib/ocrypto/asym_encryption.go b/lib/ocrypto/asym_encryption.go
index 2a030c3f32..46794d9716 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 {
@@ -76,11 +77,20 @@ func FromPublicPEMWithSalt(publicKeyInPem string, salt, info []byte) (PublicKeyE
}
switch block.Type {
case PEMBlockXWingPublicKey:
- return NewXWingEncryptor(block.Bytes, salt, info)
+ return newKEMEncryptor(xwingKEM{}, block.Bytes, salt, info)
case PEMBlockP256MLKEM768PublicKey:
- return NewP256MLKEM768Encryptor(block.Bytes, salt, info)
+ return newKEMEncryptor(nistHybridKEM{params: &p256mlkem768Params}, block.Bytes, salt, info)
case PEMBlockP384MLKEM1024PublicKey:
- return NewP384MLKEM1024Encryptor(block.Bytes, salt, info)
+ return newKEMEncryptor(nistHybridKEM{params: &p384mlkem1024Params}, block.Bytes, salt, info)
+ }
+
+ 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
}
pub, err := getPublicPart(publicKeyInPem)
@@ -237,7 +247,7 @@ func publicKeyInPemFormat(pk any) (string, error) {
publicKeyPem := pem.EncodeToMemory(
&pem.Block{
- Type: "PUBLIC KEY",
+ Type: pemBlockPublicKey,
Bytes: publicKeyBytes,
},
)
diff --git a/lib/ocrypto/benchmark_test.go b/lib/ocrypto/benchmark_test.go
index b86b3075e7..eb741838de 100644
--- a/lib/ocrypto/benchmark_test.go
+++ b/lib/ocrypto/benchmark_test.go
@@ -198,7 +198,7 @@ func BenchmarkWrapDEK(b *testing.B) {
if err != nil {
b.Fatal(err)
}
- ss, ct, err := XWingEncapsulate(pubKey)
+ ss, ct, err := xwingKEM{}.encapsulate(pubKey)
if err != nil {
b.Fatal(err)
}
@@ -214,9 +214,9 @@ func BenchmarkWrapDEK(b *testing.B) {
if err != nil {
b.Fatal(err)
}
- sinkBytes, errSink = asn1.Marshal(HybridNISTWrappedKey{
- HybridCiphertext: ct,
- EncryptedDEK: encDEK,
+ sinkBytes, errSink = asn1.Marshal(kemEnvelope{
+ KEMCiphertext: ct,
+ EncryptedDEK: encDEK,
})
}
b.ReportMetric(float64(len(sinkBytes)), "wrapped-bytes")
@@ -229,7 +229,7 @@ func BenchmarkWrapDEK(b *testing.B) {
if err != nil {
b.Fatal(err)
}
- ss, ct, err := P256MLKEM768Encapsulate(pubKey)
+ ss, ct, err := nistHybridKEM{params: &p256mlkem768Params}.encapsulate(pubKey)
if err != nil {
b.Fatal(err)
}
@@ -245,9 +245,9 @@ func BenchmarkWrapDEK(b *testing.B) {
if err != nil {
b.Fatal(err)
}
- sinkBytes, errSink = asn1.Marshal(HybridNISTWrappedKey{
- HybridCiphertext: ct,
- EncryptedDEK: encDEK,
+ sinkBytes, errSink = asn1.Marshal(kemEnvelope{
+ KEMCiphertext: ct,
+ EncryptedDEK: encDEK,
})
}
b.ReportMetric(float64(len(sinkBytes)), "wrapped-bytes")
@@ -260,7 +260,7 @@ func BenchmarkWrapDEK(b *testing.B) {
if err != nil {
b.Fatal(err)
}
- ss, ct, err := P384MLKEM1024Encapsulate(pubKey)
+ ss, ct, err := nistHybridKEM{params: &p384mlkem1024Params}.encapsulate(pubKey)
if err != nil {
b.Fatal(err)
}
@@ -276,9 +276,9 @@ func BenchmarkWrapDEK(b *testing.B) {
if err != nil {
b.Fatal(err)
}
- sinkBytes, errSink = asn1.Marshal(HybridNISTWrappedKey{
- HybridCiphertext: ct,
- EncryptedDEK: encDEK,
+ sinkBytes, errSink = asn1.Marshal(kemEnvelope{
+ KEMCiphertext: ct,
+ EncryptedDEK: encDEK,
})
}
b.ReportMetric(float64(len(sinkBytes)), "wrapped-bytes")
@@ -536,12 +536,16 @@ func BenchmarkUnwrapDEK(b *testing.B) {
}
func BenchmarkHybridSubOps(b *testing.B) {
+ xwingAdapter := xwingKEM{}
+ p256Adapter := nistHybridKEM{params: &p256mlkem768Params}
+ p384Adapter := nistHybridKEM{params: &p384mlkem1024Params}
+
// Setup X-Wing
xwingKP, err := NewXWingKeyPair()
if err != nil {
b.Fatal(err)
}
- xwingSS, xwingCt, err := XWingEncapsulate(xwingKP.publicKey)
+ xwingSS, xwingCt, err := xwingAdapter.encapsulate(xwingKP.publicKey)
if err != nil {
b.Fatal(err)
}
@@ -551,7 +555,7 @@ func BenchmarkHybridSubOps(b *testing.B) {
if err != nil {
b.Fatal(err)
}
- p256SS, p256Ct, err := P256MLKEM768Encapsulate(p256KP.publicKey)
+ p256SS, p256Ct, err := p256Adapter.encapsulate(p256KP.publicKey)
if err != nil {
b.Fatal(err)
}
@@ -561,7 +565,7 @@ func BenchmarkHybridSubOps(b *testing.B) {
if err != nil {
b.Fatal(err)
}
- p384SS, p384Ct, err := P384MLKEM1024Encapsulate(p384KP.publicKey)
+ p384SS, p384Ct, err := p384Adapter.encapsulate(p384KP.publicKey)
if err != nil {
b.Fatal(err)
}
@@ -569,19 +573,19 @@ func BenchmarkHybridSubOps(b *testing.B) {
salt := defaultTDFSalt()
// Pre-derive a wrap key for AES-GCM benchmarks
- wrapKey, err := deriveXWingWrapKey(xwingSS, salt, nil)
+ wrapKey, err := hkdfWrapKey(xwingSS, salt, nil)
if err != nil {
b.Fatal(err)
}
b.Run("XWing/Encapsulate", func(b *testing.B) {
for b.Loop() {
- sinkBytes, sinkBytes, errSink = XWingEncapsulate(xwingKP.publicKey)
+ sinkBytes, sinkBytes, errSink = xwingAdapter.encapsulate(xwingKP.publicKey)
}
})
b.Run("XWing/HKDF", func(b *testing.B) {
for b.Loop() {
- sinkBytes, errSink = deriveXWingWrapKey(xwingSS, salt, nil)
+ sinkBytes, errSink = hkdfWrapKey(xwingSS, salt, nil)
}
})
b.Run("XWing/AES-GCM-Encrypt", func(b *testing.B) {
@@ -594,25 +598,25 @@ func BenchmarkHybridSubOps(b *testing.B) {
}
})
b.Run("XWing/ASN1-Marshal", func(b *testing.B) {
- wrapped := XWingWrappedKey{XWingCiphertext: xwingCt, EncryptedDEK: testDEK}
+ wrapped := kemEnvelope{KEMCiphertext: xwingCt, EncryptedDEK: testDEK}
for b.Loop() {
sinkBytes, errSink = asn1.Marshal(wrapped)
}
})
// P256+MLKEM768 sub-ops
- p256WrapKey, err := deriveHybridNISTWrapKey(p256SS, salt, nil)
+ p256WrapKey, err := hkdfWrapKey(p256SS, salt, nil)
if err != nil {
b.Fatal(err)
}
b.Run("P256_MLKEM768/Encapsulate", func(b *testing.B) {
for b.Loop() {
- sinkBytes, sinkBytes, errSink = P256MLKEM768Encapsulate(p256KP.publicKey)
+ sinkBytes, sinkBytes, errSink = p256Adapter.encapsulate(p256KP.publicKey)
}
})
b.Run("P256_MLKEM768/HKDF", func(b *testing.B) {
for b.Loop() {
- sinkBytes, errSink = deriveHybridNISTWrapKey(p256SS, salt, nil)
+ sinkBytes, errSink = hkdfWrapKey(p256SS, salt, nil)
}
})
b.Run("P256_MLKEM768/AES-GCM-Encrypt", func(b *testing.B) {
@@ -625,25 +629,25 @@ func BenchmarkHybridSubOps(b *testing.B) {
}
})
b.Run("P256_MLKEM768/ASN1-Marshal", func(b *testing.B) {
- wrapped := HybridNISTWrappedKey{HybridCiphertext: p256Ct, EncryptedDEK: testDEK}
+ wrapped := kemEnvelope{KEMCiphertext: p256Ct, EncryptedDEK: testDEK}
for b.Loop() {
sinkBytes, errSink = asn1.Marshal(wrapped)
}
})
// P384+MLKEM1024 sub-ops
- p384WrapKey, err := deriveHybridNISTWrapKey(p384SS, salt, nil)
+ p384WrapKey, err := hkdfWrapKey(p384SS, salt, nil)
if err != nil {
b.Fatal(err)
}
b.Run("P384_MLKEM1024/Encapsulate", func(b *testing.B) {
for b.Loop() {
- sinkBytes, sinkBytes, errSink = P384MLKEM1024Encapsulate(p384KP.publicKey)
+ sinkBytes, sinkBytes, errSink = p384Adapter.encapsulate(p384KP.publicKey)
}
})
b.Run("P384_MLKEM1024/HKDF", func(b *testing.B) {
for b.Loop() {
- sinkBytes, errSink = deriveHybridNISTWrapKey(p384SS, salt, nil)
+ sinkBytes, errSink = hkdfWrapKey(p384SS, salt, nil)
}
})
b.Run("P384_MLKEM1024/AES-GCM-Encrypt", func(b *testing.B) {
@@ -656,7 +660,7 @@ func BenchmarkHybridSubOps(b *testing.B) {
}
})
b.Run("P384_MLKEM1024/ASN1-Marshal", func(b *testing.B) {
- wrapped := HybridNISTWrappedKey{HybridCiphertext: p384Ct, EncryptedDEK: testDEK}
+ wrapped := kemEnvelope{KEMCiphertext: p384Ct, EncryptedDEK: testDEK}
for b.Loop() {
sinkBytes, errSink = asn1.Marshal(wrapped)
}
diff --git a/lib/ocrypto/ec_key_pair.go b/lib/ocrypto/ec_key_pair.go
index 70e30cc8df..11a86d96fb 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"
@@ -22,11 +23,13 @@ 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"
+ 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"
)
// ParseKeyType validates a string as a known KeyType, returning an error for
@@ -35,6 +38,7 @@ 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:
@@ -79,6 +83,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,6 +96,14 @@ type ECKeyPair struct {
PrivateKey *ecdsa.PrivateKey
}
+type MLKEMKeyPair struct {
+ PrivateKey *mlkem.DecapsulationKey768
+}
+
+type MLKEM1024KeyPair struct {
+ PrivateKey *mlkem.DecapsulationKey1024
+}
+
func IsECKeyType(kt KeyType) bool {
switch kt { //nolint:exhaustive // only handle ec types
case EC256Key, EC384Key, EC521Key:
@@ -106,6 +122,15 @@ func IsRSAKeyType(kt KeyType) bool {
}
}
+func IsMLKEMKeyType(kt KeyType) bool {
+ switch kt { //nolint:exhaustive // only handle mlkem types
+ case MLKEM768Key, MLKEM1024Key:
+ return true
+ default:
+ return false
+ }
+}
+
// GetECCurveFromECCMode return elliptic curve from ecc mode
func GetECCurveFromECCMode(mode ECCMode) (elliptic.Curve, error) {
var c elliptic.Curve
@@ -212,7 +237,7 @@ func (keyPair ECKeyPair) PrivateKeyInPemFormat() (string, error) {
privateKeyPem := pem.EncodeToMemory(
&pem.Block{
- Type: "PRIVATE KEY",
+ Type: pemBlockPrivateKey,
Bytes: privateKeyBytes,
},
)
@@ -232,7 +257,7 @@ func (keyPair ECKeyPair) PublicKeyInPemFormat() (string, error) {
publicKeyPem := pem.EncodeToMemory(
&pem.Block{
- Type: "PUBLIC KEY",
+ Type: pemBlockPublicKey,
Bytes: publicKeyBytes,
},
)
@@ -452,7 +477,7 @@ func ECPrivateKeyInPemFormat(privateKey ecdsa.PrivateKey) (string, error) {
privateKeyPem := pem.EncodeToMemory(
&pem.Block{
- Type: "PRIVATE KEY",
+ Type: pemBlockPrivateKey,
Bytes: privateKeyBytes,
},
)
@@ -468,7 +493,7 @@ func ECPublicKeyInPemFormat(publicKey ecdsa.PublicKey) (string, error) {
publicKeyPem := pem.EncodeToMemory(
&pem.Block{
- Type: "PUBLIC KEY",
+ Type: pemBlockPublicKey,
Bytes: pkb,
},
)
@@ -509,3 +534,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/hybrid_common.go b/lib/ocrypto/hybrid_common.go
index 4f4ee05417..bf7385c9ad 100644
--- a/lib/ocrypto/hybrid_common.go
+++ b/lib/ocrypto/hybrid_common.go
@@ -6,42 +6,44 @@ import (
"fmt"
)
-// HybridWrapDEK parses the recipient's hybrid public key PEM, encapsulates
-// against it using the scheme implied by ktype, and returns the ASN.1-encoded
-// wrapped DEK envelope used in `hybrid-wrapped` manifests. It dispatches across
-// both the X-Wing and NIST EC + ML-KEM families so SDK call sites do not need
-// to repeat the algorithm switch.
+// WrapDEK parses the recipient's KEM public key PEM, encapsulates against it
+// using the scheme implied by ktype, and returns the ASN.1-encoded wrapped DEK
+// envelope used in `hybrid-wrapped` and `mlkem-wrapped` manifests. It covers
+// every KEM family — pure ML-KEM, X-Wing, and the NIST EC + ML-KEM hybrids —
+// so SDK call sites do not need to repeat the algorithm switch.
//
-// The HKDF salt is the default TDF salt; callers that need a non-default salt
-// should call the per-scheme `*WrapDEK` helpers directly.
-func HybridWrapDEK(ktype KeyType, kasPublicKeyPEM string, dek []byte) ([]byte, error) {
- switch ktype { //nolint:exhaustive // only handle hybrid types
- case HybridXWingKey:
- pubKey, err := XWingPubKeyFromPem([]byte(kasPublicKeyPEM))
- if err != nil {
- return nil, fmt.Errorf("X-Wing public key: %w", err)
- }
- return XWingWrapDEK(pubKey, dek)
- case HybridSecp256r1MLKEM768Key:
- pubKey, err := P256MLKEM768PubKeyFromPem([]byte(kasPublicKeyPEM))
- if err != nil {
- return nil, fmt.Errorf("P-256+ML-KEM-768 public key: %w", err)
- }
- return P256MLKEM768WrapDEK(pubKey, dek)
- case HybridSecp384r1MLKEM1024Key:
- pubKey, err := P384MLKEM1024PubKeyFromPem([]byte(kasPublicKeyPEM))
- if err != nil {
- return nil, fmt.Errorf("P-384+ML-KEM-1024 public key: %w", err)
- }
- return P384MLKEM1024WrapDEK(pubKey, dek)
- default:
- return nil, fmt.Errorf("unsupported hybrid key type: %s", ktype)
+// For hybrid PQ/T schemes the HKDF salt is the default TDF salt; callers that
+// need a non-default salt should construct an encryptor via
+// FromPublicPEMWithSalt instead. Pure ML-KEM ignores salt/info and uses the
+// 32-byte Decaps shared secret directly as the AES-GCM wrap key — see
+// adr/decisions/2026-06-16-mlkem-direct-key-wrap.md.
+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("parse %s public key: %w", ktype, err)
}
+ if got := enc.KeyType(); got != ktype {
+ return nil, fmt.Errorf("KEM key type mismatch: want %s, got %s", ktype, got)
+ }
+ return enc.Encrypt(dek)
+}
+
+// HybridWrapDEK is the legacy entrypoint for hybrid PQ/T wrapping. It now
+// delegates to WrapDEK, which covers both hybrid and pure ML-KEM schemes.
+//
+// Deprecated: Use WrapDEK.
+func HybridWrapDEK(ktype KeyType, kasPublicKeyPEM string, dek []byte) ([]byte, error) {
+ return WrapDEK(ktype, kasPublicKeyPEM, dek)
}
-// defaultTDFSalt returns the salt used for HKDF derivation in all TDF hybrid
-// key wrapping schemes (X-Wing and NIST EC + ML-KEM). Defined here rather than
-// in a per-scheme file so that any change applies uniformly across schemes.
+// defaultTDFSalt returns the salt used for HKDF derivation in the hybrid
+// PQ/T KEM wrapping schemes (X-Wing and NIST EC + ML-KEM) and in ECIES.
+// Pure ML-KEM uses the Decaps shared secret directly as the AES-GCM wrap
+// key (see adr/decisions/2026-06-16-mlkem-direct-key-wrap.md) and does
+// not call this helper.
func defaultTDFSalt() []byte {
digest := sha256.New()
digest.Write([]byte("TDF"))
@@ -66,6 +68,24 @@ func rawToPEM(blockType string, raw []byte, expectedSize int) (string, error) {
return string(pemBytes), nil
}
+// decodeSizedPEMBlock decodes a PEM block of the given type and verifies its
+// payload is exactly expectedSize bytes long. Used by X-Wing and NIST hybrid
+// PEM helpers that carry raw-bytes PEM blobs (pre-SPKI-migration).
+func decodeSizedPEMBlock(data []byte, blockType string, expectedSize int) ([]byte, error) {
+ block, _ := pem.Decode(data)
+ if block == nil {
+ return nil, fmt.Errorf("failed to parse PEM formatted %s", blockType)
+ }
+ if block.Type != blockType {
+ return nil, fmt.Errorf("unexpected PEM block type: got %s want %s", block.Type, blockType)
+ }
+ if len(block.Bytes) != expectedSize {
+ return nil, fmt.Errorf("invalid %s size: got %d want %d", blockType, len(block.Bytes), expectedSize)
+ }
+
+ return append([]byte(nil), block.Bytes...), nil
+}
+
// cloneOrNil returns a copy of data, or nil if data is empty.
func cloneOrNil(data []byte) []byte {
if len(data) == 0 {
diff --git a/lib/ocrypto/hybrid_nist.go b/lib/ocrypto/hybrid_nist.go
index ee0a575ac5..1de0f08b91 100644
--- a/lib/ocrypto/hybrid_nist.go
+++ b/lib/ocrypto/hybrid_nist.go
@@ -4,12 +4,7 @@ import (
"crypto/ecdh"
"crypto/mlkem"
"crypto/rand"
- "crypto/sha256"
- "encoding/asn1"
"fmt"
- "io"
-
- "golang.org/x/crypto/hkdf"
)
const (
@@ -52,15 +47,6 @@ const (
PEMBlockP384MLKEM1024PrivateKey = "SECP384R1 MLKEM1024 PRIVATE KEY"
)
-// AES-256 key size used for wrap key derivation.
-const hybridNISTWrapKeySize = 32
-
-// HybridNISTWrappedKey is the ASN.1 envelope stored in wrapped_key.
-type HybridNISTWrappedKey struct {
- HybridCiphertext []byte `asn1:"tag:0"`
- EncryptedDEK []byte `asn1:"tag:1"`
-}
-
// hybridNISTParams captures the curve-specific parameters for a NIST hybrid scheme.
type hybridNISTParams struct {
curve ecdh.Curve
@@ -105,22 +91,6 @@ type HybridNISTKeyPair struct {
params *hybridNISTParams
}
-// HybridNISTEncryptor implements PublicKeyEncryptor for NIST hybrid schemes.
-type HybridNISTEncryptor struct {
- publicKey []byte
- salt []byte
- info []byte
- params *hybridNISTParams
-}
-
-// HybridNISTDecryptor implements PrivateKeyDecryptor for NIST hybrid schemes.
-type HybridNISTDecryptor struct {
- privateKey []byte
- salt []byte
- info []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
@@ -221,299 +191,34 @@ func P384MLKEM1024PrivateKeyFromPem(data []byte) ([]byte, error) {
return decodeSizedPEMBlock(data, PEMBlockP384MLKEM1024PrivateKey, P384MLKEM1024PrivateKeySize)
}
-func NewP256MLKEM768Encryptor(publicKey, salt, info []byte) (*HybridNISTEncryptor, error) {
- return newHybridNISTEncryptor(&p256mlkem768Params, publicKey, salt, info)
-}
-
-func NewP384MLKEM1024Encryptor(publicKey, salt, info []byte) (*HybridNISTEncryptor, error) {
- return newHybridNISTEncryptor(&p384mlkem1024Params, publicKey, salt, info)
-}
-
-func newHybridNISTEncryptor(p *hybridNISTParams, publicKey, salt, info []byte) (*HybridNISTEncryptor, error) {
- expectedSize := p.ecPubSize + p.mlkemPubSize
- if len(publicKey) != expectedSize {
- return nil, fmt.Errorf("invalid %s public key size: got %d want %d", p.keyType, len(publicKey), expectedSize)
- }
- return &HybridNISTEncryptor{
- publicKey: append([]byte(nil), publicKey...),
- salt: cloneOrNil(salt),
- info: cloneOrNil(info),
- params: p,
- }, nil
-}
-
-func (e *HybridNISTEncryptor) Encrypt(data []byte) ([]byte, error) {
- return hybridNISTWrapDEK(e.params, e.publicKey, data, e.salt, e.info)
-}
-
-func (e *HybridNISTEncryptor) PublicKeyInPemFormat() (string, error) {
- return rawToPEM(e.params.pubPEMBlock, e.publicKey, e.params.ecPubSize+e.params.mlkemPubSize)
-}
-
-func (e *HybridNISTEncryptor) Type() SchemeType { return Hybrid }
-func (e *HybridNISTEncryptor) KeyType() KeyType { return e.params.keyType }
-func (e *HybridNISTEncryptor) EphemeralKey() []byte { return nil }
-
-func (e *HybridNISTEncryptor) Metadata() (map[string]string, error) {
- return make(map[string]string), nil
-}
-
-func NewP256MLKEM768Decryptor(privateKey []byte) (*HybridNISTDecryptor, error) {
- return NewSaltedP256MLKEM768Decryptor(privateKey, defaultTDFSalt(), nil)
-}
-
-func NewSaltedP256MLKEM768Decryptor(privateKey, salt, info []byte) (*HybridNISTDecryptor, error) {
- return newHybridNISTDecryptor(&p256mlkem768Params, privateKey, salt, info)
-}
-
-func NewP384MLKEM1024Decryptor(privateKey []byte) (*HybridNISTDecryptor, error) {
- return NewSaltedP384MLKEM1024Decryptor(privateKey, defaultTDFSalt(), nil)
-}
-
-func NewSaltedP384MLKEM1024Decryptor(privateKey, salt, info []byte) (*HybridNISTDecryptor, error) {
- return newHybridNISTDecryptor(&p384mlkem1024Params, privateKey, salt, info)
-}
-
-func newHybridNISTDecryptor(p *hybridNISTParams, privateKey, salt, info []byte) (*HybridNISTDecryptor, error) {
- expectedSize := p.ecPrivSize + p.mlkemPrivSize
- if len(privateKey) != expectedSize {
- return nil, fmt.Errorf("invalid %s private key size: got %d want %d", p.keyType, len(privateKey), expectedSize)
- }
- return &HybridNISTDecryptor{
- privateKey: append([]byte(nil), privateKey...),
- salt: cloneOrNil(salt),
- info: cloneOrNil(info),
- params: p,
- }, nil
-}
-
-func (d *HybridNISTDecryptor) Decrypt(data []byte) ([]byte, error) {
- return hybridNISTUnwrapDEK(d.params, d.privateKey, data, d.salt, d.info)
-}
-
+// P256MLKEM768WrapDEK wraps a DEK using the P-256 + ML-KEM-768 hybrid scheme.
+//
+// Deprecated: Use WrapDEK with HybridSecp256r1MLKEM768Key, or construct via
+// FromPublicPEM.
func P256MLKEM768WrapDEK(publicKeyRaw, dek []byte) ([]byte, error) {
- return hybridNISTWrapDEK(&p256mlkem768Params, publicKeyRaw, dek, defaultTDFSalt(), nil)
+ return wrapDEKWithKEM(nistHybridKEM{params: &p256mlkem768Params}, publicKeyRaw, dek, defaultTDFSalt(), nil)
}
+// P256MLKEM768UnwrapDEK unwraps an envelope produced by P256MLKEM768WrapDEK
+// using the supplied raw P-256 + ML-KEM-768 private key. This is the binary-
+// bytes counterpart to FromPrivatePEM; callers that already hold raw key
+// material can use it directly without re-encoding to PEM.
func P256MLKEM768UnwrapDEK(privateKeyRaw, wrappedDER []byte) ([]byte, error) {
- return hybridNISTUnwrapDEK(&p256mlkem768Params, privateKeyRaw, wrappedDER, defaultTDFSalt(), nil)
+ return unwrapDEKWithKEM(nistHybridKEM{params: &p256mlkem768Params}, privateKeyRaw, wrappedDER, defaultTDFSalt(), nil)
}
+// P384MLKEM1024WrapDEK wraps a DEK using the P-384 + ML-KEM-1024 hybrid scheme.
+//
+// Deprecated: Use WrapDEK with HybridSecp384r1MLKEM1024Key, or construct via
+// FromPublicPEM.
func P384MLKEM1024WrapDEK(publicKeyRaw, dek []byte) ([]byte, error) {
- return hybridNISTWrapDEK(&p384mlkem1024Params, publicKeyRaw, dek, defaultTDFSalt(), nil)
+ return wrapDEKWithKEM(nistHybridKEM{params: &p384mlkem1024Params}, publicKeyRaw, dek, defaultTDFSalt(), nil)
}
+// P384MLKEM1024UnwrapDEK unwraps an envelope produced by P384MLKEM1024WrapDEK
+// using the supplied raw P-384 + ML-KEM-1024 private key. This is the binary-
+// bytes counterpart to FromPrivatePEM; callers that already hold raw key
+// material can use it directly without re-encoding to PEM.
func P384MLKEM1024UnwrapDEK(privateKeyRaw, wrappedDER []byte) ([]byte, error) {
- return hybridNISTUnwrapDEK(&p384mlkem1024Params, privateKeyRaw, wrappedDER, defaultTDFSalt(), nil)
-}
-
-// hybridNISTEncapsulate performs hybrid encapsulation:
-// 1. Generates an ephemeral EC key and computes ECDH shared secret
-// 2. Encapsulates ML-KEM to produce a post-quantum shared secret
-// 3. Combines both secrets (ECDH || ML-KEM)
-// 4. Builds hybrid ciphertext (ephemeral EC point || ML-KEM ciphertext)
-//
-// Returns (combinedSecret, hybridCiphertext) without applying KDF or encryption.
-func hybridNISTEncapsulate(p *hybridNISTParams, publicKeyRaw []byte) ([]byte, []byte, error) {
- expectedPubSize := p.ecPubSize + p.mlkemPubSize
- if len(publicKeyRaw) != expectedPubSize {
- return nil, nil, fmt.Errorf("invalid %s public key size: got %d want %d", p.keyType, len(publicKeyRaw), expectedPubSize)
- }
-
- ecPubBytes := publicKeyRaw[:p.ecPubSize]
- mlkemPubBytes := publicKeyRaw[p.ecPubSize:]
-
- // ECDH: generate ephemeral key, compute shared secret
- ecPub, err := p.curve.NewPublicKey(ecPubBytes)
- if err != nil {
- return nil, nil, fmt.Errorf("invalid EC public key: %w", err)
- }
- ephemeral, err := p.curve.GenerateKey(rand.Reader)
- if err != nil {
- return nil, nil, fmt.Errorf("ECDH ephemeral key generation failed: %w", err)
- }
- ecdhSecret, err := ephemeral.ECDH(ecPub)
- if err != nil {
- return nil, nil, fmt.Errorf("ECDH failed: %w", err)
- }
- ephemeralPub := ephemeral.PublicKey().Bytes()
-
- // ML-KEM: encapsulate
- var mlkemSecret, mlkemCt []byte
- switch p.keyType { //nolint:exhaustive // only NIST hybrid types
- case HybridSecp256r1MLKEM768Key:
- ek, ekErr := mlkem.NewEncapsulationKey768(mlkemPubBytes)
- if ekErr != nil {
- return nil, nil, fmt.Errorf("mlkem768 encapsulation key: %w", ekErr)
- }
- mlkemSecret, mlkemCt = ek.Encapsulate()
- case HybridSecp384r1MLKEM1024Key:
- ek, ekErr := mlkem.NewEncapsulationKey1024(mlkemPubBytes)
- if ekErr != nil {
- return nil, nil, fmt.Errorf("mlkem1024 encapsulation key: %w", ekErr)
- }
- mlkemSecret, mlkemCt = ek.Encapsulate()
- default:
- return nil, nil, fmt.Errorf("unsupported ML-KEM key type: %s", p.keyType)
- }
-
- // Combine secrets: ECDH || ML-KEM
- combinedSecret := make([]byte, 0, len(ecdhSecret)+len(mlkemSecret))
- combinedSecret = append(combinedSecret, ecdhSecret...)
- combinedSecret = append(combinedSecret, mlkemSecret...)
-
- // Build hybrid ciphertext: ephemeral EC point || ML-KEM ciphertext
- hybridCt := make([]byte, 0, len(ephemeralPub)+len(mlkemCt))
- hybridCt = append(hybridCt, ephemeralPub...)
- hybridCt = append(hybridCt, mlkemCt...)
-
- return combinedSecret, hybridCt, nil
-}
-
-// P256MLKEM768Encapsulate performs P-256 ECDH + ML-KEM-768 hybrid encapsulation.
-func P256MLKEM768Encapsulate(publicKeyRaw []byte) ([]byte, []byte, error) {
- return hybridNISTEncapsulate(&p256mlkem768Params, publicKeyRaw)
-}
-
-// P384MLKEM1024Encapsulate performs P-384 ECDH + ML-KEM-1024 hybrid encapsulation.
-func P384MLKEM1024Encapsulate(publicKeyRaw []byte) ([]byte, []byte, error) {
- return hybridNISTEncapsulate(&p384mlkem1024Params, publicKeyRaw)
-}
-
-func hybridNISTWrapDEK(p *hybridNISTParams, publicKeyRaw, dek, salt, info []byte) ([]byte, error) {
- combinedSecret, hybridCt, err := hybridNISTEncapsulate(p, publicKeyRaw)
- if err != nil {
- return nil, err
- }
-
- // Derive AES-256 wrap key via HKDF
- wrapKey, err := deriveHybridNISTWrapKey(combinedSecret, salt, info)
- if err != nil {
- return nil, err
- }
-
- // AES-GCM encrypt DEK
- 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, salt, info []byte) ([]byte, error) {
- expectedPrivSize := p.ecPrivSize + p.mlkemPrivSize
- if len(privateKeyRaw) != expectedPrivSize {
- return nil, fmt.Errorf("invalid %s private key size: got %d want %d", p.keyType, len(privateKeyRaw), expectedPrivSize)
- }
-
- 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.ecPubSize + p.mlkemCtSize
- if len(wrapped.HybridCiphertext) != expectedCtSize {
- return nil, fmt.Errorf("invalid %s ciphertext size: got %d want %d",
- p.keyType, len(wrapped.HybridCiphertext), expectedCtSize)
- }
-
- // Split hybrid ciphertext
- ephemeralPubBytes := wrapped.HybridCiphertext[:p.ecPubSize]
- mlkemCtBytes := wrapped.HybridCiphertext[p.ecPubSize:]
-
- // Split private key
- ecPrivBytes := privateKeyRaw[:p.ecPrivSize]
- mlkemPrivBytes := privateKeyRaw[p.ecPrivSize:]
-
- // ECDH: reconstruct shared secret
- ecPriv, err := p.curve.NewPrivateKey(ecPrivBytes)
- if err != nil {
- return nil, fmt.Errorf("invalid EC private key: %w", err)
- }
- ephemeralPub, err := p.curve.NewPublicKey(ephemeralPubBytes)
- if err != nil {
- return nil, fmt.Errorf("invalid ephemeral EC public key: %w", err)
- }
- ecdhSecret, err := ecPriv.ECDH(ephemeralPub)
- if err != nil {
- return nil, fmt.Errorf("ECDH failed: %w", err)
- }
-
- // ML-KEM: decapsulate. Implicit rejection (FIPS 203 §6.3) means a wrong-key
- // ciphertext yields a pseudorandom shared secret without an error here;
- // authentication is enforced by the AES-GCM decrypt below.
- var mlkemSecret []byte
- switch p.keyType { //nolint:exhaustive // only NIST hybrid types
- case HybridSecp256r1MLKEM768Key:
- dk, dkErr := mlkem.NewDecapsulationKey768(mlkemPrivBytes)
- if dkErr != nil {
- return nil, fmt.Errorf("mlkem768 decapsulation key: %w", dkErr)
- }
- mlkemSecret, err = dk.Decapsulate(mlkemCtBytes)
- case HybridSecp384r1MLKEM1024Key:
- dk, dkErr := mlkem.NewDecapsulationKey1024(mlkemPrivBytes)
- if dkErr != nil {
- return nil, fmt.Errorf("mlkem1024 decapsulation key: %w", dkErr)
- }
- mlkemSecret, err = dk.Decapsulate(mlkemCtBytes)
- default:
- return nil, fmt.Errorf("unsupported ML-KEM key type: %s", p.keyType)
- }
- if err != nil {
- return nil, fmt.Errorf("ML-KEM decapsulate failed: %w", err)
- }
-
- // Combine secrets: ECDH || ML-KEM
- combinedSecret := make([]byte, 0, len(ecdhSecret)+len(mlkemSecret))
- combinedSecret = append(combinedSecret, ecdhSecret...)
- combinedSecret = append(combinedSecret, mlkemSecret...)
-
- // Derive AES-256 wrap key via HKDF
- wrapKey, err := deriveHybridNISTWrapKey(combinedSecret, salt, info)
- if err != nil {
- return nil, err
- }
-
- // AES-GCM decrypt DEK
- 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
-}
-
-func deriveHybridNISTWrapKey(combinedSecret, salt, info []byte) ([]byte, error) {
- if len(salt) == 0 {
- salt = defaultTDFSalt()
- }
-
- hkdfObj := hkdf.New(sha256.New, combinedSecret, salt, info)
- derivedKey := make([]byte, hybridNISTWrapKeySize)
- if _, err := io.ReadFull(hkdfObj, derivedKey); err != nil {
- return nil, fmt.Errorf("hkdf failure: %w", err)
- }
-
- return derivedKey, nil
+ return unwrapDEKWithKEM(nistHybridKEM{params: &p384mlkem1024Params}, privateKeyRaw, wrappedDER, defaultTDFSalt(), nil)
}
diff --git a/lib/ocrypto/hybrid_nist_test.go b/lib/ocrypto/hybrid_nist_test.go
index e7c9808aae..2a741644f4 100644
--- a/lib/ocrypto/hybrid_nist_test.go
+++ b/lib/ocrypto/hybrid_nist_test.go
@@ -115,16 +115,16 @@ func TestP384MLKEM1024WrapUnwrapWrongKeyFails(t *testing.T) {
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"),
+func TestHybridNISTEnvelopeASN1RoundTrip(t *testing.T) {
+ original := kemEnvelope{
+ KEMCiphertext: []byte("hybrid-ciphertext-data"),
+ EncryptedDEK: []byte("encrypted-dek-data"),
}
der, err := asn1.Marshal(original)
require.NoError(t, err)
- var decoded HybridNISTWrappedKey
+ var decoded kemEnvelope
rest, err := asn1.Unmarshal(der, &decoded)
require.NoError(t, err)
assert.Empty(t, rest)
@@ -146,23 +146,18 @@ func TestP256MLKEM768PEMDispatch(t *testing.T) {
decryptor, err := FromPrivatePEMWithSalt(privatePEM, []byte("salt"), []byte("info"))
require.NoError(t, err)
- nistEncryptor, ok := encryptor.(*HybridNISTEncryptor)
- require.True(t, ok)
- assert.Equal(t, Hybrid, nistEncryptor.Type())
- assert.Equal(t, HybridSecp256r1MLKEM768Key, nistEncryptor.KeyType())
- assert.Nil(t, nistEncryptor.EphemeralKey())
+ assert.Equal(t, Hybrid, encryptor.Type())
+ assert.Equal(t, HybridSecp256r1MLKEM768Key, encryptor.KeyType())
+ assert.Nil(t, encryptor.EphemeralKey())
- metadata, err := nistEncryptor.Metadata()
+ metadata, err := encryptor.Metadata()
require.NoError(t, err)
assert.Empty(t, metadata)
- nistDecryptor, ok := decryptor.(*HybridNISTDecryptor)
- require.True(t, ok)
-
- wrapped, err := nistEncryptor.Encrypt([]byte("dispatch-dek"))
+ wrapped, err := encryptor.Encrypt([]byte("dispatch-dek"))
require.NoError(t, err)
- plaintext, err := nistDecryptor.Decrypt(wrapped)
+ plaintext, err := decryptor.Decrypt(wrapped)
require.NoError(t, err)
assert.Equal(t, []byte("dispatch-dek"), plaintext)
}
@@ -182,19 +177,14 @@ func TestP384MLKEM1024PEMDispatch(t *testing.T) {
decryptor, err := FromPrivatePEMWithSalt(privatePEM, []byte("salt"), []byte("info"))
require.NoError(t, err)
- nistEncryptor, ok := encryptor.(*HybridNISTEncryptor)
- 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)
- require.True(t, ok)
+ assert.Equal(t, Hybrid, encryptor.Type())
+ assert.Equal(t, HybridSecp384r1MLKEM1024Key, encryptor.KeyType())
+ assert.Nil(t, encryptor.EphemeralKey())
- wrapped, err := nistEncryptor.Encrypt([]byte("dispatch-dek-384"))
+ wrapped, err := encryptor.Encrypt([]byte("dispatch-dek-384"))
require.NoError(t, err)
- plaintext, err := nistDecryptor.Decrypt(wrapped)
+ plaintext, err := decryptor.Decrypt(wrapped)
require.NoError(t, err)
assert.Equal(t, []byte("dispatch-dek-384"), plaintext)
}
@@ -209,7 +199,7 @@ func TestP256MLKEM768Encapsulate(t *testing.T) {
pubKeyRaw, err := P256MLKEM768PubKeyFromPem([]byte(pubKey))
require.NoError(t, err)
- combinedSecret, hybridCt, err := P256MLKEM768Encapsulate(pubKeyRaw)
+ combinedSecret, hybridCt, err := nistHybridKEM{params: &p256mlkem768Params}.encapsulate(pubKeyRaw)
require.NoError(t, err)
assert.NotEmpty(t, combinedSecret)
assert.Len(t, hybridCt, P256MLKEM768CiphertextSize)
@@ -225,7 +215,7 @@ func TestP384MLKEM1024Encapsulate(t *testing.T) {
pubKeyRaw, err := P384MLKEM1024PubKeyFromPem([]byte(pubKey))
require.NoError(t, err)
- combinedSecret, hybridCt, err := P384MLKEM1024Encapsulate(pubKeyRaw)
+ combinedSecret, hybridCt, err := nistHybridKEM{params: &p384mlkem1024Params}.encapsulate(pubKeyRaw)
require.NoError(t, err)
assert.NotEmpty(t, combinedSecret)
assert.Len(t, hybridCt, P384MLKEM1024CiphertextSize)
diff --git a/lib/ocrypto/kem.go b/lib/ocrypto/kem.go
new file mode 100644
index 0000000000..b34da9f329
--- /dev/null
+++ b/lib/ocrypto/kem.go
@@ -0,0 +1,532 @@
+package ocrypto
+
+import (
+ "crypto/mlkem"
+ "crypto/rand"
+ "crypto/sha256"
+ "encoding/asn1"
+ "encoding/pem"
+ "fmt"
+ "io"
+
+ "github.com/cloudflare/circl/kem/xwing"
+ "golang.org/x/crypto/hkdf"
+)
+
+// kem is the post-quantum KEM contract implemented by ML-KEM, X-Wing, and the
+// NIST hybrid PQ/T schemes. Unifying behind this single interface collapses the
+// `hybrid-wrapped` and `mlkem-wrapped` wrap/unwrap paths into one envelope and
+// one AES-GCM call site; per-scheme key-derivation policy is selected by
+// 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
+}
+
+// kemByKeyType returns the kem adapter for the supplied KeyType, covering both
+// pure ML-KEM and hybrid PQ/T schemes. This is the entry point for wrap-side
+// dispatch where the caller knows the KAS algorithm but has not yet decoded a
+// public key.
+func kemByKeyType(kt KeyType) (kem, bool) {
+ switch kt { //nolint:exhaustive // only handle KEM types; other KeyTypes return false
+ case MLKEM768Key:
+ return mlkemKEM{variant: mlkem768}, true
+ case MLKEM1024Key:
+ return mlkemKEM{variant: mlkem1024}, true
+ case HybridXWingKey:
+ return xwingKEM{}, true
+ case HybridSecp256r1MLKEM768Key:
+ return nistHybridKEM{params: &p256mlkem768Params}, true
+ case HybridSecp384r1MLKEM1024Key:
+ return nistHybridKEM{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 — handled by the unified wrap/unwrap path.
+func IsKEMKeyType(kt KeyType) bool {
+ _, ok := kemByKeyType(kt)
+ return ok
+}
+
+// --- 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
+}
+
+// --- xwingKEM adapter -------------------------------------------------------
+
+type xwingKEM struct{}
+
+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) {
+ if len(pub) != XWingPublicKeySize {
+ return nil, nil, fmt.Errorf("invalid X-Wing public key size: got %d want %d", len(pub), XWingPublicKeySize)
+ }
+ ss, ct, err := xwing.Encapsulate(pub, nil)
+ if err != nil {
+ return nil, nil, fmt.Errorf("xwing.Encapsulate failed: %w", err)
+ }
+ return ss, ct, nil
+}
+
+func (xwingKEM) decapsulate(priv, ct []byte) ([]byte, error) {
+ if len(priv) != XWingPrivateKeySize {
+ return nil, fmt.Errorf("invalid X-Wing private key size: got %d want %d", len(priv), XWingPrivateKeySize)
+ }
+ return xwing.Decapsulate(ct, priv), nil
+}
+
+func (xwingKEM) publicKeyPEM(pub []byte) (string, error) {
+ return rawToPEM(PEMBlockXWingPublicKey, pub, XWingPublicKeySize)
+}
+
+// wrapKey derives a 32-byte AES key from the X-Wing shared secret via
+// HKDF-SHA256 over (salt, info).
+func (xwingKEM) wrapKey(sharedSecret, salt, info []byte) ([]byte, error) {
+ return hkdfWrapKey(sharedSecret, salt, info)
+}
+
+// --- nistHybridKEM adapter --------------------------------------------------
+
+type nistHybridKEM struct {
+ params *hybridNISTParams
+}
+
+func (h nistHybridKEM) keyType() KeyType { return h.params.keyType }
+func (nistHybridKEM) scheme() SchemeType { return Hybrid }
+func (h nistHybridKEM) pubSize() int { return h.params.ecPubSize + h.params.mlkemPubSize }
+func (h nistHybridKEM) privSize() int { return h.params.ecPrivSize + h.params.mlkemPrivSize }
+func (h nistHybridKEM) ctSize() int { return h.params.ecPubSize + h.params.mlkemCtSize }
+
+// mlkemAdapter returns the ML-KEM half of this hybrid scheme.
+func (h nistHybridKEM) mlkemAdapter() mlkemKEM {
+ if h.params.mlkemPubSize == MLKEM1024PublicKeySize {
+ return mlkemKEM{variant: mlkem1024}
+ }
+ return mlkemKEM{variant: mlkem768}
+}
+
+func (h nistHybridKEM) encapsulate(pub []byte) ([]byte, []byte, error) {
+ if len(pub) != h.pubSize() {
+ return nil, nil, fmt.Errorf("invalid %s public key size: got %d want %d", h.keyType(), len(pub), h.pubSize())
+ }
+ ecPubBytes := pub[:h.params.ecPubSize]
+ mlkemPubBytes := pub[h.params.ecPubSize:]
+
+ ecPub, err := h.params.curve.NewPublicKey(ecPubBytes)
+ if err != nil {
+ return nil, nil, fmt.Errorf("invalid EC public key: %w", err)
+ }
+ ephemeral, err := h.params.curve.GenerateKey(rand.Reader)
+ if err != nil {
+ return nil, nil, fmt.Errorf("ECDH ephemeral key generation failed: %w", err)
+ }
+ ecdhSecret, err := ephemeral.ECDH(ecPub)
+ if err != nil {
+ return nil, nil, fmt.Errorf("ECDH failed: %w", err)
+ }
+ ephemeralPub := ephemeral.PublicKey().Bytes()
+
+ mlkemSecret, mlkemCt, err := h.mlkemAdapter().encapsulate(mlkemPubBytes)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ combinedSecret := make([]byte, 0, len(ecdhSecret)+len(mlkemSecret))
+ combinedSecret = append(combinedSecret, ecdhSecret...)
+ combinedSecret = append(combinedSecret, mlkemSecret...)
+
+ hybridCt := make([]byte, 0, len(ephemeralPub)+len(mlkemCt))
+ hybridCt = append(hybridCt, ephemeralPub...)
+ hybridCt = append(hybridCt, mlkemCt...)
+
+ return combinedSecret, hybridCt, nil
+}
+
+func (h nistHybridKEM) decapsulate(priv, ct []byte) ([]byte, error) {
+ if len(priv) != h.privSize() {
+ return nil, fmt.Errorf("invalid %s private key size: got %d want %d", h.keyType(), len(priv), h.privSize())
+ }
+ if len(ct) != h.ctSize() {
+ return nil, fmt.Errorf("invalid %s ciphertext size: got %d want %d", h.keyType(), len(ct), h.ctSize())
+ }
+
+ ephemeralPubBytes := ct[:h.params.ecPubSize]
+ mlkemCtBytes := ct[h.params.ecPubSize:]
+ ecPrivBytes := priv[:h.params.ecPrivSize]
+ mlkemPrivBytes := priv[h.params.ecPrivSize:]
+
+ ecPriv, err := h.params.curve.NewPrivateKey(ecPrivBytes)
+ if err != nil {
+ return nil, fmt.Errorf("invalid EC private key: %w", err)
+ }
+ ephemeralPub, err := h.params.curve.NewPublicKey(ephemeralPubBytes)
+ if err != nil {
+ return nil, fmt.Errorf("invalid ephemeral EC public key: %w", err)
+ }
+ ecdhSecret, err := ecPriv.ECDH(ephemeralPub)
+ if err != nil {
+ return nil, fmt.Errorf("ECDH failed: %w", err)
+ }
+
+ // FIPS 203 §6.3 implicit rejection: a wrong-key ciphertext yields a
+ // pseudorandom shared secret without an error here; authentication is
+ // enforced by AES-GCM at the wrap layer.
+ mlkemSecret, err := h.mlkemAdapter().decapsulate(mlkemPrivBytes, mlkemCtBytes)
+ if err != nil {
+ return nil, err
+ }
+
+ combinedSecret := make([]byte, 0, len(ecdhSecret)+len(mlkemSecret))
+ combinedSecret = append(combinedSecret, ecdhSecret...)
+ combinedSecret = append(combinedSecret, mlkemSecret...)
+
+ return combinedSecret, nil
+}
+
+func (h nistHybridKEM) publicKeyPEM(pub []byte) (string, error) {
+ return rawToPEM(h.params.pubPEMBlock, pub, h.pubSize())
+}
+
+// wrapKey derives a 32-byte AES key from the concatenated EC+ML-KEM shared
+// secret via HKDF-SHA256 over (salt, info). The KDF here is load-bearing: it
+// is the combiner that binds the two halves of the hybrid into a single
+// uniformly-random wrap key.
+func (nistHybridKEM) wrapKey(sharedSecret, salt, info []byte) ([]byte, error) {
+ return hkdfWrapKey(sharedSecret, salt, info)
+}
+
+// --- 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
+}
+
+// hkdfWrapKey derives the AES-256 wrap key used by the hybrid PQ/T KEM
+// schemes (X-Wing, NIST EC + ML-KEM). Pure ML-KEM uses the shared secret
+// directly and does not call this helper.
+func hkdfWrapKey(sharedSecret, salt, info []byte) ([]byte, error) {
+ if len(salt) == 0 {
+ salt = defaultTDFSalt()
+ }
+ hkdfObj := hkdf.New(sha256.New, sharedSecret, salt, info)
+ derivedKey := make([]byte, kemWrapKeySize)
+ if _, err := io.ReadFull(hkdfObj, derivedKey); err != nil {
+ return nil, fmt.Errorf("hkdf failure: %w", err)
+ }
+ return derivedKey, 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) {
+ if 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)
+}
diff --git a/lib/ocrypto/mlkem.go b/lib/ocrypto/mlkem.go
new file mode 100644
index 0000000000..436815d059
--- /dev/null
+++ b/lib/ocrypto/mlkem.go
@@ -0,0 +1,213 @@
+package ocrypto
+
+import (
+ "bytes"
+ "encoding/asn1"
+ "encoding/pem"
+ "errors"
+ "fmt"
+)
+
+// PEM block types defined by RFC 7468 for SPKI / PKCS#8 envelopes.
+const (
+ pemBlockPublicKey = "PUBLIC KEY"
+ pemBlockPrivateKey = "PRIVATE KEY"
+)
+
+// 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
+}
+
+const bitsPerByte = 8
+
+// 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
+}
+
+// ParseMLKEMPublicSPKI returns the OID and raw encapsulation key bytes from an
+// SPKI DER blob if the algorithm is ML-KEM-768 or ML-KEM-1024.
+//
+// Deprecated: Use ParseKEMPublicSPKI and verify the returned OID against the
+// expected ML-KEM variant.
+func ParseMLKEMPublicSPKI(der []byte) (asn1.ObjectIdentifier, []byte, error) {
+ oid, raw, err := ParseKEMPublicSPKI(der)
+ if err != nil {
+ return nil, nil, err
+ }
+ if !oid.Equal(OidMLKEM768) && !oid.Equal(OidMLKEM1024) {
+ return nil, nil, errNotKEM
+ }
+ return oid, raw, 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
+}
+
+// normalizeMLKEMPublicKey detects the input format and returns raw key bytes.
+// Accepts: raw key (1184/1568 bytes), SPKI DER (1206/1590 bytes), or PEM-wrapped SPKI.
+func normalizeMLKEMPublicKey(input []byte, expectedRawSize int, expectedOID asn1.ObjectIdentifier) ([]byte, error) {
+ if len(input) == expectedRawSize {
+ return input, nil
+ }
+
+ if bytes.HasPrefix(input, []byte("-----BEGIN")) {
+ block, _ := pem.Decode(input)
+ if block == nil {
+ return nil, errors.New("failed to decode PEM block")
+ }
+ if block.Type != pemBlockPublicKey {
+ return nil, fmt.Errorf("expected %s PEM block, got %s", pemBlockPublicKey, block.Type)
+ }
+ input = block.Bytes
+ }
+
+ oid, rawKey, err := ParseMLKEMPublicSPKI(input)
+ if err != nil {
+ if errors.Is(err, errNotKEM) {
+ return nil, errors.New("not an ML-KEM key in SPKI format")
+ }
+ return nil, fmt.Errorf("failed to parse SPKI: %w", err)
+ }
+
+ if !oid.Equal(expectedOID) {
+ return nil, fmt.Errorf("OID mismatch: expected %v, got %v", expectedOID, oid)
+ }
+
+ if len(rawKey) != expectedRawSize {
+ return nil, fmt.Errorf("extracted key has wrong size: got %d want %d", len(rawKey), expectedRawSize)
+ }
+
+ return rawKey, nil
+}
+
+// MLKEM768WrapDEK encapsulates against an ML-KEM-768 public key (raw, SPKI
+// DER, or PEM) and returns the ASN.1 DER envelope carrying the KEM ciphertext
+// and AES-GCM-wrapped DEK. The ML-KEM Decaps shared secret is used directly
+// as the AES-256 wrap key (no HKDF); see adr/decisions/2026-06-16-mlkem-direct-key-wrap.md.
+//
+// Deprecated: Use WrapDEK with MLKEM768Key, or construct via FromPublicPEM.
+func MLKEM768WrapDEK(publicKey, dek []byte) ([]byte, error) {
+ rawKey, err := normalizeMLKEMPublicKey(publicKey, MLKEM768PublicKeySize, OidMLKEM768)
+ if err != nil {
+ return nil, fmt.Errorf("invalid ML-KEM-768 public key: %w", err)
+ }
+ return wrapDEKWithKEM(mlkemKEM{variant: mlkem768}, rawKey, dek, nil, nil)
+}
+
+// MLKEM768UnwrapDEK decapsulates the envelope produced by MLKEM768WrapDEK
+// using the supplied raw ML-KEM-768 seed. This is the binary-bytes counterpart
+// to FromPrivatePEM; callers that already hold a raw seed can use it directly
+// without re-encoding to PKCS#8 PEM.
+func MLKEM768UnwrapDEK(privateKeyRaw, wrappedDER []byte) ([]byte, error) {
+ return unwrapDEKWithKEM(mlkemKEM{variant: mlkem768}, privateKeyRaw, wrappedDER, nil, nil)
+}
+
+// MLKEM1024WrapDEK encapsulates against an ML-KEM-1024 public key (raw, SPKI
+// DER, or PEM) and returns the ASN.1 DER envelope carrying the KEM ciphertext
+// and AES-GCM-wrapped DEK. The ML-KEM Decaps shared secret is used directly
+// as the AES-256 wrap key (no HKDF); see adr/decisions/2026-06-16-mlkem-direct-key-wrap.md.
+//
+// Deprecated: Use WrapDEK with MLKEM1024Key, or construct via FromPublicPEM.
+func MLKEM1024WrapDEK(publicKey, dek []byte) ([]byte, error) {
+ rawKey, err := normalizeMLKEMPublicKey(publicKey, MLKEM1024PublicKeySize, OidMLKEM1024)
+ if err != nil {
+ return nil, fmt.Errorf("invalid ML-KEM-1024 public key: %w", err)
+ }
+ return wrapDEKWithKEM(mlkemKEM{variant: mlkem1024}, rawKey, dek, nil, nil)
+}
+
+// MLKEM1024UnwrapDEK decapsulates the envelope produced by MLKEM1024WrapDEK
+// using the supplied raw ML-KEM-1024 seed. This is the binary-bytes counterpart
+// to FromPrivatePEM; callers that already hold a raw seed can use it directly
+// without re-encoding to PKCS#8 PEM.
+func MLKEM1024UnwrapDEK(privateKeyRaw, wrappedDER []byte) ([]byte, error) {
+ return unwrapDEKWithKEM(mlkemKEM{variant: mlkem1024}, privateKeyRaw, wrappedDER, nil, nil)
+}
diff --git a/lib/ocrypto/mlkem_format_test.go b/lib/ocrypto/mlkem_format_test.go
new file mode 100644
index 0000000000..0e954eee87
--- /dev/null
+++ b/lib/ocrypto/mlkem_format_test.go
@@ -0,0 +1,124 @@
+package ocrypto
+
+import (
+ "encoding/pem"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+// TestMLKEM768WrapDEKFormats verifies that MLKEM768WrapDEK accepts raw, SPKI DER, and PEM formats
+func TestMLKEM768WrapDEKFormats(t *testing.T) {
+ keyPair, err := NewMLKEMKeyPair()
+ require.NoError(t, err)
+
+ dek := []byte("0123456789abcdef0123456789abcdef")
+
+ // Test 1: Raw key (1184 bytes)
+ rawKey := keyPair.PrivateKey.EncapsulationKey().Bytes()
+ require.Len(t, rawKey, MLKEM768PublicKeySize)
+
+ wrappedFromRaw, err := MLKEM768WrapDEK(rawKey, dek)
+ require.NoError(t, err, "Should accept raw key")
+
+ // Test 2: SPKI DER (1206 bytes)
+ spkiDER, err := marshalKEMPublicSPKI(OidMLKEM768, rawKey)
+ require.NoError(t, err)
+ require.Greater(t, len(spkiDER), len(rawKey), "SPKI DER should be larger than raw key")
+
+ wrappedFromSPKI, err := MLKEM768WrapDEK(spkiDER, dek)
+ require.NoError(t, err, "Should accept SPKI DER")
+
+ // Test 3: PEM-wrapped SPKI (~1686 bytes)
+ pemBytes := pem.EncodeToMemory(&pem.Block{Type: pemBlockPublicKey, Bytes: spkiDER})
+ require.Greater(t, len(pemBytes), len(spkiDER), "PEM should be larger than DER")
+
+ wrappedFromPEM, err := MLKEM768WrapDEK(pemBytes, dek)
+ require.NoError(t, err, "Should accept PEM-wrapped SPKI")
+
+ // Verify we can unwrap all three (ML-KEM uses randomness, so wrapped results differ each time)
+ privateKeyBytes := keyPair.PrivateKey.Bytes()
+
+ plaintext1, err := MLKEM768UnwrapDEK(privateKeyBytes, wrappedFromRaw)
+ require.NoError(t, err, "Should unwrap from raw key wrapping")
+ assert.Equal(t, dek, plaintext1)
+
+ plaintext2, err := MLKEM768UnwrapDEK(privateKeyBytes, wrappedFromSPKI)
+ require.NoError(t, err, "Should unwrap from SPKI DER wrapping")
+ assert.Equal(t, dek, plaintext2)
+
+ plaintext3, err := MLKEM768UnwrapDEK(privateKeyBytes, wrappedFromPEM)
+ require.NoError(t, err, "Should unwrap from PEM wrapping")
+ assert.Equal(t, dek, plaintext3)
+}
+
+// TestMLKEM1024WrapDEKFormats verifies that MLKEM1024WrapDEK accepts raw, SPKI DER, and PEM formats
+func TestMLKEM1024WrapDEKFormats(t *testing.T) {
+ keyPair, err := NewMLKEM1024KeyPair()
+ require.NoError(t, err)
+
+ dek := []byte("0123456789abcdef0123456789abcdef")
+
+ // Test 1: Raw key (1568 bytes)
+ rawKey := keyPair.PrivateKey.EncapsulationKey().Bytes()
+ require.Len(t, rawKey, MLKEM1024PublicKeySize)
+
+ wrappedFromRaw, err := MLKEM1024WrapDEK(rawKey, dek)
+ require.NoError(t, err, "Should accept raw key")
+
+ // Test 2: SPKI DER (1590 bytes)
+ spkiDER, err := marshalKEMPublicSPKI(OidMLKEM1024, rawKey)
+ require.NoError(t, err)
+ require.Greater(t, len(spkiDER), len(rawKey), "SPKI DER should be larger than raw key")
+
+ wrappedFromSPKI, err := MLKEM1024WrapDEK(spkiDER, dek)
+ require.NoError(t, err, "Should accept SPKI DER")
+
+ // Test 3: PEM-wrapped SPKI (~2206 bytes)
+ pemBytes := pem.EncodeToMemory(&pem.Block{Type: pemBlockPublicKey, Bytes: spkiDER})
+ require.Greater(t, len(pemBytes), len(spkiDER), "PEM should be larger than DER")
+
+ wrappedFromPEM, err := MLKEM1024WrapDEK(pemBytes, dek)
+ require.NoError(t, err, "Should accept PEM-wrapped SPKI")
+
+ // Verify we can unwrap all three (ML-KEM uses randomness, so wrapped results differ each time)
+ privateKeyBytes := keyPair.PrivateKey.Bytes()
+
+ plaintext1, err := MLKEM1024UnwrapDEK(privateKeyBytes, wrappedFromRaw)
+ require.NoError(t, err, "Should unwrap from raw key wrapping")
+ assert.Equal(t, dek, plaintext1)
+
+ plaintext2, err := MLKEM1024UnwrapDEK(privateKeyBytes, wrappedFromSPKI)
+ require.NoError(t, err, "Should unwrap from SPKI DER wrapping")
+ assert.Equal(t, dek, plaintext2)
+
+ plaintext3, err := MLKEM1024UnwrapDEK(privateKeyBytes, wrappedFromPEM)
+ require.NoError(t, err, "Should unwrap from PEM wrapping")
+ assert.Equal(t, dek, plaintext3)
+}
+
+// TestMLKEM768WrapDEKInvalidFormats verifies error handling for invalid inputs
+func TestMLKEM768WrapDEKInvalidFormats(t *testing.T) {
+ dek := []byte("0123456789abcdef0123456789abcdef")
+
+ // Wrong size raw key
+ wrongSizeRaw := make([]byte, 100)
+ _, err := MLKEM768WrapDEK(wrongSizeRaw, dek)
+ require.Error(t, err, "Should reject wrong-size raw key")
+
+ // Wrong OID in SPKI
+ keyPair1024, err := NewMLKEM1024KeyPair()
+ require.NoError(t, err)
+ spki1024, err := marshalKEMPublicSPKI(OidMLKEM1024, keyPair1024.PrivateKey.EncapsulationKey().Bytes())
+ require.NoError(t, err)
+
+ _, err = MLKEM768WrapDEK(spki1024, dek)
+ require.Error(t, err, "Should reject ML-KEM-1024 SPKI when expecting ML-KEM-768")
+ assert.Contains(t, err.Error(), "OID mismatch")
+
+ // Invalid PEM
+ invalidPEM := []byte("-----BEGIN PUBLIC KEY-----\ninvalid base64\n-----END PUBLIC KEY-----")
+ _, err = MLKEM768WrapDEK(invalidPEM, dek)
+ require.Error(t, err, "Should reject invalid PEM")
+}
diff --git a/lib/ocrypto/mlkem_test.go b/lib/ocrypto/mlkem_test.go
new file mode 100644
index 0000000000..f70c245c58
--- /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 := MLKEM768WrapDEK(publicKeyBytes, dek)
+ require.NoError(t, err)
+
+ plaintext, err := MLKEM768UnwrapDEK(privateKeyBytes, wrapped)
+ 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 := MLKEM1024WrapDEK(publicKeyBytes, dek)
+ require.NoError(t, err)
+
+ plaintext, err := MLKEM1024UnwrapDEK(privateKeyBytes, wrapped)
+ 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 := MLKEM768WrapDEK(publicKey1, []byte("top secret dek"))
+ require.NoError(t, err)
+
+ _, err = MLKEM768UnwrapDEK(privateKey2, wrapped)
+ 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 := MLKEM1024WrapDEK(publicKey1, []byte("top secret dek"))
+ require.NoError(t, err)
+
+ _, err = MLKEM1024UnwrapDEK(privateKey2, wrapped)
+ 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 = MLKEM768UnwrapDEK(privateKeyBytes, der)
+ 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 = MLKEM1024UnwrapDEK(privateKeyBytes, der)
+ 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/rsa_key_pair.go b/lib/ocrypto/rsa_key_pair.go
index 914eb8f80c..5294e10c13 100644
--- a/lib/ocrypto/rsa_key_pair.go
+++ b/lib/ocrypto/rsa_key_pair.go
@@ -41,7 +41,7 @@ func (keyPair RsaKeyPair) PrivateKeyInPemFormat() (string, error) {
privateKeyPem := pem.EncodeToMemory(
&pem.Block{
- Type: "PRIVATE KEY",
+ Type: pemBlockPrivateKey,
Bytes: privateKeyBytes,
},
)
@@ -61,7 +61,7 @@ func (keyPair RsaKeyPair) PublicKeyInPemFormat() (string, error) {
publicKeyPem := pem.EncodeToMemory(
&pem.Block{
- Type: "PUBLIC KEY",
+ Type: pemBlockPublicKey,
Bytes: publicKeyBytes,
},
)
diff --git a/lib/ocrypto/xwing.go b/lib/ocrypto/xwing.go
index 1ea9d5ab25..ce8ac47c01 100644
--- a/lib/ocrypto/xwing.go
+++ b/lib/ocrypto/xwing.go
@@ -2,14 +2,9 @@ package ocrypto
import (
"crypto/rand"
- "crypto/sha256"
- "encoding/asn1"
- "encoding/pem"
"fmt"
- "io"
"github.com/cloudflare/circl/kem/xwing"
- "golang.org/x/crypto/hkdf"
)
const (
@@ -23,28 +18,11 @@ const (
PEMBlockXWingPrivateKey = "XWING PRIVATE KEY"
)
-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 {
@@ -82,179 +60,18 @@ func XWingPrivateKeyFromPem(data []byte) ([]byte, error) {
return decodeSizedPEMBlock(data, PEMBlockXWingPrivateKey, XWingPrivateKeySize)
}
-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)
- }
-
- return &XWingEncryptor{
- publicKey: append([]byte(nil), publicKey...),
- salt: cloneOrNil(salt),
- info: cloneOrNil(info),
- }, nil
-}
-
-func (e *XWingEncryptor) Encrypt(data []byte) ([]byte, error) {
- return xwingWrapDEK(e.publicKey, data, e.salt, e.info)
-}
-
-func (e *XWingEncryptor) PublicKeyInPemFormat() (string, error) {
- return rawToPEM(PEMBlockXWingPublicKey, e.publicKey, XWingPublicKeySize)
-}
-
-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)
-}
-
+// XWingWrapDEK encapsulates against an X-Wing public key and returns the
+// ASN.1 DER envelope carrying the KEM ciphertext and AES-GCM-wrapped DEK.
+//
+// Deprecated: Use WrapDEK with HybridXWingKey, or construct via FromPublicPEM.
func XWingWrapDEK(publicKeyRaw, dek []byte) ([]byte, error) {
- return xwingWrapDEK(publicKeyRaw, dek, defaultTDFSalt(), nil)
+ return wrapDEKWithKEM(xwingKEM{}, publicKeyRaw, dek, defaultTDFSalt(), nil)
}
+// XWingUnwrapDEK decapsulates the envelope produced by XWingWrapDEK using the
+// supplied raw X-Wing private key. This is the binary-bytes counterpart to
+// FromPrivatePEM (which works from PEM); callers that already hold raw key
+// material can use it directly without re-encoding to PEM.
func XWingUnwrapDEK(privateKeyRaw, wrappedDER []byte) ([]byte, error) {
- return xwingUnwrapDEK(privateKeyRaw, wrappedDER, defaultTDFSalt(), nil)
-}
-
-// XWingEncapsulate performs the X-Wing KEM encapsulation, returning the shared
-// secret and ciphertext without applying KDF or encryption.
-func XWingEncapsulate(publicKeyRaw []byte) ([]byte, []byte, error) {
- if len(publicKeyRaw) != XWingPublicKeySize {
- return nil, nil, fmt.Errorf("invalid X-Wing public key size: got %d want %d", len(publicKeyRaw), XWingPublicKeySize)
- }
-
- sharedSecret, ciphertext, err := xwing.Encapsulate(publicKeyRaw, nil)
- if err != nil {
- return nil, nil, fmt.Errorf("xwing.Encapsulate failed: %w", err)
- }
-
- 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()
- }
-
- hkdfObj := hkdf.New(sha256.New, sharedSecret, salt, info)
- derivedKey := make([]byte, xwing.SharedKeySize)
- if _, err := io.ReadFull(hkdfObj, derivedKey); err != nil {
- return nil, fmt.Errorf("hkdf failure: %w", err)
- }
-
- return derivedKey, nil
-}
-
-func decodeSizedPEMBlock(data []byte, blockType string, expectedSize int) ([]byte, error) {
- block, _ := pem.Decode(data)
- if block == nil {
- return nil, fmt.Errorf("failed to parse PEM formatted %s", blockType)
- }
- if block.Type != blockType {
- return nil, fmt.Errorf("unexpected PEM block type: got %s want %s", block.Type, blockType)
- }
- if len(block.Bytes) != expectedSize {
- return nil, fmt.Errorf("invalid %s size: got %d want %d", blockType, len(block.Bytes), expectedSize)
- }
-
- return append([]byte(nil), block.Bytes...), nil
+ return unwrapDEKWithKEM(xwingKEM{}, privateKeyRaw, wrappedDER, defaultTDFSalt(), nil)
}
diff --git a/lib/ocrypto/xwing_test.go b/lib/ocrypto/xwing_test.go
index c0bf783ba9..1e363c93fc 100644
--- a/lib/ocrypto/xwing_test.go
+++ b/lib/ocrypto/xwing_test.go
@@ -60,16 +60,16 @@ func TestXWingWrapUnwrapWrongKeyFails(t *testing.T) {
assert.Contains(t, err.Error(), "AES-GCM decrypt failed")
}
-func TestXWingWrappedKeyASN1RoundTrip(t *testing.T) {
- original := XWingWrappedKey{
- XWingCiphertext: []byte("ciphertext"),
- EncryptedDEK: []byte("encrypted-dek"),
+func TestXWingEnvelopeASN1RoundTrip(t *testing.T) {
+ original := kemEnvelope{
+ KEMCiphertext: []byte("ciphertext"),
+ EncryptedDEK: []byte("encrypted-dek"),
}
der, err := asn1.Marshal(original)
require.NoError(t, err)
- var decoded XWingWrappedKey
+ var decoded kemEnvelope
rest, err := asn1.Unmarshal(der, &decoded)
require.NoError(t, err)
assert.Empty(t, rest)
@@ -91,23 +91,18 @@ func TestXWingPEMDispatch(t *testing.T) {
decryptor, err := FromPrivatePEMWithSalt(privatePEM, []byte("salt"), []byte("info"))
require.NoError(t, err)
- xwingEncryptor, ok := encryptor.(*XWingEncryptor)
- require.True(t, ok)
- assert.Equal(t, Hybrid, xwingEncryptor.Type())
- assert.Equal(t, HybridXWingKey, xwingEncryptor.KeyType())
- assert.Nil(t, xwingEncryptor.EphemeralKey())
+ assert.Equal(t, Hybrid, encryptor.Type())
+ assert.Equal(t, HybridXWingKey, encryptor.KeyType())
+ assert.Nil(t, encryptor.EphemeralKey())
- metadata, err := xwingEncryptor.Metadata()
+ metadata, err := encryptor.Metadata()
require.NoError(t, err)
assert.Empty(t, metadata)
- xwingDecryptor, ok := decryptor.(*XWingDecryptor)
- require.True(t, ok)
-
- wrapped, err := xwingEncryptor.Encrypt([]byte("dispatch-dek"))
+ wrapped, err := encryptor.Encrypt([]byte("dispatch-dek"))
require.NoError(t, err)
- plaintext, err := xwingDecryptor.Decrypt(wrapped)
+ plaintext, err := decryptor.Decrypt(wrapped)
require.NoError(t, err)
assert.Equal(t, []byte("dispatch-dek"), plaintext)
}
@@ -116,14 +111,14 @@ func TestXWingEncapsulate(t *testing.T) {
keyPair, err := NewXWingKeyPair()
require.NoError(t, err)
- sharedSecret, ciphertext, err := XWingEncapsulate(keyPair.publicKey)
+ sharedSecret, ciphertext, err := xwingKEM{}.encapsulate(keyPair.publicKey)
require.NoError(t, err)
assert.Len(t, sharedSecret, 32)
assert.Len(t, ciphertext, XWingCiphertextSize)
}
func TestXWingEncapsulateInvalidKeySize(t *testing.T) {
- _, _, err := XWingEncapsulate([]byte("too-short"))
+ _, _, err := xwingKEM{}.encapsulate([]byte("too-short"))
require.Error(t, err)
- assert.Contains(t, err.Error(), "invalid X-Wing public key size")
+ assert.Contains(t, err.Error(), "X-Wing public key size")
}
diff --git a/otdfctl/cmd/policy/kasKeys.go b/otdfctl/cmd/policy/kasKeys.go
index e811486284..fab10c03e6 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..166f14dd93 100644
--- a/otdfctl/docs/man/policy/kas-registry/key/create.md
+++ b/otdfctl/docs/man/policy/kas-registry/key/create.md
@@ -75,6 +75,8 @@ otdfctl policy kas-registry key create --key-id "aws-key" --algorithm "rsa:2048"
| `ec:secp256r1` |
| `ec:secp384r1` |
| `ec:secp521r1` |
+ | `mlkem:768` |
+ | `mlkem:1024` |
| `hpqt:xwing` |
| `hpqt:secp256r1-mlkem768` |
| `hpqt:secp384r1-mlkem1024` |
diff --git a/otdfctl/docs/man/policy/kas-registry/key/import.md b/otdfctl/docs/man/policy/kas-registry/key/import.md
index b08a2ea843..1c209271f6 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` |
+ | `mlkem:768` |
+ | `mlkem:1024` |
| `hpqt:xwing` |
| `hpqt:secp256r1-mlkem768` |
| `hpqt:secp384r1-mlkem1024` |
diff --git a/otdfctl/docs/man/policy/kas-registry/key/rotate.md b/otdfctl/docs/man/policy/kas-registry/key/rotate.md
index 726d85f74b..29a94bf53e 100644
--- a/otdfctl/docs/man/policy/kas-registry/key/rotate.md
+++ b/otdfctl/docs/man/policy/kas-registry/key/rotate.md
@@ -88,6 +88,8 @@ otdfctl policy kas-registry key rotate --key "public-key-old" --kas "Secondary K
| `ec:secp256r1` |
| `ec:secp384r1` |
| `ec:secp521r1` |
+ | `mlkem:768` |
+ | `mlkem:1024` |
| `hpqt:xwing` |
| `hpqt:secp256r1-mlkem768` |
| `hpqt:secp384r1-mlkem1024` |
diff --git a/otdfctl/pkg/cli/sdkHelpers.go b/otdfctl/pkg/cli/sdkHelpers.go
index 943fbbc71e..941e406b7e 100644
--- a/otdfctl/pkg/cli/sdkHelpers.go
+++ b/otdfctl/pkg/cli/sdkHelpers.go
@@ -131,6 +131,10 @@ func KeyAlgToEnum(alg string) (policy.Algorithm, error) {
return policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768, nil
case "hpqt:secp384r1-mlkem1024":
return policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024, 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")
}
@@ -154,6 +158,10 @@ func KeyEnumToAlg(enum policy.Algorithm) (string, error) {
return "hpqt:secp256r1-mlkem768", nil
case policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024:
return "hpqt:secp384r1-mlkem1024", 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..558af3cd55 100644
--- a/otdfctl/pkg/utils/pemvalidate.go
+++ b/otdfctl/pkg/utils/pemvalidate.go
@@ -53,6 +53,14 @@ 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_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 1e386a7531..92175c8323 100644
--- a/protocol/go/policy/objects.pb.go
+++ b/protocol/go/policy/objects.pb.go
@@ -246,6 +246,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.
@@ -260,6 +262,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,
@@ -271,6 +275,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,
}
)
@@ -314,20 +320,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,
@@ -339,6 +349,8 @@ var (
"ALGORITHM_HPQT_XWING": 6,
"ALGORITHM_HPQT_SECP256R1_MLKEM768": 7,
"ALGORITHM_HPQT_SECP384R1_MLKEM1024": 8,
+ "ALGORITHM_MLKEM_768": 20,
+ "ALGORITHM_MLKEM_1024": 21,
}
)
@@ -3760,7 +3772,7 @@ var file_policy_objects_proto_rawDesc = []byte{
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, 0x03, 0x0a, 0x13, 0x4b, 0x61, 0x73, 0x50, 0x75,
+ 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, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43,
@@ -3786,47 +3798,55 @@ var file_policy_objects_proto_rawDesc = []byte{
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,
+ 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/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/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 a33ce486f7..0a8e8d382b 100644
--- a/service/internal/security/basic_manager.go
+++ b/service/internal/security/basic_manager.go
@@ -82,17 +82,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,65 +103,21 @@ 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:
- if len(ephemeralPublicKey) > 0 {
- return nil, errors.New("ephemeral public key should not be provided for X-Wing decryption")
- }
- xwingPrivKey, err := ocrypto.XWingPrivateKeyFromPem(privKey)
- if err != nil {
- return nil, fmt.Errorf("failed to create X-Wing private key from PEM: %w", err)
- }
- plaintext, err := ocrypto.XWingUnwrapDEK(xwingPrivKey, ciphertext)
- if err != nil {
- return nil, fmt.Errorf("failed to decrypt with X-Wing: %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.HybridSecp256r1MLKEM768Key:
- if len(ephemeralPublicKey) > 0 {
- return nil, errors.New("ephemeral public key should not be provided for hybrid decryption")
- }
- privKeyBytes, err := ocrypto.P256MLKEM768PrivateKeyFromPem(privKey)
- if err != nil {
- return nil, fmt.Errorf("failed to parse P256-MLKEM768 private key from PEM: %w", err)
- }
- plaintext, err := ocrypto.P256MLKEM768UnwrapDEK(privKeyBytes, ciphertext)
- if err != nil {
- return nil, fmt.Errorf("failed to decrypt with P256-MLKEM768: %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.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")
- }
- privKeyBytes, err := ocrypto.P384MLKEM1024PrivateKeyFromPem(privKey)
- if err != nil {
- return nil, fmt.Errorf("failed to parse P384-MLKEM1024 private key from PEM: %w", err)
+ return nil, fmt.Errorf("ephemeral public key should not be provided for %s decryption", alg)
}
- plaintext, err := ocrypto.P384MLKEM1024UnwrapDEK(privKeyBytes, ciphertext)
- if err != nil {
- return nil, fmt.Errorf("failed to decrypt with P384-MLKEM1024: %w", err)
- }
- protectedKey, err := ocrypto.NewAESProtectedKey(plaintext)
+ plaintext, err := decrypter.Decrypt(ciphertext)
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 59953a8523..95c2efce28 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
@@ -120,7 +118,8 @@ func loadKeys(ks []KeyPairInfo) (*StandardCrypto, error) {
keysByAlg := make(map[string]keylist)
keysByID := make(keylist)
for _, k := range ks {
- slog.Info("crypto cfg loading",
+ slog.Info(
+ "crypto cfg loading",
slog.Any("id", k.KID),
slog.Any("alg", k.Algorithm),
)
@@ -162,17 +161,18 @@ func loadKey(k KeyPairInfo) (any, error) {
ecPrivateKeyPem: string(privatePEM),
ecCertificatePEM: string(certPEM),
}, nil
- case AlgorithmHPQTXWing:
- return StandardXWingCrypto{
- KeyPairInfo: k,
- xwingPrivateKeyPem: string(privatePEM),
- xwingPublicKeyPem: string(certPEM),
- }, nil
- case AlgorithmHPQTSecp256r1MLKEM768, AlgorithmHPQTSecp384r1MLKEM1024:
- return StandardHybridCrypto{
- KeyPairInfo: k,
- hybridPrivateKeyPem: string(privatePEM),
- hybridPublicKeyPem: string(certPEM),
+ case AlgorithmHPQTXWing,
+ AlgorithmHPQTSecp256r1MLKEM768, AlgorithmHPQTSecp384r1MLKEM1024,
+ AlgorithmMLKEM768, AlgorithmMLKEM1024:
+ decryptor, err := ocrypto.FromPrivatePEM(string(privatePEM))
+ if err != nil {
+ return nil, fmt.Errorf("ocrypto.FromPrivatePEM (%s) failed: %w", k.Algorithm, err)
+ }
+ return StandardKEMCrypto{
+ KeyPairInfo: k,
+ privateKeyPem: string(privatePEM),
+ publicKeyPem: string(certPEM),
+ decryptor: decryptor,
}, nil
case AlgorithmRSA2048, AlgorithmRSA4096:
asymDecryption, err := ocrypto.NewAsymDecryption(string(privatePEM))
@@ -247,7 +247,8 @@ func loadDeprecatedKeys(rsaKeys map[string]StandardKeyInfo, ecKeys map[string]St
keysByID[id] = k
}
for id, kasInfo := range ecKeys {
- slog.Info("cfg.ECKeys",
+ slog.Info(
+ "cfg.ECKeys",
slog.String("id", id),
slog.Any("kasInfo", kasInfo),
)
@@ -353,40 +354,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)
- }
- xw, ok := k.(StandardXWingCrypto)
- if !ok {
- return "", fmt.Errorf("key with id [%s] is not an X-Wing key: %w", kid, ErrCertNotFound)
+ return "", fmt.Errorf("no key with id [%s]: %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]
+ kem, ok := k.(StandardKEMCrypto)
if !ok {
- return "", fmt.Errorf("no hybrid key with id [%s]: %w", kid, ErrCertNotFound)
+ return "", fmt.Errorf("key with id [%s] is not a KEM key: %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) {
@@ -499,47 +481,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)
}
- privateKey, err := ocrypto.XWingPrivateKeyFromPem([]byte(key.xwingPrivateKeyPem))
+ rawKey, err = key.decryptor.Decrypt(ciphertext)
if err != nil {
- return nil, fmt.Errorf("failed to parse X-Wing private key: %w", err)
- }
-
- rawKey, err = ocrypto.XWingUnwrapDEK(privateKey, 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")
- }
-
- switch key.Algorithm {
- case AlgorithmHPQTSecp256r1MLKEM768:
- privateKey, err := ocrypto.P256MLKEM768PrivateKeyFromPem([]byte(key.hybridPrivateKeyPem))
- if err != nil {
- return nil, fmt.Errorf("failed to parse P256-MLKEM768 private key: %w", err)
- }
- rawKey, err = ocrypto.P256MLKEM768UnwrapDEK(privateKey, ciphertext)
- if err != nil {
- return nil, fmt.Errorf("failed to decrypt with P256-MLKEM768: %w", err)
- }
- case AlgorithmHPQTSecp384r1MLKEM1024:
- privateKey, err := ocrypto.P384MLKEM1024PrivateKeyFromPem([]byte(key.hybridPrivateKeyPem))
- if err != nil {
- return nil, fmt.Errorf("failed to parse P384-MLKEM1024 private key: %w", err)
- }
- rawKey, err = ocrypto.P384MLKEM1024UnwrapDEK(privateKey, ciphertext)
- if err != nil {
- return nil, fmt.Errorf("failed to decrypt with P384-MLKEM1024: %w", err)
- }
- default:
- return nil, fmt.Errorf("unsupported hybrid algorithm [%s]", key.Algorithm)
+ 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/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 aba7ffa84e..c5e18b34b6 100644
--- a/service/kas/access/rewrap.go
+++ b/service/kas/access/rewrap.go
@@ -160,7 +160,8 @@ func (p *Provider) parseSRT(ctx context.Context, srt string) (jwt.Token, string,
"unable to validate or parse token",
slog.Any("error", err),
slog.Int("srt_length", len(srt)),
- jwkThumbprintAttr(ctxAuth.GetJWKFromContext(ctx, p.Logger)))
+ jwkThumbprintAttr(ctxAuth.GetJWKFromContext(ctx, p.Logger)),
+ )
return nil, "", err401("could not parse token")
}
@@ -187,7 +188,8 @@ func (p *Provider) logSRTValidationFailure(ctx context.Context, token jwt.Token,
issuedAt := token.IssuedAt()
if !issuedAt.IsZero() {
- fields = append(fields,
+ fields = append(
+ fields,
slog.Time("iat", issuedAt),
slog.Duration("iat_delta", issuedAt.Sub(now)),
)
@@ -198,7 +200,8 @@ func (p *Provider) logSRTValidationFailure(ctx context.Context, token jwt.Token,
expires := token.Expiration()
if !expires.IsZero() {
- fields = append(fields,
+ fields = append(
+ fields,
slog.Time("exp", expires),
slog.Duration("exp_delta", now.Sub(expires)),
)
@@ -209,7 +212,8 @@ func (p *Provider) logSRTValidationFailure(ctx context.Context, token jwt.Token,
notBefore := token.NotBefore()
if !notBefore.IsZero() {
- fields = append(fields,
+ fields = append(
+ fields,
slog.Time("nbf", notBefore),
slog.Duration("nbf_delta", notBefore.Sub(now)),
)
@@ -261,7 +265,8 @@ func (p *Provider) verifySRTSignature(ctx context.Context, srt string, dpopJWK j
)
if err != nil {
if p.Logger != nil {
- p.Logger.WarnContext(ctx,
+ p.Logger.WarnContext(
+ ctx,
"unable to verify request token",
slog.Int("srt_length", len(srt)),
jwkThumbprintAttr(dpopJWK),
@@ -370,7 +375,8 @@ func (p *Provider) extractSRTBody(ctx context.Context, headers http.Header, in *
err := protojson.UnmarshalOptions{DiscardUnknown: true}.Unmarshal([]byte(rbString), &requestBody)
// if there are no requests then it could be a v1 request
if err != nil {
- p.Logger.WarnContext(ctx,
+ p.Logger.WarnContext(
+ ctx,
"invalid SRT",
slog.Any("err_v2", err),
slog.Int("rb_string_length", len(rbString)),
@@ -382,7 +388,8 @@ func (p *Provider) extractSRTBody(ctx context.Context, headers http.Header, in *
var errv1 error
if requestBody, errv1 = extractAndConvertV1SRTBody([]byte(rbString)); errv1 != nil {
- p.Logger.WarnContext(ctx,
+ p.Logger.WarnContext(
+ ctx,
"invalid SRT",
slog.Any("err_v1", errv1),
slog.Int("rb_string_length", len(rbString)),
@@ -393,7 +400,8 @@ func (p *Provider) extractSRTBody(ctx context.Context, headers http.Header, in *
isV1 = true
}
// TODO: this log is too big and should be reconsidered or removed
- p.Logger.DebugContext(ctx,
+ p.Logger.DebugContext(
+ ctx,
"extracted request body",
slog.String("rewrap_body", requestBody.String()),
slog.String("rewrap_srt", rbString),
@@ -594,7 +602,8 @@ func (p *Provider) Rewrap(ctx context.Context, req *connect.Request[kaspb.Rewrap
}
kaoResults := *getMapValue(results)
if len(kaoResults) != 1 {
- p.Logger.WarnContext(ctx,
+ p.Logger.WarnContext(
+ ctx,
"status 400 due to wrong result set size",
slog.Any("kao_results", kaoResults),
slog.Any("results", results),
@@ -681,7 +690,8 @@ func (p *Provider) verifyRewrapRequests(ctx context.Context, req *kaspb.Unsigned
// Get EC key size and convert to mode
keySize, err := ocrypto.GetECKeySize([]byte(ephemeralPubKeyPEM))
if err != nil {
- p.Logger.WarnContext(ctx,
+ p.Logger.WarnContext(
+ ctx,
"failed to get EC key size",
slog.Any("kao", kao),
slog.Any("error", err),
@@ -692,7 +702,8 @@ func (p *Provider) verifyRewrapRequests(ctx context.Context, req *kaspb.Unsigned
mode, err := ocrypto.ECSizeToMode(keySize)
if err != nil {
- p.Logger.WarnContext(ctx,
+ p.Logger.WarnContext(
+ ctx,
"failed to convert key size to mode",
slog.Any("kao", kao),
slog.Any("error", err),
@@ -704,7 +715,8 @@ func (p *Provider) verifyRewrapRequests(ctx context.Context, req *kaspb.Unsigned
// Parse the PEM public key
block, _ := pem.Decode([]byte(ephemeralPubKeyPEM))
if block == nil {
- p.Logger.WarnContext(ctx,
+ p.Logger.WarnContext(
+ ctx,
"failed to decode PEM block",
slog.Any("kao", kao),
slog.Any("error", err),
@@ -715,7 +727,8 @@ func (p *Provider) verifyRewrapRequests(ctx context.Context, req *kaspb.Unsigned
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
- p.Logger.WarnContext(ctx,
+ p.Logger.WarnContext(
+ ctx,
"failed to parse public key",
slog.Any("kao", kao),
slog.Any("error", err),
@@ -760,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.HybridTDFEnabled && !p.Preview.HybridTDFEnabled {
+ 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() != "" {
@@ -898,7 +925,8 @@ func (p *Provider) tdf3Rewrap(ctx context.Context, requests []*kaspb.UnsignedRew
// Store per-KAO results even on error so tamper signals (e.g. corrupted
// policy body → generic "bad request") reach the SDK rather than being
// replaced by a top-level "invalid request".
- p.Logger.WarnContext(ctx,
+ p.Logger.WarnContext(
+ ctx,
"rewrap: verifyRewrapRequests failed",
slog.String("policy_id", policyID),
slog.Any("error", err),
@@ -916,7 +944,8 @@ func (p *Provider) tdf3Rewrap(ctx context.Context, requests []*kaspb.UnsignedRew
pdpAccessResults, accessErr := p.canAccess(ctx, tok, policies, additionalRewrapContext.Obligations.FulfillableFQNs)
if accessErr != nil {
- p.Logger.DebugContext(ctx,
+ p.Logger.DebugContext(
+ ctx,
"tdf3rewrap: cannot access policy",
slog.Any("policies", policies),
slog.Any("error", accessErr),
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 2bf66902ae..3ad41ad7db 100644
--- a/service/policy/objects.proto
+++ b/service/policy/objects.proto
@@ -399,6 +399,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
@@ -572,6 +574,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
+}