diff --git a/.github/scripts/init-temp-keys.sh b/.github/scripts/init-temp-keys.sh
index 4bb94ea76b..e9227c74d8 100755
--- a/.github/scripts/init-temp-keys.sh
+++ b/.github/scripts/init-temp-keys.sh
@@ -50,6 +50,9 @@ openssl rsa -in "$opt_output/kas-private.pem" -pubout -out "$opt_output/kas-cert
openssl ecparam -name prime256v1 >ecparams.tmp
openssl req -x509 -nodes -newkey ec:ecparams.tmp -subj "/CN=kas" -keyout "$opt_output/kas-ec-private.pem" -out "$opt_output/kas-ec-cert.pem" -days 365
+# Generate hybrid post-quantum key pairs (X-Wing, P256+ML-KEM-768, P384+ML-KEM-1024)
+go run ./service/cmd/keygen -output "$opt_output"
+
mkdir -p keys
openssl req -x509 -nodes -newkey RSA:2048 -subj "/CN=ca" -keyout keys/keycloak-ca-private.pem -out keys/keycloak-ca.pem -days 365
printf "subjectAltName=DNS:localhost,IP:127.0.0.1" >keys/sanX509.conf
diff --git a/docs/grpc/index.html b/docs/grpc/index.html
index 5d2dd2888a..b552502d7b 100644
--- a/docs/grpc/index.html
+++ b/docs/grpc/index.html
@@ -4027,6 +4027,24 @@
Algorithm
|
+
+ | ALGORITHM_HPQT_XWING |
+ 6 |
+ |
+
+
+
+ | ALGORITHM_HPQT_SECP256R1_MLKEM768 |
+ 7 |
+ |
+
+
+
+ | ALGORITHM_HPQT_SECP384R1_MLKEM1024 |
+ 8 |
+ |
+
+
@@ -4138,6 +4156,24 @@ 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 |
+ |
+
+
@@ -6276,7 +6312,7 @@ KeyAccess
|
Type of key wrapping used for the data encryption key
Required: Always
-Values: 'wrapped' (RSA-wrapped for ZTDF), 'ec-wrapped' (experimental ECDH-wrapped) |
+Values: 'wrapped' (RSA-wrapped for ZTDF), 'ec-wrapped' (experimental ECDH-wrapped), 'hybrid-wrapped' (experimental X-Wing-wrapped)
@@ -6333,7 +6369,7 @@ KeyAccess
|
Ephemeral public key for ECDH key derivation (ec-wrapped type only)
Required: When key_type="ec-wrapped" (experimental ECDH-based ZTDF)
-Omitted: When key_type="wrapped" (RSA-based ZTDF)
+Omitted: When key_type="wrapped" or key_type="hybrid-wrapped"
Should be a PEM-encoded PKCS#8 (ASN.1) formatted public key
Used to derive the symmetric key for unwrapping the DEK |
@@ -6661,7 +6697,7 @@ RewrapResponse
|
KAS's ephemeral session public key in PEM format
Required: For EC-based operations (key_type="ec-wrapped")
-Optional: Empty for RSA-based ZTDF (key_type="wrapped")
+Optional: Empty for RSA-based or X-Wing-based ZTDF (key_type="wrapped" or key_type="hybrid-wrapped")
Used by client to perform ECDH key agreement and decrypt the kas_wrapped_key values |
diff --git a/docs/openapi/authorization/authorization.openapi.yaml b/docs/openapi/authorization/authorization.openapi.yaml
index 1938f339fe..16dafb6cfd 100644
--- a/docs/openapi/authorization/authorization.openapi.yaml
+++ b/docs/openapi/authorization/authorization.openapi.yaml
@@ -341,6 +341,9 @@ components:
- ALGORITHM_EC_P256
- ALGORITHM_EC_P384
- ALGORITHM_EC_P521
+ - ALGORITHM_HPQT_XWING
+ - ALGORITHM_HPQT_SECP256R1_MLKEM768
+ - ALGORITHM_HPQT_SECP384R1_MLKEM1024
description: Supported key algorithms.
policy.KasPublicKeyAlgEnum:
type: string
@@ -352,6 +355,9 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
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 0f4f92d55f..7e9d837275 100644
--- a/docs/openapi/authorization/v2/authorization.openapi.yaml
+++ b/docs/openapi/authorization/v2/authorization.openapi.yaml
@@ -175,6 +175,9 @@ components:
- ALGORITHM_EC_P256
- ALGORITHM_EC_P384
- ALGORITHM_EC_P521
+ - ALGORITHM_HPQT_XWING
+ - ALGORITHM_HPQT_SECP256R1_MLKEM768
+ - ALGORITHM_HPQT_SECP384R1_MLKEM1024
description: Supported key algorithms.
policy.KasPublicKeyAlgEnum:
type: string
@@ -186,6 +189,9 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
policy.SourceType:
type: string
title: SourceType
diff --git a/docs/openapi/kas/kas.openapi.yaml b/docs/openapi/kas/kas.openapi.yaml
index b9e18aa899..26c48e22ae 100644
--- a/docs/openapi/kas/kas.openapi.yaml
+++ b/docs/openapi/kas/kas.openapi.yaml
@@ -214,7 +214,7 @@ components:
description: |-
Type of key wrapping used for the data encryption key
Required: Always
- Values: 'wrapped' (RSA-wrapped for ZTDF), 'ec-wrapped' (experimental ECDH-wrapped)
+ Values: 'wrapped' (RSA-wrapped for ZTDF), 'ec-wrapped' (experimental ECDH-wrapped), 'hybrid-wrapped' (experimental X-Wing-wrapped)
url:
type: string
title: kas_url
@@ -261,7 +261,7 @@ components:
description: |-
Ephemeral public key for ECDH key derivation (ec-wrapped type only)
Required: When key_type="ec-wrapped" (experimental ECDH-based ZTDF)
- Omitted: When key_type="wrapped" (RSA-based ZTDF)
+ Omitted: When key_type="wrapped" or key_type="hybrid-wrapped"
Should be a PEM-encoded PKCS#8 (ASN.1) formatted public key
Used to derive the symmetric key for unwrapping the DEK
title: KeyAccess
@@ -451,7 +451,7 @@ components:
description: |-
KAS's ephemeral session public key in PEM format
Required: For EC-based operations (key_type="ec-wrapped")
- Optional: Empty for RSA-based ZTDF (key_type="wrapped")
+ Optional: Empty for RSA-based or X-Wing-based ZTDF (key_type="wrapped" or key_type="hybrid-wrapped")
Used by client to perform ECDH key agreement and decrypt the kas_wrapped_key values
schemaVersion:
type: string
diff --git a/docs/openapi/policy/actions/actions.openapi.yaml b/docs/openapi/policy/actions/actions.openapi.yaml
index ec633192ae..ca0f755485 100644
--- a/docs/openapi/policy/actions/actions.openapi.yaml
+++ b/docs/openapi/policy/actions/actions.openapi.yaml
@@ -203,6 +203,9 @@ components:
- ALGORITHM_EC_P256
- ALGORITHM_EC_P384
- ALGORITHM_EC_P521
+ - ALGORITHM_HPQT_XWING
+ - ALGORITHM_HPQT_SECP256R1_MLKEM768
+ - ALGORITHM_HPQT_SECP384R1_MLKEM1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -229,6 +232,9 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
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 4ace6604af..0c24167f65 100644
--- a/docs/openapi/policy/attributes/attributes.openapi.yaml
+++ b/docs/openapi/policy/attributes/attributes.openapi.yaml
@@ -724,6 +724,9 @@ components:
- ALGORITHM_EC_P256
- ALGORITHM_EC_P384
- ALGORITHM_EC_P521
+ - ALGORITHM_HPQT_XWING
+ - ALGORITHM_HPQT_SECP256R1_MLKEM768
+ - ALGORITHM_HPQT_SECP384R1_MLKEM1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -750,6 +753,9 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
policy.SourceType:
type: string
title: SourceType
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 9cdc346918..da2be2ceaa 100644
--- a/docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml
+++ b/docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml
@@ -534,6 +534,9 @@ components:
- ALGORITHM_EC_P256
- ALGORITHM_EC_P384
- ALGORITHM_EC_P521
+ - ALGORITHM_HPQT_XWING
+ - ALGORITHM_HPQT_SECP256R1_MLKEM768
+ - ALGORITHM_HPQT_SECP384R1_MLKEM1024
description: Supported key algorithms.
policy.KasPublicKeyAlgEnum:
type: string
@@ -545,6 +548,9 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
policy.KeyMode:
type: string
title: KeyMode
@@ -1147,7 +1153,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]
+ this in [1, 2, 3, 4, 5, 6, 7, 8]
```
$ref: '#/components/schemas/policy.Algorithm'
@@ -1670,7 +1676,7 @@ components:
Filter keys by algorithm
The key_algorithm must be one of the defined values.:
```
- this in [0, 1, 2, 3, 4, 5]
+ this in [0, 1, 2, 3, 4, 5, 6, 7, 8]
```
$ref: '#/components/schemas/policy.Algorithm'
@@ -1932,7 +1938,7 @@ components:
Required
The key_algorithm must be one of the defined values.:
```
- this in [1, 2, 3, 4, 5]
+ this in [1, 2, 3, 4, 5, 6, 7, 8]
```
$ref: '#/components/schemas/policy.Algorithm'
diff --git a/docs/openapi/policy/namespaces/namespaces.openapi.yaml b/docs/openapi/policy/namespaces/namespaces.openapi.yaml
index 4a5b7e35cb..6c1e546db0 100644
--- a/docs/openapi/policy/namespaces/namespaces.openapi.yaml
+++ b/docs/openapi/policy/namespaces/namespaces.openapi.yaml
@@ -353,6 +353,9 @@ components:
- ALGORITHM_EC_P256
- ALGORITHM_EC_P384
- ALGORITHM_EC_P521
+ - ALGORITHM_HPQT_XWING
+ - ALGORITHM_HPQT_SECP256R1_MLKEM768
+ - ALGORITHM_HPQT_SECP384R1_MLKEM1024
description: Supported key algorithms.
policy.KasPublicKeyAlgEnum:
type: string
@@ -364,6 +367,9 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
policy.SortDirection:
type: string
title: SortDirection
diff --git a/docs/openapi/policy/objects.openapi.yaml b/docs/openapi/policy/objects.openapi.yaml
index 917017b1a0..b3f3c734ec 100644
--- a/docs/openapi/policy/objects.openapi.yaml
+++ b/docs/openapi/policy/objects.openapi.yaml
@@ -21,6 +21,9 @@ components:
- ALGORITHM_EC_P256
- ALGORITHM_EC_P384
- ALGORITHM_EC_P521
+ - ALGORITHM_HPQT_XWING
+ - ALGORITHM_HPQT_SECP256R1_MLKEM768
+ - ALGORITHM_HPQT_SECP384R1_MLKEM1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -47,6 +50,9 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
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 dbe62f43ca..37c0ab57ba 100644
--- a/docs/openapi/policy/obligations/obligations.openapi.yaml
+++ b/docs/openapi/policy/obligations/obligations.openapi.yaml
@@ -518,6 +518,9 @@ components:
- ALGORITHM_EC_P256
- ALGORITHM_EC_P384
- ALGORITHM_EC_P521
+ - ALGORITHM_HPQT_XWING
+ - ALGORITHM_HPQT_SECP256R1_MLKEM768
+ - ALGORITHM_HPQT_SECP384R1_MLKEM1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -544,6 +547,9 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
policy.SourceType:
type: string
title: SourceType
diff --git a/docs/openapi/policy/registeredresources/registered_resources.openapi.yaml b/docs/openapi/policy/registeredresources/registered_resources.openapi.yaml
index 97b2d07814..2bfd46ffc2 100644
--- a/docs/openapi/policy/registeredresources/registered_resources.openapi.yaml
+++ b/docs/openapi/policy/registeredresources/registered_resources.openapi.yaml
@@ -413,6 +413,9 @@ components:
- ALGORITHM_EC_P256
- ALGORITHM_EC_P384
- ALGORITHM_EC_P521
+ - ALGORITHM_HPQT_XWING
+ - ALGORITHM_HPQT_SECP256R1_MLKEM768
+ - ALGORITHM_HPQT_SECP384R1_MLKEM1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -439,6 +442,9 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
policy.SourceType:
type: string
title: SourceType
diff --git a/docs/openapi/policy/resourcemapping/resource_mapping.openapi.yaml b/docs/openapi/policy/resourcemapping/resource_mapping.openapi.yaml
index c768b805c0..880043c4f1 100644
--- a/docs/openapi/policy/resourcemapping/resource_mapping.openapi.yaml
+++ b/docs/openapi/policy/resourcemapping/resource_mapping.openapi.yaml
@@ -413,6 +413,9 @@ components:
- ALGORITHM_EC_P256
- ALGORITHM_EC_P384
- ALGORITHM_EC_P521
+ - ALGORITHM_HPQT_XWING
+ - ALGORITHM_HPQT_SECP256R1_MLKEM768
+ - ALGORITHM_HPQT_SECP384R1_MLKEM1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -439,6 +442,9 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
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 ec2033a9c1..d8dda22d01 100644
--- a/docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml
+++ b/docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml
@@ -449,6 +449,9 @@ components:
- ALGORITHM_EC_P256
- ALGORITHM_EC_P384
- ALGORITHM_EC_P521
+ - ALGORITHM_HPQT_XWING
+ - ALGORITHM_HPQT_SECP256R1_MLKEM768
+ - ALGORITHM_HPQT_SECP384R1_MLKEM1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -475,6 +478,9 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
policy.SourceType:
type: string
title: SourceType
diff --git a/docs/openapi/policy/unsafe/unsafe.openapi.yaml b/docs/openapi/policy/unsafe/unsafe.openapi.yaml
index f52e95b427..6c8859d581 100644
--- a/docs/openapi/policy/unsafe/unsafe.openapi.yaml
+++ b/docs/openapi/policy/unsafe/unsafe.openapi.yaml
@@ -387,6 +387,9 @@ components:
- ALGORITHM_EC_P256
- ALGORITHM_EC_P384
- ALGORITHM_EC_P521
+ - ALGORITHM_HPQT_XWING
+ - ALGORITHM_HPQT_SECP256R1_MLKEM768
+ - ALGORITHM_HPQT_SECP384R1_MLKEM1024
description: Supported key algorithms.
policy.AttributeRuleTypeEnum:
type: string
@@ -413,6 +416,9 @@ components:
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1
- KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768
+ - KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024
policy.KeyMode:
type: string
title: KeyMode
diff --git a/examples/cmd/encrypt.go b/examples/cmd/encrypt.go
index 4b8adc9eb4..e14f8ba033 100644
--- a/examples/cmd/encrypt.go
+++ b/examples/cmd/encrypt.go
@@ -93,13 +93,24 @@ func encrypt(cmd *cobra.Command, args []string) error {
}
func keyTypeForKeyType(alg string) (ocrypto.KeyType, error) {
- switch alg {
- case string(ocrypto.RSA2048Key):
+ switch ocrypto.KeyType(alg) {
+ case ocrypto.RSA2048Key:
return ocrypto.RSA2048Key, nil
- case string(ocrypto.EC256Key):
+ case ocrypto.RSA4096Key:
+ return ocrypto.RSA4096Key, nil
+ case ocrypto.EC256Key:
return ocrypto.EC256Key, nil
+ case ocrypto.EC384Key:
+ return ocrypto.EC384Key, nil
+ case ocrypto.EC521Key:
+ return ocrypto.EC521Key, nil
+ case ocrypto.HybridXWingKey:
+ return ocrypto.HybridXWingKey, nil
+ case ocrypto.HybridSecp256r1MLKEM768Key:
+ return ocrypto.HybridSecp256r1MLKEM768Key, nil
+ case ocrypto.HybridSecp384r1MLKEM1024Key:
+ return ocrypto.HybridSecp384r1MLKEM1024Key, nil
default:
- // do not submit add ocrypto.UnknownKey
return ocrypto.RSA2048Key, fmt.Errorf("unsupported key type [%s]", alg)
}
}
diff --git a/lib/ocrypto/BENCHMARK_REPORT.md b/lib/ocrypto/BENCHMARK_REPORT.md
new file mode 100644
index 0000000000..ac1b501374
--- /dev/null
+++ b/lib/ocrypto/BENCHMARK_REPORT.md
@@ -0,0 +1,162 @@
+# Benchmark Report: Hybrid Post-Quantum Key Wrapping Performance
+
+**Platform:** Apple M4, darwin/arm64, Go 1.25.8
+**Date:** 2026-04-15
+**Methodology:** `go test -bench=. -benchmem -count=3` (median of 3 runs)
+
+> **Note:** Wrap and unwrap benchmarks mirror the actual TDF code paths:
+> - **Wrap** follows `sdk/tdf.go` (`generateWrapKeyWithRSA`, `generateWrapKeyWithEC`, `generateWrapKeyWithHybrid`)
+> - **Unwrap** follows `service/internal/security/standard_crypto.go:Decrypt()`
+>
+> This includes PEM parsing, ephemeral keygen, ECDH, HKDF, AES-GCM, and ASN.1 marshaling — not simplified library-level `WrapDEK()` / `UnwrapDEK()` calls.
+
+## How to Run
+
+```bash
+# Full benchmark suite (use -count=5 for statistical significance)
+cd lib/ocrypto && go test -bench=. -benchmem -count=5 -timeout=10m
+
+# Quick single-count run
+cd lib/ocrypto && go test -bench=. -benchmem -count=1 -timeout=5m
+
+# Specific benchmark groups
+cd lib/ocrypto && go test -bench=BenchmarkKeyGeneration -benchmem
+cd lib/ocrypto && go test -bench=BenchmarkWrapDEK -benchmem
+cd lib/ocrypto && go test -bench=BenchmarkUnwrapDEK -benchmem
+cd lib/ocrypto && go test -bench=BenchmarkHybridSubOps -benchmem
+
+# Wrapped key size comparison table
+cd lib/ocrypto && go test -v -run TestWrappedKeySizeComparison
+```
+
+## Results
+
+### Key Generation
+
+| Scheme | Time | B/op | allocs/op | vs EC P-256 |
+|--------|-----:|-----:|----------:|-------------|
+| RSA-2048 | 48.2 ms | 671 KB | 6,101 | ~6,500x slower |
+| EC P-256 | 7.4 us | 984 B | 16 | baseline |
+| X-Wing | 44.1 us | 9.8 KB | 9 | ~6x slower |
+| P256+ML-KEM-768 | 35.3 us | 16.6 KB | 16 | ~5x slower |
+| P384+ML-KEM-1024 | 114.8 us | 23.9 KB | 19 | ~15x slower |
+
+**Takeaway:** RSA-2048 key generation is orders of magnitude slower than everything else (~48ms). All hybrid schemes generate keys in under 115us. EC P-256 is fastest at ~7.4us.
+
+### Wrap DEK (32-byte AES-256 key)
+
+These benchmarks follow the exact TDF wrapping paths:
+- **RSA:** `FromPublicPEM` -> `Encrypt` (OAEP)
+- **EC:** `NewECKeyPair` -> `ComputeECDHKey` -> `CalculateHKDF` -> `AES-GCM Encrypt`
+- **Hybrid:** `PubKeyFromPem` -> `Encapsulate` -> `CalculateHKDF` -> `AES-GCM Encrypt` -> `ASN.1 Marshal`
+
+| Scheme | Time | Wrapped Size | B/op | allocs/op | vs EC P-256 |
+|--------|-----:|-------------:|-----:|----------:|-------------|
+| RSA-2048 | 25.6 us | 256 B | 4.1 KB | 33 | 0.5x (faster) |
+| EC P-256 | 55.0 us | 60 B | 12.0 KB | 158 | baseline |
+| X-Wing | 77.1 us | 1,190 B | 16.4 KB | 42 | ~1.4x slower |
+| P256+ML-KEM-768 | 67.6 us | 1,223 B | 18.7 KB | 58 | ~1.2x slower |
+| P384+ML-KEM-1024 | 356.3 us | 1,735 B | 27.0 KB | 67 | ~6.5x slower |
+
+**Takeaway:** P256+ML-KEM-768 wrapping (~68us) is only ~1.2x slower than EC P-256 (~55us) — the ephemeral EC keygen + ECDH in the EC path narrows the gap significantly. RSA wrap is fastest since it's just OAEP padding. P384+ML-KEM-1024 is noticeably slower (~356us) due to the P-384 ECDH cost.
+
+### Unwrap DEK
+
+These benchmarks follow the KAS unwrap paths:
+- **RSA:** pre-loaded `AsymDecryption.Decrypt` (key parsed at startup)
+- **EC:** `NewSaltedECDecryptor(cachedKey, TDFSalt)` -> `DecryptWithEphemeralKey`
+- **Hybrid:** `PrivateKeyFromPem` -> `UnwrapDEK` (PEM parsed each call)
+
+| Scheme | Time | B/op | allocs/op | vs EC P-256 |
+|--------|-----:|-----:|----------:|-------------|
+| RSA-2048 | 705.0 us | 560 B | 8 | ~25x slower |
+| EC P-256 | 28.0 us | 4.1 KB | 40 | baseline |
+| X-Wing | 90.0 us | 12.4 KB | 37 | ~3.2x slower |
+| P256+ML-KEM-768 | 78.0 us | 22.0 KB | 50 | ~2.8x slower |
+| P384+ML-KEM-1024 | 365.2 us | 30.7 KB | 59 | ~13x slower |
+
+**Takeaway:** RSA unwrap is the slowest operation in the entire suite (~705us) due to private key exponentiation. P256+ML-KEM-768 unwraps in ~78us — fast enough for real-time use. Hybrid unwraps include PEM parsing overhead that could be optimized by caching parsed keys (as EC already does).
+
+### Wrap + Unwrap Round-Trip Summary
+
+| Scheme | Wrap + Unwrap | Quantum Safe? |
+|--------|-------------:|:-------------:|
+| RSA-2048 | 731 us | No |
+| EC P-256 | 83 us | No |
+| X-Wing | 167 us | Yes |
+| P256+ML-KEM-768 | 146 us | Yes |
+| P384+ML-KEM-1024 | 722 us | Yes |
+
+## Analysis: Where Time Is Spent
+
+The `BenchmarkHybridSubOps` benchmarks break down hybrid wrap operations into their constituent parts:
+
+### X-Wing Sub-Operations
+
+| Operation | Time | % of Wrap |
+|-----------|-----:|----------:|
+| Encapsulate (X25519 + ML-KEM-768) | 71.9 us | 93.3% |
+| HKDF key derivation | 0.53 us | 0.7% |
+| AES-GCM encrypt (32B DEK) | 0.39 us | 0.5% |
+| ASN.1 marshal | 0.57 us | 0.7% |
+| PEM parsing + overhead | ~3.7 us | 4.8% |
+
+### P256+ML-KEM-768 Sub-Operations
+
+| Operation | Time | % of Wrap |
+|-----------|-----:|----------:|
+| Encapsulate (ECDH P-256 + ML-KEM-768) | 63.6 us | 94.1% |
+| HKDF key derivation | 0.53 us | 0.8% |
+| AES-GCM encrypt (32B DEK) | 0.40 us | 0.6% |
+| ASN.1 marshal | 0.55 us | 0.8% |
+| PEM parsing + overhead | ~2.5 us | 3.7% |
+
+### P384+ML-KEM-1024 Sub-Operations
+
+| Operation | Time | % of Wrap |
+|-----------|-----:|----------:|
+| Encapsulate (ECDH P-384 + ML-KEM-1024) | 344.8 us | 96.8% |
+| HKDF key derivation | 0.53 us | 0.1% |
+| AES-GCM encrypt (32B DEK) | 0.40 us | 0.1% |
+| ASN.1 marshal | 0.61 us | 0.2% |
+| PEM parsing + overhead | ~10.0 us | 2.8% |
+
+**Conclusion:** KEM encapsulation dominates all hybrid schemes at 93-97% of total time. HKDF, AES-GCM, and ASN.1 marshaling are all sub-microsecond and negligible. The P-384 elliptic curve ECDH is ~5x slower than P-256, which is why P384+ML-KEM-1024 is significantly slower than P256+ML-KEM-768.
+
+## Manifest Size Impact
+
+| Scheme | Wrapped Key | Public Key (PEM) | Base64 Wrapped | Notes |
+|--------|------------:|-----------------:|---------------:|-------|
+| RSA-2048 | 256 B | 451 B | 344 B | No ephemeral key in manifest |
+| EC P-256 | 60 B | 178 B | 80 B | + ephemeral key (91 B) in manifest |
+| X-Wing | 1,190 B | 1,714 B | 1,588 B | All in single ASN.1 blob |
+| P256+ML-KEM-768 | 1,223 B | 1,785 B | 1,632 B | All in single ASN.1 blob |
+| P384+ML-KEM-1024 | 1,735 B | 2,347 B | 2,316 B | All in single ASN.1 blob |
+
+> Base64 overhead = ceil(raw_bytes * 4/3). TDF manifests store wrapped keys as base64.
+
+Hybrid schemes produce wrapped keys that are ~20x larger than EC P-256 (1.2-1.7 KB vs 60 B). For a TDF with a single recipient, this adds ~1-2 KB to the manifest. For multi-recipient TDFs, the overhead scales linearly per recipient.
+
+## Trade-offs Summary
+
+| Concern | RSA-2048 | EC P-256 | X-Wing | P256+ML-KEM-768 | P384+ML-KEM-1024 |
+|---------|----------|----------|--------|-----------------|-------------------|
+| Quantum resistance | None | None | Yes (hybrid) | Yes (hybrid) | Yes (hybrid) |
+| Key generation | 48 ms (slow) | 7.4 us (fastest) | 44 us | 35 us | 115 us |
+| Wrap latency | 26 us | 55 us | 77 us | 68 us | 356 us |
+| Unwrap latency | 705 us (slow) | 28 us | 90 us | 78 us | 365 us |
+| Round-trip | 731 us | 83 us | 167 us | 146 us | 722 us |
+| Wrapped key size | 256 B | 60 B | 1,190 B | 1,223 B | 1,735 B |
+| Standards basis | PKCS#1 | ECIES | IETF draft | NIST SP 800-227 | NIST SP 800-227 |
+
+### Recommendations
+
+- **P256+ML-KEM-768** is the best all-around hybrid choice: NIST-standardized, fastest hybrid round-trip (146us), and moderate size overhead (1.2 KB wrapped keys). Only 1.2x slower than EC P-256 for wrapping.
+- **P384+ML-KEM-1024** provides a higher classical security level (192-bit vs 128-bit) at the cost of ~5x more latency. Use when policy requires P-384 or equivalent classical strength.
+- **X-Wing** offers a simpler construction (X25519 + ML-KEM-768) but is based on an IETF draft rather than a NIST standard. Performance is comparable to P256+ML-KEM-768.
+- **EC P-256** remains the fastest and smallest option for environments where quantum resistance is not yet required.
+- **RSA-2048** has the worst unwrap performance (705us) and should be considered legacy.
+
+### Optimization Opportunities
+
+- **Hybrid unwrap PEM caching:** The KAS currently parses hybrid private key PEM on every unwrap call. Caching the parsed key (as EC already does) would save ~5-10us per unwrap.
diff --git a/lib/ocrypto/asym_decryption.go b/lib/ocrypto/asym_decryption.go
index 426f859723..fdd7bb5005 100644
--- a/lib/ocrypto/asym_decryption.go
+++ b/lib/ocrypto/asym_decryption.go
@@ -43,6 +43,14 @@ func FromPrivatePEMWithSalt(privateKeyInPem string, salt, info []byte) (PrivateK
if block == nil {
return AsymDecryption{}, errors.New("failed to parse PEM formatted private key")
}
+ switch block.Type {
+ case PEMBlockXWingPrivateKey:
+ return NewSaltedXWingDecryptor(block.Bytes, salt, info)
+ case PEMBlockP256MLKEM768PrivateKey:
+ return NewSaltedP256MLKEM768Decryptor(block.Bytes, salt, info)
+ case PEMBlockP384MLKEM1024PrivateKey:
+ return NewSaltedP384MLKEM1024Decryptor(block.Bytes, salt, info)
+ }
priv, err := x509.ParsePKCS8PrivateKey(block.Bytes)
switch {
diff --git a/lib/ocrypto/asym_encryption.go b/lib/ocrypto/asym_encryption.go
index c44aa64cce..7e08199509 100644
--- a/lib/ocrypto/asym_encryption.go
+++ b/lib/ocrypto/asym_encryption.go
@@ -23,8 +23,9 @@ import (
type SchemeType string
const (
- RSA SchemeType = "wrapped"
- EC SchemeType = "ec-wrapped"
+ RSA SchemeType = "wrapped"
+ EC SchemeType = "ec-wrapped"
+ Hybrid SchemeType = "hybrid-wrapped"
)
type PublicKeyEncryptor interface {
@@ -69,6 +70,19 @@ func FromPublicPEM(publicKeyInPem string) (PublicKeyEncryptor, error) {
}
func FromPublicPEMWithSalt(publicKeyInPem string, salt, info []byte) (PublicKeyEncryptor, error) {
+ block, _ := pem.Decode([]byte(publicKeyInPem))
+ if block == nil {
+ return nil, errors.New("failed to parse PEM formatted public key")
+ }
+ switch block.Type {
+ case PEMBlockXWingPublicKey:
+ return NewXWingEncryptor(block.Bytes, salt, info)
+ case PEMBlockP256MLKEM768PublicKey:
+ return NewP256MLKEM768Encryptor(block.Bytes, salt, info)
+ case PEMBlockP384MLKEM1024PublicKey:
+ return NewP384MLKEM1024Encryptor(block.Bytes, salt, info)
+ }
+
pub, err := getPublicPart(publicKeyInPem)
if err != nil {
return nil, err
diff --git a/lib/ocrypto/benchmark_test.go b/lib/ocrypto/benchmark_test.go
new file mode 100644
index 0000000000..f3286f2da2
--- /dev/null
+++ b/lib/ocrypto/benchmark_test.go
@@ -0,0 +1,685 @@
+package ocrypto
+
+import (
+ "crypto/sha256"
+ "crypto/x509"
+ "encoding/asn1"
+ "fmt"
+ "testing"
+)
+
+// Sink variables to prevent compiler from optimizing away results.
+var (
+ sinkBytes []byte
+ errSink error
+)
+
+// testDEK is a 32-byte AES-256 key used as the payload for wrap/unwrap benchmarks.
+var testDEK = []byte("0123456789abcdef0123456789abcdef")
+
+func BenchmarkKeyGeneration(b *testing.B) {
+ b.Run("RSA-2048", func(b *testing.B) {
+ for b.Loop() {
+ _, errSink = NewRSAKeyPair(2048)
+ }
+ })
+ b.Run("EC-P256", func(b *testing.B) {
+ for b.Loop() {
+ _, errSink = NewECKeyPair(ECCModeSecp256r1)
+ }
+ })
+ b.Run("XWing", func(b *testing.B) {
+ for b.Loop() {
+ _, errSink = NewXWingKeyPair()
+ }
+ })
+ b.Run("P256_MLKEM768", func(b *testing.B) {
+ for b.Loop() {
+ _, errSink = NewP256MLKEM768KeyPair()
+ }
+ })
+ b.Run("P384_MLKEM1024", func(b *testing.B) {
+ for b.Loop() {
+ _, errSink = NewP384MLKEM1024KeyPair()
+ }
+ })
+}
+
+// benchTDFSalt matches tdf.go:tdfSalt() — SHA-256("TDF").
+func benchTDFSalt() []byte {
+ digest := sha256.New()
+ digest.Write([]byte("TDF"))
+ return digest.Sum(nil)
+}
+
+// BenchmarkWrapDEK mirrors the actual TDF key-wrapping paths in sdk/tdf.go:
+// - RSA: FromPublicPEM -> Encrypt (generateWrapKeyWithRSA)
+// - EC: NewECKeyPair -> ComputeECDHKey -> HKDF -> AES-GCM (generateWrapKeyWithEC)
+// - Hybrid: PubKeyFromPem -> Encapsulate -> HKDF -> AES-GCM -> ASN.1 (generateWrapKeyWithHybrid)
+func BenchmarkWrapDEK(b *testing.B) {
+ salt := benchTDFSalt()
+
+ // RSA-2048: setup KAS public key
+ rsaKP, err := NewRSAKeyPair(2048)
+ if err != nil {
+ b.Fatal(err)
+ }
+ rsaPubPEM, err := rsaKP.PublicKeyInPemFormat()
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ // EC P-256: setup KAS public key PEM
+ ecKP, err := NewECKeyPair(ECCModeSecp256r1)
+ if err != nil {
+ b.Fatal(err)
+ }
+ ecKASPubPEM, err := ecKP.PublicKeyInPemFormat()
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ // X-Wing: setup KAS public key PEM
+ xwingKP, err := NewXWingKeyPair()
+ if err != nil {
+ b.Fatal(err)
+ }
+ xwingPubPEM, err := xwingKP.PublicKeyInPemFormat()
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ // P256+MLKEM768: setup KAS public key PEM
+ p256KP, err := NewP256MLKEM768KeyPair()
+ if err != nil {
+ b.Fatal(err)
+ }
+ p256PubPEM, err := p256KP.PublicKeyInPemFormat()
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ // P384+MLKEM1024: setup KAS public key PEM
+ p384KP, err := NewP384MLKEM1024KeyPair()
+ if err != nil {
+ b.Fatal(err)
+ }
+ p384PubPEM, err := p384KP.PublicKeyInPemFormat()
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ // RSA: tdf.go calls FromPublicPEM -> Encrypt
+ b.Run("RSA-2048", func(b *testing.B) {
+ for b.Loop() {
+ enc, err := FromPublicPEM(rsaPubPEM)
+ if err != nil {
+ b.Fatal(err)
+ }
+ sinkBytes, errSink = enc.Encrypt(testDEK)
+ }
+ b.ReportMetric(float64(len(sinkBytes)), "wrapped-bytes")
+ })
+
+ // EC: tdf.go generates ephemeral EC keypair, computes ECDH, derives via HKDF, AES-GCM wraps
+ b.Run("EC-P256", func(b *testing.B) {
+ for b.Loop() {
+ ephKP, err := NewECKeyPair(ECCModeSecp256r1)
+ if err != nil {
+ b.Fatal(err)
+ }
+ ephPrivPEM, err := ephKP.PrivateKeyInPemFormat()
+ if err != nil {
+ b.Fatal(err)
+ }
+ ecdhKey, err := ComputeECDHKey([]byte(ephPrivPEM), []byte(ecKASPubPEM))
+ if err != nil {
+ b.Fatal(err)
+ }
+ sessionKey, err := CalculateHKDF(salt, ecdhKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+ gcm, err := NewAESGcm(sessionKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+ sinkBytes, errSink = gcm.Encrypt(testDEK)
+ }
+ b.ReportMetric(float64(len(sinkBytes)), "wrapped-bytes")
+ })
+
+ // X-Wing: tdf.go parses PEM, calls Encapsulate, HKDF, AES-GCM, then ASN.1 marshal
+ b.Run("XWing", func(b *testing.B) {
+ for b.Loop() {
+ pubKey, err := XWingPubKeyFromPem([]byte(xwingPubPEM))
+ if err != nil {
+ b.Fatal(err)
+ }
+ ss, ct, err := XWingEncapsulate(pubKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+ wrapKey, err := CalculateHKDF(salt, ss)
+ if err != nil {
+ b.Fatal(err)
+ }
+ gcm, err := NewAESGcm(wrapKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+ encDEK, err := gcm.Encrypt(testDEK)
+ if err != nil {
+ b.Fatal(err)
+ }
+ sinkBytes, errSink = asn1.Marshal(HybridNISTWrappedKey{
+ HybridCiphertext: ct,
+ EncryptedDEK: encDEK,
+ })
+ }
+ b.ReportMetric(float64(len(sinkBytes)), "wrapped-bytes")
+ })
+
+ // P256+MLKEM768: same flow as X-Wing with different Encapsulate/PEM parse
+ b.Run("P256_MLKEM768", func(b *testing.B) {
+ for b.Loop() {
+ pubKey, err := P256MLKEM768PubKeyFromPem([]byte(p256PubPEM))
+ if err != nil {
+ b.Fatal(err)
+ }
+ ss, ct, err := P256MLKEM768Encapsulate(pubKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+ wrapKey, err := CalculateHKDF(salt, ss)
+ if err != nil {
+ b.Fatal(err)
+ }
+ gcm, err := NewAESGcm(wrapKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+ encDEK, err := gcm.Encrypt(testDEK)
+ if err != nil {
+ b.Fatal(err)
+ }
+ sinkBytes, errSink = asn1.Marshal(HybridNISTWrappedKey{
+ HybridCiphertext: ct,
+ EncryptedDEK: encDEK,
+ })
+ }
+ b.ReportMetric(float64(len(sinkBytes)), "wrapped-bytes")
+ })
+
+ // P384+MLKEM1024: same flow with P384 variant
+ b.Run("P384_MLKEM1024", func(b *testing.B) {
+ for b.Loop() {
+ pubKey, err := P384MLKEM1024PubKeyFromPem([]byte(p384PubPEM))
+ if err != nil {
+ b.Fatal(err)
+ }
+ ss, ct, err := P384MLKEM1024Encapsulate(pubKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+ wrapKey, err := CalculateHKDF(salt, ss)
+ if err != nil {
+ b.Fatal(err)
+ }
+ gcm, err := NewAESGcm(wrapKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+ encDEK, err := gcm.Encrypt(testDEK)
+ if err != nil {
+ b.Fatal(err)
+ }
+ sinkBytes, errSink = asn1.Marshal(HybridNISTWrappedKey{
+ HybridCiphertext: ct,
+ EncryptedDEK: encDEK,
+ })
+ }
+ b.ReportMetric(float64(len(sinkBytes)), "wrapped-bytes")
+ })
+}
+
+// BenchmarkUnwrapDEK mirrors the actual KAS unwrap paths in
+// service/internal/security/standard_crypto.go:Decrypt():
+// - RSA: pre-loaded AsymDecryption.Decrypt (key already parsed)
+// - EC: ECPrivateKeyFromPem (cached) -> NewSaltedECDecryptor(TDFSalt) -> DecryptWithEphemeralKey
+// - Hybrid: PrivateKeyFromPem -> UnwrapDEK (PEM parsed each time in current KAS code)
+func BenchmarkUnwrapDEK(b *testing.B) {
+ salt := benchTDFSalt()
+
+ // RSA-2048: KAS pre-loads the AsymDecryption at startup
+ rsaKP, err := NewRSAKeyPair(2048)
+ if err != nil {
+ b.Fatal(err)
+ }
+ rsaPubPEM, err := rsaKP.PublicKeyInPemFormat()
+ if err != nil {
+ b.Fatal(err)
+ }
+ rsaPrivPEM, err := rsaKP.PrivateKeyInPemFormat()
+ if err != nil {
+ b.Fatal(err)
+ }
+ rsaEnc, err := NewAsymEncryption(rsaPubPEM)
+ if err != nil {
+ b.Fatal(err)
+ }
+ rsaWrapped, err := rsaEnc.Encrypt(testDEK)
+ if err != nil {
+ b.Fatal(err)
+ }
+ rsaDec, err := NewAsymDecryption(rsaPrivPEM)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ // EC P-256: KAS caches the parsed private key, creates decryptor per request
+ ecKASKP, err := NewECKeyPair(ECCModeSecp256r1)
+ if err != nil {
+ b.Fatal(err)
+ }
+ ecKASPubPEM, err := ecKASKP.PublicKeyInPemFormat()
+ if err != nil {
+ b.Fatal(err)
+ }
+ ecKASPrivPEM, err := ecKASKP.PrivateKeyInPemFormat()
+ if err != nil {
+ b.Fatal(err)
+ }
+ // Wrap using the TDF path: ephemeral keygen + ECDH + HKDF + AES-GCM
+ ecEphKP, err := NewECKeyPair(ECCModeSecp256r1)
+ if err != nil {
+ b.Fatal(err)
+ }
+ ecEphPrivPEM, err := ecEphKP.PrivateKeyInPemFormat()
+ if err != nil {
+ b.Fatal(err)
+ }
+ ecEphPubPEM, err := ecEphKP.PublicKeyInPemFormat()
+ if err != nil {
+ b.Fatal(err)
+ }
+ ecdhKey, err := ComputeECDHKey([]byte(ecEphPrivPEM), []byte(ecKASPubPEM))
+ if err != nil {
+ b.Fatal(err)
+ }
+ ecSessionKey, err := CalculateHKDF(salt, ecdhKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+ ecGCM, err := NewAESGcm(ecSessionKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+ ecWrapped, err := ecGCM.Encrypt(testDEK)
+ if err != nil {
+ b.Fatal(err)
+ }
+ // KAS receives the ephemeral public key as DER (parsed from PEM in the manifest).
+ // DecryptWithEphemeralKey first tries x509.ParsePKIXPublicKey (DER), then compressed.
+ ecEphPubECDH, err := ECPubKeyFromPem([]byte(ecEphPubPEM))
+ if err != nil {
+ b.Fatal(err)
+ }
+ ecEphDER, err := x509.MarshalPKIXPublicKey(ecEphPubECDH)
+ if err != nil {
+ b.Fatal(err)
+ }
+ // KAS parses private key once (cached in StandardECCrypto)
+ ecKASPrivKey, err := ECPrivateKeyFromPem([]byte(ecKASPrivPEM))
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ // X-Wing: KAS parses PEM each call, then calls UnwrapDEK
+ xwingKP, err := NewXWingKeyPair()
+ if err != nil {
+ b.Fatal(err)
+ }
+ xwingPrivPEM, err := xwingKP.PrivateKeyInPemFormat()
+ if err != nil {
+ b.Fatal(err)
+ }
+ xwingWrapped, err := XWingWrapDEK(xwingKP.publicKey, testDEK)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ // P256+MLKEM768: KAS parses PEM each call, then calls UnwrapDEK
+ p256KP, err := NewP256MLKEM768KeyPair()
+ if err != nil {
+ b.Fatal(err)
+ }
+ p256PrivPEM, err := p256KP.PrivateKeyInPemFormat()
+ if err != nil {
+ b.Fatal(err)
+ }
+ p256Wrapped, err := P256MLKEM768WrapDEK(p256KP.publicKey, testDEK)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ // P384+MLKEM1024: KAS parses PEM each call, then calls UnwrapDEK
+ p384KP, err := NewP384MLKEM1024KeyPair()
+ if err != nil {
+ b.Fatal(err)
+ }
+ p384PrivPEM, err := p384KP.PrivateKeyInPemFormat()
+ if err != nil {
+ b.Fatal(err)
+ }
+ p384Wrapped, err := P384MLKEM1024WrapDEK(p384KP.publicKey, testDEK)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ // RSA: KAS has pre-loaded AsymDecryption, just calls Decrypt
+ b.Run("RSA-2048", func(b *testing.B) {
+ for b.Loop() {
+ sinkBytes, errSink = rsaDec.Decrypt(rsaWrapped)
+ }
+ })
+
+ // EC: KAS creates NewSaltedECDecryptor(cachedSK, TDFSalt, nil) -> DecryptWithEphemeralKey
+ b.Run("EC-P256", func(b *testing.B) {
+ for b.Loop() {
+ dec, err := NewSaltedECDecryptor(ecKASPrivKey, salt, nil)
+ if err != nil {
+ b.Fatal(err)
+ }
+ sinkBytes, errSink = dec.DecryptWithEphemeralKey(ecWrapped, ecEphDER)
+ }
+ })
+
+ // X-Wing: KAS parses PEM then calls UnwrapDEK
+ b.Run("XWing", func(b *testing.B) {
+ for b.Loop() {
+ privKey, err := XWingPrivateKeyFromPem([]byte(xwingPrivPEM))
+ if err != nil {
+ b.Fatal(err)
+ }
+ sinkBytes, errSink = XWingUnwrapDEK(privKey, xwingWrapped)
+ }
+ })
+
+ // P256+MLKEM768: KAS parses PEM then calls UnwrapDEK
+ b.Run("P256_MLKEM768", func(b *testing.B) {
+ for b.Loop() {
+ privKey, err := P256MLKEM768PrivateKeyFromPem([]byte(p256PrivPEM))
+ if err != nil {
+ b.Fatal(err)
+ }
+ sinkBytes, errSink = P256MLKEM768UnwrapDEK(privKey, p256Wrapped)
+ }
+ })
+
+ // P384+MLKEM1024: KAS parses PEM then calls UnwrapDEK
+ b.Run("P384_MLKEM1024", func(b *testing.B) {
+ for b.Loop() {
+ privKey, err := P384MLKEM1024PrivateKeyFromPem([]byte(p384PrivPEM))
+ if err != nil {
+ b.Fatal(err)
+ }
+ sinkBytes, errSink = P384MLKEM1024UnwrapDEK(privKey, p384Wrapped)
+ }
+ })
+}
+
+func BenchmarkHybridSubOps(b *testing.B) {
+ // Setup X-Wing
+ xwingKP, err := NewXWingKeyPair()
+ if err != nil {
+ b.Fatal(err)
+ }
+ xwingSS, xwingCt, err := XWingEncapsulate(xwingKP.publicKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ // Setup P256+MLKEM768
+ p256KP, err := NewP256MLKEM768KeyPair()
+ if err != nil {
+ b.Fatal(err)
+ }
+ p256SS, p256Ct, err := P256MLKEM768Encapsulate(p256KP.publicKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ // Setup P384+MLKEM1024
+ p384KP, err := NewP384MLKEM1024KeyPair()
+ if err != nil {
+ b.Fatal(err)
+ }
+ p384SS, p384Ct, err := P384MLKEM1024Encapsulate(p384KP.publicKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ salt := defaultXWingSalt()
+
+ // Pre-derive a wrap key for AES-GCM benchmarks
+ wrapKey, err := deriveXWingWrapKey(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)
+ }
+ })
+ b.Run("XWing/HKDF", func(b *testing.B) {
+ for b.Loop() {
+ sinkBytes, errSink = deriveXWingWrapKey(xwingSS, salt, nil)
+ }
+ })
+ b.Run("XWing/AES-GCM-Encrypt", func(b *testing.B) {
+ gcm, err := NewAESGcm(wrapKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+ for b.Loop() {
+ sinkBytes, errSink = gcm.Encrypt(testDEK)
+ }
+ })
+ b.Run("XWing/ASN1-Marshal", func(b *testing.B) {
+ wrapped := XWingWrappedKey{XWingCiphertext: xwingCt, EncryptedDEK: testDEK}
+ for b.Loop() {
+ sinkBytes, errSink = asn1.Marshal(wrapped)
+ }
+ })
+
+ // P256+MLKEM768 sub-ops
+ p256WrapKey, err := deriveHybridNISTWrapKey(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)
+ }
+ })
+ b.Run("P256_MLKEM768/HKDF", func(b *testing.B) {
+ for b.Loop() {
+ sinkBytes, errSink = deriveHybridNISTWrapKey(p256SS, salt, nil)
+ }
+ })
+ b.Run("P256_MLKEM768/AES-GCM-Encrypt", func(b *testing.B) {
+ gcm, err := NewAESGcm(p256WrapKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+ for b.Loop() {
+ sinkBytes, errSink = gcm.Encrypt(testDEK)
+ }
+ })
+ b.Run("P256_MLKEM768/ASN1-Marshal", func(b *testing.B) {
+ wrapped := HybridNISTWrappedKey{HybridCiphertext: p256Ct, EncryptedDEK: testDEK}
+ for b.Loop() {
+ sinkBytes, errSink = asn1.Marshal(wrapped)
+ }
+ })
+
+ // P384+MLKEM1024 sub-ops
+ p384WrapKey, err := deriveHybridNISTWrapKey(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)
+ }
+ })
+ b.Run("P384_MLKEM1024/HKDF", func(b *testing.B) {
+ for b.Loop() {
+ sinkBytes, errSink = deriveHybridNISTWrapKey(p384SS, salt, nil)
+ }
+ })
+ b.Run("P384_MLKEM1024/AES-GCM-Encrypt", func(b *testing.B) {
+ gcm, err := NewAESGcm(p384WrapKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+ for b.Loop() {
+ sinkBytes, errSink = gcm.Encrypt(testDEK)
+ }
+ })
+ b.Run("P384_MLKEM1024/ASN1-Marshal", func(b *testing.B) {
+ wrapped := HybridNISTWrappedKey{HybridCiphertext: p384Ct, EncryptedDEK: testDEK}
+ for b.Loop() {
+ sinkBytes, errSink = asn1.Marshal(wrapped)
+ }
+ })
+}
+
+func TestWrappedKeySizeComparison(t *testing.T) {
+ type sizeResult struct {
+ scheme string
+ wrappedLen int
+ pubKeyLen int
+ notes string
+ }
+
+ var results []sizeResult
+
+ // RSA-2048
+ rsaKP, err := NewRSAKeyPair(2048)
+ if err != nil {
+ t.Fatal(err)
+ }
+ rsaPubPEM, err := rsaKP.PublicKeyInPemFormat()
+ if err != nil {
+ t.Fatal(err)
+ }
+ rsaEnc, err := NewAsymEncryption(rsaPubPEM)
+ if err != nil {
+ t.Fatal(err)
+ }
+ rsaWrapped, err := rsaEnc.Encrypt(testDEK)
+ if err != nil {
+ t.Fatal(err)
+ }
+ results = append(results, sizeResult{
+ scheme: "RSA-2048",
+ wrappedLen: len(rsaWrapped),
+ pubKeyLen: len(rsaPubPEM),
+ notes: "No ephemeral key",
+ })
+
+ // EC P-256
+ ecKP, err := NewECKeyPair(ECCModeSecp256r1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ ecPubPEM, err := ecKP.PublicKeyInPemFormat()
+ if err != nil {
+ t.Fatal(err)
+ }
+ ecEnc, err := FromPublicPEM(ecPubPEM)
+ if err != nil {
+ t.Fatal(err)
+ }
+ ecWrapped, err := ecEnc.Encrypt(testDEK)
+ if err != nil {
+ t.Fatal(err)
+ }
+ ecEphemeral := ecEnc.EphemeralKey()
+ results = append(results, sizeResult{
+ scheme: "EC P-256",
+ wrappedLen: len(ecWrapped),
+ pubKeyLen: len(ecPubPEM),
+ notes: fmt.Sprintf("+ ephemeral key (%d bytes)", len(ecEphemeral)),
+ })
+
+ // X-Wing
+ xwingKP, err := NewXWingKeyPair()
+ if err != nil {
+ t.Fatal(err)
+ }
+ xwingPubPEM, err := xwingKP.PublicKeyInPemFormat()
+ if err != nil {
+ t.Fatal(err)
+ }
+ xwingWrapped, err := XWingWrapDEK(xwingKP.publicKey, testDEK)
+ if err != nil {
+ t.Fatal(err)
+ }
+ results = append(results, sizeResult{
+ scheme: "X-Wing",
+ wrappedLen: len(xwingWrapped),
+ pubKeyLen: len(xwingPubPEM),
+ notes: "All in ASN.1 blob",
+ })
+
+ // P256+MLKEM768
+ p256KP, err := NewP256MLKEM768KeyPair()
+ if err != nil {
+ t.Fatal(err)
+ }
+ p256PubPEM, err := p256KP.PublicKeyInPemFormat()
+ if err != nil {
+ t.Fatal(err)
+ }
+ p256Wrapped, err := P256MLKEM768WrapDEK(p256KP.publicKey, testDEK)
+ if err != nil {
+ t.Fatal(err)
+ }
+ results = append(results, sizeResult{
+ scheme: "P256+MLKEM768",
+ wrappedLen: len(p256Wrapped),
+ pubKeyLen: len(p256PubPEM),
+ notes: "All in ASN.1 blob",
+ })
+
+ // P384+MLKEM1024
+ p384KP, err := NewP384MLKEM1024KeyPair()
+ if err != nil {
+ t.Fatal(err)
+ }
+ p384PubPEM, err := p384KP.PublicKeyInPemFormat()
+ if err != nil {
+ t.Fatal(err)
+ }
+ p384Wrapped, err := P384MLKEM1024WrapDEK(p384KP.publicKey, testDEK)
+ if err != nil {
+ t.Fatal(err)
+ }
+ results = append(results, sizeResult{
+ scheme: "P384+MLKEM1024",
+ wrappedLen: len(p384Wrapped),
+ pubKeyLen: len(p384PubPEM),
+ notes: "All in ASN.1 blob",
+ })
+
+ // Print table
+ t.Logf("\n%-20s %20s %20s %s", "Scheme", "Wrapped Key (bytes)", "Public Key (bytes)", "Notes")
+ t.Logf("%-20s %20s %20s %s", "------", "-------------------", "------------------", "-----")
+ for _, r := range results {
+ t.Logf("%-20s %20d %20d %s", r.scheme, r.wrappedLen, r.pubKeyLen, r.notes)
+ }
+}
diff --git a/lib/ocrypto/go.mod b/lib/ocrypto/go.mod
index 8328aa0e4c..1fafd3a069 100644
--- a/lib/ocrypto/go.mod
+++ b/lib/ocrypto/go.mod
@@ -5,6 +5,7 @@ go 1.25.0
toolchain go1.25.8
require (
+ github.com/cloudflare/circl v1.6.3
github.com/stretchr/testify v1.10.0
golang.org/x/crypto v0.45.0
)
@@ -14,6 +15,7 @@ require (
github.com/kr/pretty v0.3.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
+ golang.org/x/sys v0.38.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/lib/ocrypto/go.sum b/lib/ocrypto/go.sum
index 63574bef4b..0388adaa2d 100644
--- a/lib/ocrypto/go.sum
+++ b/lib/ocrypto/go.sum
@@ -1,3 +1,5 @@
+github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
+github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -18,6 +20,8 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
+golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
+golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
diff --git a/lib/ocrypto/hybrid_nist.go b/lib/ocrypto/hybrid_nist.go
new file mode 100644
index 0000000000..c366f2ed17
--- /dev/null
+++ b/lib/ocrypto/hybrid_nist.go
@@ -0,0 +1,534 @@
+package ocrypto
+
+import (
+ "crypto/ecdh"
+ "crypto/rand"
+ "crypto/sha256"
+ "encoding/asn1"
+ "fmt"
+ "io"
+
+ "github.com/cloudflare/circl/kem/mlkem/mlkem1024"
+ "github.com/cloudflare/circl/kem/mlkem/mlkem768"
+ "golang.org/x/crypto/hkdf"
+)
+
+const (
+ HybridSecp256r1MLKEM768Key KeyType = "hpqt:secp256r1-mlkem768"
+ HybridSecp384r1MLKEM1024Key KeyType = "hpqt:secp384r1-mlkem1024"
+)
+
+// Sizes for P-256 + ML-KEM-768 hybrid.
+const (
+ P256MLKEM768ECPublicKeySize = 65 // uncompressed P-256 point
+ P256MLKEM768ECPrivateKeySize = 32 // P-256 scalar
+ P256MLKEM768MLKEMPubKeySize = 1184 // mlkem768.PublicKeySize
+ P256MLKEM768MLKEMPrivKeySize = 2400 // mlkem768.PrivateKeySize
+ P256MLKEM768MLKEMCtSize = 1088 // mlkem768.CiphertextSize
+
+ P256MLKEM768PublicKeySize = P256MLKEM768ECPublicKeySize + P256MLKEM768MLKEMPubKeySize // 1249
+ P256MLKEM768PrivateKeySize = P256MLKEM768ECPrivateKeySize + P256MLKEM768MLKEMPrivKeySize // 2432
+ P256MLKEM768CiphertextSize = P256MLKEM768ECPublicKeySize + P256MLKEM768MLKEMCtSize // 1153
+
+ PEMBlockP256MLKEM768PublicKey = "SECP256R1 MLKEM768 PUBLIC KEY"
+ PEMBlockP256MLKEM768PrivateKey = "SECP256R1 MLKEM768 PRIVATE KEY"
+)
+
+// Sizes for P-384 + ML-KEM-1024 hybrid.
+const (
+ P384MLKEM1024ECPublicKeySize = 97 // uncompressed P-384 point
+ P384MLKEM1024ECPrivateKeySize = 48 // P-384 scalar
+ P384MLKEM1024MLKEMPubKeySize = 1568 // mlkem1024.PublicKeySize
+ P384MLKEM1024MLKEMPrivKeySize = 3168 // mlkem1024.PrivateKeySize
+ P384MLKEM1024MLKEMCtSize = 1568 // mlkem1024.CiphertextSize
+
+ P384MLKEM1024PublicKeySize = P384MLKEM1024ECPublicKeySize + P384MLKEM1024MLKEMPubKeySize // 1665
+ P384MLKEM1024PrivateKeySize = P384MLKEM1024ECPrivateKeySize + P384MLKEM1024MLKEMPrivKeySize // 3216
+ P384MLKEM1024CiphertextSize = P384MLKEM1024ECPublicKeySize + P384MLKEM1024MLKEMCtSize // 1665
+
+ PEMBlockP384MLKEM1024PublicKey = "SECP384R1 MLKEM1024 PUBLIC KEY"
+ 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
+ ecPubSize int
+ ecPrivSize int
+ mlkemPubSize int
+ mlkemPrivSize int
+ mlkemCtSize int
+ pubPEMBlock string
+ privPEMBlock string
+ keyType KeyType
+ mlkemEncapsulate func(pubKey []byte) (sharedSecret, ciphertext []byte, err error)
+ mlkemDecapsulate func(privKey, ciphertext []byte) (sharedSecret []byte, err error)
+}
+
+var p256mlkem768Params = hybridNISTParams{
+ curve: ecdh.P256(),
+ ecPubSize: P256MLKEM768ECPublicKeySize,
+ ecPrivSize: P256MLKEM768ECPrivateKeySize,
+ mlkemPubSize: P256MLKEM768MLKEMPubKeySize,
+ mlkemPrivSize: P256MLKEM768MLKEMPrivKeySize,
+ mlkemCtSize: P256MLKEM768MLKEMCtSize,
+ pubPEMBlock: PEMBlockP256MLKEM768PublicKey,
+ privPEMBlock: PEMBlockP256MLKEM768PrivateKey,
+ keyType: HybridSecp256r1MLKEM768Key,
+ mlkemEncapsulate: func(pubKey []byte) ([]byte, []byte, error) {
+ var pk mlkem768.PublicKey
+ if err := pk.Unpack(pubKey); err != nil {
+ return nil, nil, fmt.Errorf("mlkem768 public key unpack: %w", err)
+ }
+ ct := make([]byte, mlkem768.CiphertextSize)
+ ss := make([]byte, mlkem768.SharedKeySize)
+ pk.EncapsulateTo(ct, ss, nil)
+ return ss, ct, nil
+ },
+ mlkemDecapsulate: func(privKey, ciphertext []byte) ([]byte, error) {
+ var sk mlkem768.PrivateKey
+ if err := sk.Unpack(privKey); err != nil {
+ return nil, fmt.Errorf("mlkem768 private key unpack: %w", err)
+ }
+ ss := make([]byte, mlkem768.SharedKeySize)
+ sk.DecapsulateTo(ss, ciphertext)
+ return ss, nil
+ },
+}
+
+var p384mlkem1024Params = hybridNISTParams{
+ curve: ecdh.P384(),
+ ecPubSize: P384MLKEM1024ECPublicKeySize,
+ ecPrivSize: P384MLKEM1024ECPrivateKeySize,
+ mlkemPubSize: P384MLKEM1024MLKEMPubKeySize,
+ mlkemPrivSize: P384MLKEM1024MLKEMPrivKeySize,
+ mlkemCtSize: P384MLKEM1024MLKEMCtSize,
+ pubPEMBlock: PEMBlockP384MLKEM1024PublicKey,
+ privPEMBlock: PEMBlockP384MLKEM1024PrivateKey,
+ keyType: HybridSecp384r1MLKEM1024Key,
+ mlkemEncapsulate: func(pubKey []byte) ([]byte, []byte, error) {
+ var pk mlkem1024.PublicKey
+ if err := pk.Unpack(pubKey); err != nil {
+ return nil, nil, fmt.Errorf("mlkem1024 public key unpack: %w", err)
+ }
+ ct := make([]byte, mlkem1024.CiphertextSize)
+ ss := make([]byte, mlkem1024.SharedKeySize)
+ pk.EncapsulateTo(ct, ss, nil)
+ return ss, ct, nil
+ },
+ mlkemDecapsulate: func(privKey, ciphertext []byte) ([]byte, error) {
+ var sk mlkem1024.PrivateKey
+ if err := sk.Unpack(privKey); err != nil {
+ return nil, fmt.Errorf("mlkem1024 private key unpack: %w", err)
+ }
+ ss := make([]byte, mlkem1024.SharedKeySize)
+ sk.DecapsulateTo(ss, ciphertext)
+ return ss, nil
+ },
+}
+
+// HybridNISTKeyPair holds a hybrid EC + ML-KEM keypair as raw bytes.
+type HybridNISTKeyPair struct {
+ publicKey []byte
+ privateKey []byte
+ 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
+ case HybridXWingKey, HybridSecp256r1MLKEM768Key, HybridSecp384r1MLKEM1024Key:
+ return true
+ default:
+ return false
+ }
+}
+
+// NewHybridKeyPair creates a key pair for the given hybrid key type.
+func NewHybridKeyPair(kt KeyType) (KeyPair, error) {
+ switch kt { //nolint:exhaustive // only handle hybrid types
+ case HybridXWingKey:
+ return NewXWingKeyPair()
+ case HybridSecp256r1MLKEM768Key:
+ return NewP256MLKEM768KeyPair()
+ case HybridSecp384r1MLKEM1024Key:
+ return NewP384MLKEM1024KeyPair()
+ default:
+ return nil, fmt.Errorf("unsupported hybrid key type: %v", kt)
+ }
+}
+
+func NewP256MLKEM768KeyPair() (HybridNISTKeyPair, error) {
+ return newHybridNISTKeyPair(&p256mlkem768Params, func() ([]byte, []byte, error) {
+ pk, sk, err := mlkem768.GenerateKeyPair(rand.Reader)
+ if err != nil {
+ return nil, nil, err
+ }
+ pub := make([]byte, mlkem768.PublicKeySize)
+ priv := make([]byte, mlkem768.PrivateKeySize)
+ pk.Pack(pub)
+ sk.Pack(priv)
+ return pub, priv, nil
+ })
+}
+
+func NewP384MLKEM1024KeyPair() (HybridNISTKeyPair, error) {
+ return newHybridNISTKeyPair(&p384mlkem1024Params, func() ([]byte, []byte, error) {
+ pk, sk, err := mlkem1024.GenerateKeyPair(rand.Reader)
+ if err != nil {
+ return nil, nil, err
+ }
+ pub := make([]byte, mlkem1024.PublicKeySize)
+ priv := make([]byte, mlkem1024.PrivateKeySize)
+ pk.Pack(pub)
+ sk.Pack(priv)
+ return pub, priv, nil
+ })
+}
+
+func newHybridNISTKeyPair(p *hybridNISTParams, genMLKEM func() (pub, priv []byte, err error)) (HybridNISTKeyPair, error) {
+ ecPriv, err := p.curve.GenerateKey(rand.Reader)
+ if err != nil {
+ return HybridNISTKeyPair{}, fmt.Errorf("ECDH key generation failed: %w", err)
+ }
+ ecPub := ecPriv.PublicKey().Bytes() // uncompressed point
+ ecPrivBytes := ecPriv.Bytes() // raw scalar
+
+ mlkemPub, mlkemPriv, err := genMLKEM()
+ if err != nil {
+ return HybridNISTKeyPair{}, fmt.Errorf("ML-KEM key generation failed: %w", err)
+ }
+
+ pubKey := make([]byte, 0, p.ecPubSize+p.mlkemPubSize)
+ pubKey = append(pubKey, ecPub...)
+ pubKey = append(pubKey, mlkemPub...)
+
+ privKey := make([]byte, 0, p.ecPrivSize+p.mlkemPrivSize)
+ privKey = append(privKey, ecPrivBytes...)
+ privKey = append(privKey, mlkemPriv...)
+
+ return HybridNISTKeyPair{
+ publicKey: pubKey,
+ privateKey: privKey,
+ params: p,
+ }, nil
+}
+
+func (k HybridNISTKeyPair) PublicKeyInPemFormat() (string, error) {
+ return rawToPEM(k.params.pubPEMBlock, k.publicKey, k.params.ecPubSize+k.params.mlkemPubSize)
+}
+
+func (k HybridNISTKeyPair) PrivateKeyInPemFormat() (string, error) {
+ return rawToPEM(k.params.privPEMBlock, k.privateKey, k.params.ecPrivSize+k.params.mlkemPrivSize)
+}
+
+func (k HybridNISTKeyPair) GetKeyType() KeyType {
+ return k.params.keyType
+}
+
+func P256MLKEM768PubKeyFromPem(data []byte) ([]byte, error) {
+ return decodeSizedPEMBlock(data, PEMBlockP256MLKEM768PublicKey, P256MLKEM768PublicKeySize)
+}
+
+func P256MLKEM768PrivateKeyFromPem(data []byte) ([]byte, error) {
+ return decodeSizedPEMBlock(data, PEMBlockP256MLKEM768PrivateKey, P256MLKEM768PrivateKeySize)
+}
+
+func P384MLKEM1024PubKeyFromPem(data []byte) ([]byte, error) {
+ return decodeSizedPEMBlock(data, PEMBlockP384MLKEM1024PublicKey, P384MLKEM1024PublicKeySize)
+}
+
+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, defaultXWingSalt(), nil)
+}
+
+func NewSaltedP256MLKEM768Decryptor(privateKey, salt, info []byte) (*HybridNISTDecryptor, error) {
+ return newHybridNISTDecryptor(&p256mlkem768Params, privateKey, salt, info)
+}
+
+func NewP384MLKEM1024Decryptor(privateKey []byte) (*HybridNISTDecryptor, error) {
+ return NewSaltedP384MLKEM1024Decryptor(privateKey, defaultXWingSalt(), 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)
+}
+
+func P256MLKEM768WrapDEK(publicKeyRaw, dek []byte) ([]byte, error) {
+ return hybridNISTWrapDEK(&p256mlkem768Params, publicKeyRaw, dek, defaultXWingSalt(), nil)
+}
+
+func P256MLKEM768UnwrapDEK(privateKeyRaw, wrappedDER []byte) ([]byte, error) {
+ return hybridNISTUnwrapDEK(&p256mlkem768Params, privateKeyRaw, wrappedDER, defaultXWingSalt(), nil)
+}
+
+func P384MLKEM1024WrapDEK(publicKeyRaw, dek []byte) ([]byte, error) {
+ return hybridNISTWrapDEK(&p384mlkem1024Params, publicKeyRaw, dek, defaultXWingSalt(), nil)
+}
+
+func P384MLKEM1024UnwrapDEK(privateKeyRaw, wrappedDER []byte) ([]byte, error) {
+ return hybridNISTUnwrapDEK(&p384mlkem1024Params, privateKeyRaw, wrappedDER, defaultXWingSalt(), 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
+ mlkemSecret, mlkemCt, err := p.mlkemEncapsulate(mlkemPubBytes)
+ if err != nil {
+ return nil, nil, fmt.Errorf("ML-KEM encapsulate failed: %w", err)
+ }
+
+ // 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
+ mlkemSecret, err := p.mlkemDecapsulate(mlkemPrivBytes, mlkemCtBytes)
+ 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 = defaultXWingSalt()
+ }
+
+ 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
+}
diff --git a/lib/ocrypto/hybrid_nist_test.go b/lib/ocrypto/hybrid_nist_test.go
new file mode 100644
index 0000000000..557fb7639e
--- /dev/null
+++ b/lib/ocrypto/hybrid_nist_test.go
@@ -0,0 +1,235 @@
+package ocrypto
+
+import (
+ "encoding/asn1"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestP256MLKEM768KeyPairAndPEM(t *testing.T) {
+ keyPair, err := NewP256MLKEM768KeyPair()
+ require.NoError(t, err)
+
+ publicPEM, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+ privatePEM, err := keyPair.PrivateKeyInPemFormat()
+ require.NoError(t, err)
+
+ publicKey, err := P256MLKEM768PubKeyFromPem([]byte(publicPEM))
+ require.NoError(t, err)
+ privateKey, err := P256MLKEM768PrivateKeyFromPem([]byte(privatePEM))
+ require.NoError(t, err)
+
+ assert.Len(t, publicKey, P256MLKEM768PublicKeySize)
+ assert.Len(t, privateKey, P256MLKEM768PrivateKeySize)
+ assert.Equal(t, HybridSecp256r1MLKEM768Key, keyPair.GetKeyType())
+}
+
+func TestP384MLKEM1024KeyPairAndPEM(t *testing.T) {
+ keyPair, err := NewP384MLKEM1024KeyPair()
+ require.NoError(t, err)
+
+ publicPEM, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+ privatePEM, err := keyPair.PrivateKeyInPemFormat()
+ require.NoError(t, err)
+
+ publicKey, err := P384MLKEM1024PubKeyFromPem([]byte(publicPEM))
+ require.NoError(t, err)
+ privateKey, err := P384MLKEM1024PrivateKeyFromPem([]byte(privatePEM))
+ require.NoError(t, err)
+
+ assert.Len(t, publicKey, P384MLKEM1024PublicKeySize)
+ assert.Len(t, privateKey, P384MLKEM1024PrivateKeySize)
+ assert.Equal(t, HybridSecp384r1MLKEM1024Key, keyPair.GetKeyType())
+}
+
+func TestNewKeyPairP256MLKEM768(t *testing.T) {
+ keyPair, err := NewP256MLKEM768KeyPair()
+ require.NoError(t, err)
+ assert.Equal(t, HybridSecp256r1MLKEM768Key, keyPair.GetKeyType())
+}
+
+func TestNewKeyPairP384MLKEM1024(t *testing.T) {
+ keyPair, err := NewP384MLKEM1024KeyPair()
+ require.NoError(t, err)
+ assert.Equal(t, HybridSecp384r1MLKEM1024Key, keyPair.GetKeyType())
+}
+
+func TestP256MLKEM768WrapUnwrapRoundTrip(t *testing.T) {
+ keyPair, err := NewP256MLKEM768KeyPair()
+ require.NoError(t, err)
+
+ dek := []byte("0123456789abcdef0123456789abcdef")
+ wrapped, err := P256MLKEM768WrapDEK(keyPair.publicKey, dek)
+ require.NoError(t, err)
+
+ plaintext, err := P256MLKEM768UnwrapDEK(keyPair.privateKey, wrapped)
+ require.NoError(t, err)
+ assert.Equal(t, dek, plaintext)
+}
+
+func TestP384MLKEM1024WrapUnwrapRoundTrip(t *testing.T) {
+ keyPair, err := NewP384MLKEM1024KeyPair()
+ require.NoError(t, err)
+
+ dek := []byte("0123456789abcdef0123456789abcdef")
+ wrapped, err := P384MLKEM1024WrapDEK(keyPair.publicKey, dek)
+ require.NoError(t, err)
+
+ plaintext, err := P384MLKEM1024UnwrapDEK(keyPair.privateKey, wrapped)
+ require.NoError(t, err)
+ assert.Equal(t, dek, plaintext)
+}
+
+func TestP256MLKEM768WrapUnwrapWrongKeyFails(t *testing.T) {
+ keyPair, err := NewP256MLKEM768KeyPair()
+ require.NoError(t, err)
+ wrongKeyPair, err := NewP256MLKEM768KeyPair()
+ require.NoError(t, err)
+
+ wrapped, err := P256MLKEM768WrapDEK(keyPair.publicKey, []byte("top secret dek"))
+ require.NoError(t, err)
+
+ _, err = P256MLKEM768UnwrapDEK(wrongKeyPair.privateKey, wrapped)
+ require.Error(t, err)
+}
+
+func TestP384MLKEM1024WrapUnwrapWrongKeyFails(t *testing.T) {
+ keyPair, err := NewP384MLKEM1024KeyPair()
+ require.NoError(t, err)
+ wrongKeyPair, err := NewP384MLKEM1024KeyPair()
+ require.NoError(t, err)
+
+ wrapped, err := P384MLKEM1024WrapDEK(keyPair.publicKey, []byte("top secret dek"))
+ require.NoError(t, err)
+
+ _, err = P384MLKEM1024UnwrapDEK(wrongKeyPair.privateKey, wrapped)
+ require.Error(t, err)
+}
+
+func TestHybridNISTWrappedKeyASN1RoundTrip(t *testing.T) {
+ original := HybridNISTWrappedKey{
+ HybridCiphertext: []byte("hybrid-ciphertext-data"),
+ EncryptedDEK: []byte("encrypted-dek-data"),
+ }
+
+ der, err := asn1.Marshal(original)
+ require.NoError(t, err)
+
+ var decoded HybridNISTWrappedKey
+ rest, err := asn1.Unmarshal(der, &decoded)
+ require.NoError(t, err)
+ assert.Empty(t, rest)
+ assert.Equal(t, original, decoded)
+}
+
+func TestP256MLKEM768PEMDispatch(t *testing.T) {
+ keyPair, err := NewP256MLKEM768KeyPair()
+ require.NoError(t, err)
+
+ publicPEM, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+ privatePEM, err := keyPair.PrivateKeyInPemFormat()
+ require.NoError(t, err)
+
+ encryptor, err := FromPublicPEMWithSalt(publicPEM, []byte("salt"), []byte("info"))
+ require.NoError(t, err)
+
+ 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())
+
+ metadata, err := nistEncryptor.Metadata()
+ require.NoError(t, err)
+ assert.Empty(t, metadata)
+
+ nistDecryptor, ok := decryptor.(*HybridNISTDecryptor)
+ require.True(t, ok)
+
+ wrapped, err := nistEncryptor.Encrypt([]byte("dispatch-dek"))
+ require.NoError(t, err)
+
+ plaintext, err := nistDecryptor.Decrypt(wrapped)
+ require.NoError(t, err)
+ assert.Equal(t, []byte("dispatch-dek"), plaintext)
+}
+
+func TestP384MLKEM1024PEMDispatch(t *testing.T) {
+ keyPair, err := NewP384MLKEM1024KeyPair()
+ require.NoError(t, err)
+
+ publicPEM, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+ privatePEM, err := keyPair.PrivateKeyInPemFormat()
+ require.NoError(t, err)
+
+ encryptor, err := FromPublicPEMWithSalt(publicPEM, []byte("salt"), []byte("info"))
+ require.NoError(t, err)
+
+ 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)
+
+ wrapped, err := nistEncryptor.Encrypt([]byte("dispatch-dek-384"))
+ require.NoError(t, err)
+
+ plaintext, err := nistDecryptor.Decrypt(wrapped)
+ require.NoError(t, err)
+ assert.Equal(t, []byte("dispatch-dek-384"), plaintext)
+}
+
+func TestP256MLKEM768Encapsulate(t *testing.T) {
+ keyPair, err := NewP256MLKEM768KeyPair()
+ require.NoError(t, err)
+
+ pubKey, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+
+ pubKeyRaw, err := P256MLKEM768PubKeyFromPem([]byte(pubKey))
+ require.NoError(t, err)
+
+ combinedSecret, hybridCt, err := P256MLKEM768Encapsulate(pubKeyRaw)
+ require.NoError(t, err)
+ assert.NotEmpty(t, combinedSecret)
+ assert.NotEmpty(t, hybridCt)
+}
+
+func TestP384MLKEM1024Encapsulate(t *testing.T) {
+ keyPair, err := NewP384MLKEM1024KeyPair()
+ require.NoError(t, err)
+
+ pubKey, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+
+ pubKeyRaw, err := P384MLKEM1024PubKeyFromPem([]byte(pubKey))
+ require.NoError(t, err)
+
+ combinedSecret, hybridCt, err := P384MLKEM1024Encapsulate(pubKeyRaw)
+ require.NoError(t, err)
+ assert.NotEmpty(t, combinedSecret)
+ assert.NotEmpty(t, hybridCt)
+}
+
+func TestIsHybridKeyTypeIncludesNewTypes(t *testing.T) {
+ assert.True(t, IsHybridKeyType(HybridXWingKey))
+ assert.True(t, IsHybridKeyType(HybridSecp256r1MLKEM768Key))
+ assert.True(t, IsHybridKeyType(HybridSecp384r1MLKEM1024Key))
+ assert.False(t, IsHybridKeyType(EC256Key))
+ assert.False(t, IsHybridKeyType(RSA2048Key))
+}
diff --git a/lib/ocrypto/xwing.go b/lib/ocrypto/xwing.go
new file mode 100644
index 0000000000..93bd8c5f29
--- /dev/null
+++ b/lib/ocrypto/xwing.go
@@ -0,0 +1,289 @@
+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 (
+ HybridXWingKey KeyType = "hpqt:xwing"
+
+ XWingPublicKeySize = xwing.PublicKeySize
+ XWingPrivateKeySize = xwing.PrivateKeySize
+ XWingCiphertextSize = xwing.CiphertextSize
+
+ PEMBlockXWingPublicKey = "XWING PUBLIC KEY"
+ 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 {
+ return XWingKeyPair{}, fmt.Errorf("xwing.GenerateKeyPair failed: %w", err)
+ }
+
+ publicKey := make([]byte, XWingPublicKeySize)
+ privateKey := make([]byte, XWingPrivateKeySize)
+ pk.Pack(publicKey)
+ sk.Pack(privateKey)
+
+ return XWingKeyPair{
+ publicKey: publicKey,
+ privateKey: privateKey,
+ }, nil
+}
+
+func (k XWingKeyPair) PublicKeyInPemFormat() (string, error) {
+ return rawToPEM(PEMBlockXWingPublicKey, k.publicKey, XWingPublicKeySize)
+}
+
+func (k XWingKeyPair) PrivateKeyInPemFormat() (string, error) {
+ return rawToPEM(PEMBlockXWingPrivateKey, k.privateKey, XWingPrivateKeySize)
+}
+
+func (k XWingKeyPair) GetKeyType() KeyType {
+ return HybridXWingKey
+}
+
+func XWingPubKeyFromPem(data []byte) ([]byte, error) {
+ return decodeSizedPEMBlock(data, PEMBlockXWingPublicKey, XWingPublicKeySize)
+}
+
+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, defaultXWingSalt(), 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)
+}
+
+func XWingWrapDEK(publicKeyRaw, dek []byte) ([]byte, error) {
+ return xwingWrapDEK(publicKeyRaw, dek, defaultXWingSalt(), nil)
+}
+
+func XWingUnwrapDEK(privateKeyRaw, wrappedDER []byte) ([]byte, error) {
+ return xwingUnwrapDEK(privateKeyRaw, wrappedDER, defaultXWingSalt(), 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 = defaultXWingSalt()
+ }
+
+ 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 rawToPEM(blockType string, raw []byte, expectedSize int) (string, error) {
+ if len(raw) != expectedSize {
+ return "", fmt.Errorf("invalid %s size: got %d want %d", blockType, len(raw), expectedSize)
+ }
+
+ pemBytes := pem.EncodeToMemory(&pem.Block{
+ Type: blockType,
+ Bytes: raw,
+ })
+ if pemBytes == nil {
+ return "", fmt.Errorf("failed to encode %s to PEM", blockType)
+ }
+
+ return string(pemBytes), 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
+}
+
+func defaultXWingSalt() []byte {
+ digest := sha256.New()
+ digest.Write([]byte("TDF"))
+ return digest.Sum(nil)
+}
+
+func cloneOrNil(data []byte) []byte {
+ if len(data) == 0 {
+ return nil
+ }
+ return append([]byte(nil), data...)
+}
diff --git a/lib/ocrypto/xwing_test.go b/lib/ocrypto/xwing_test.go
new file mode 100644
index 0000000000..c0bf783ba9
--- /dev/null
+++ b/lib/ocrypto/xwing_test.go
@@ -0,0 +1,129 @@
+package ocrypto
+
+import (
+ "encoding/asn1"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestXWingKeyPairAndPEM(t *testing.T) {
+ keyPair, err := NewXWingKeyPair()
+ require.NoError(t, err)
+
+ publicPEM, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+ privatePEM, err := keyPair.PrivateKeyInPemFormat()
+ require.NoError(t, err)
+
+ publicKey, err := XWingPubKeyFromPem([]byte(publicPEM))
+ require.NoError(t, err)
+ privateKey, err := XWingPrivateKeyFromPem([]byte(privatePEM))
+ require.NoError(t, err)
+
+ assert.Len(t, publicKey, XWingPublicKeySize)
+ assert.Len(t, privateKey, XWingPrivateKeySize)
+ assert.Equal(t, HybridXWingKey, keyPair.GetKeyType())
+}
+
+func TestNewKeyPairXWing(t *testing.T) {
+ keyPair, err := NewXWingKeyPair()
+ require.NoError(t, err)
+ assert.Equal(t, HybridXWingKey, keyPair.GetKeyType())
+}
+
+func TestXWingWrapUnwrapRoundTrip(t *testing.T) {
+ keyPair, err := NewXWingKeyPair()
+ require.NoError(t, err)
+
+ dek := []byte("0123456789abcdef0123456789abcdef")
+ wrapped, err := XWingWrapDEK(keyPair.publicKey, dek)
+ require.NoError(t, err)
+
+ plaintext, err := XWingUnwrapDEK(keyPair.privateKey, wrapped)
+ require.NoError(t, err)
+ assert.Equal(t, dek, plaintext)
+}
+
+func TestXWingWrapUnwrapWrongKeyFails(t *testing.T) {
+ keyPair, err := NewXWingKeyPair()
+ require.NoError(t, err)
+ wrongKeyPair, err := NewXWingKeyPair()
+ require.NoError(t, err)
+
+ wrapped, err := XWingWrapDEK(keyPair.publicKey, []byte("top secret dek"))
+ require.NoError(t, err)
+
+ _, err = XWingUnwrapDEK(wrongKeyPair.privateKey, wrapped)
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "AES-GCM decrypt failed")
+}
+
+func TestXWingWrappedKeyASN1RoundTrip(t *testing.T) {
+ original := XWingWrappedKey{
+ XWingCiphertext: []byte("ciphertext"),
+ EncryptedDEK: []byte("encrypted-dek"),
+ }
+
+ der, err := asn1.Marshal(original)
+ require.NoError(t, err)
+
+ var decoded XWingWrappedKey
+ rest, err := asn1.Unmarshal(der, &decoded)
+ require.NoError(t, err)
+ assert.Empty(t, rest)
+ assert.Equal(t, original, decoded)
+}
+
+func TestXWingPEMDispatch(t *testing.T) {
+ keyPair, err := NewXWingKeyPair()
+ require.NoError(t, err)
+
+ publicPEM, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+ privatePEM, err := keyPair.PrivateKeyInPemFormat()
+ require.NoError(t, err)
+
+ encryptor, err := FromPublicPEMWithSalt(publicPEM, []byte("salt"), []byte("info"))
+ require.NoError(t, err)
+
+ 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())
+
+ metadata, err := xwingEncryptor.Metadata()
+ require.NoError(t, err)
+ assert.Empty(t, metadata)
+
+ xwingDecryptor, ok := decryptor.(*XWingDecryptor)
+ require.True(t, ok)
+
+ wrapped, err := xwingEncryptor.Encrypt([]byte("dispatch-dek"))
+ require.NoError(t, err)
+
+ plaintext, err := xwingDecryptor.Decrypt(wrapped)
+ require.NoError(t, err)
+ assert.Equal(t, []byte("dispatch-dek"), plaintext)
+}
+
+func TestXWingEncapsulate(t *testing.T) {
+ keyPair, err := NewXWingKeyPair()
+ require.NoError(t, err)
+
+ sharedSecret, ciphertext, err := XWingEncapsulate(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"))
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "invalid X-Wing public key size")
+}
diff --git a/opentdf-dev.yaml b/opentdf-dev.yaml
index 93a471101f..d44cf0772f 100644
--- a/opentdf-dev.yaml
+++ b/opentdf-dev.yaml
@@ -21,7 +21,8 @@ services:
kas:
registered_kas_uri: http://localhost:8080 # Should match what you have registered for *this* KAS in the policy db.
preview:
- ec_tdf_enabled: false
+ ec_tdf_enabled: true
+ hybrid_tdf_enabled: true
key_management: false
root_key: a8c4824daafcfa38ed0d13002e92b08720e6c4fcee67d52e954c1a6e045907d1 # For local development testing only
keyring:
@@ -35,6 +36,12 @@ services:
- kid: r1
alg: rsa:2048
legacy: true
+ - kid: x1
+ alg: hpqt:xwing
+ - kid: h1
+ alg: hpqt:secp256r1-mlkem768
+ - kid: h2
+ alg: hpqt:secp384r1-mlkem1024
entityresolution:
log_level: info
url: http://localhost:8888/auth
@@ -183,4 +190,16 @@ server:
alg: ec:secp256r1
private: kas-ec-private.pem
cert: kas-ec-cert.pem
+ - kid: x1
+ alg: hpqt:xwing
+ private: kas-xwing-private.pem
+ cert: kas-xwing-public.pem
+ - kid: h1
+ alg: hpqt:secp256r1-mlkem768
+ private: kas-p256mlkem768-private.pem
+ cert: kas-p256mlkem768-public.pem
+ - kid: h2
+ alg: hpqt:secp384r1-mlkem1024
+ private: kas-p384mlkem1024-private.pem
+ cert: kas-p384mlkem1024-public.pem
port: 8080
diff --git a/opentdf-example.yaml b/opentdf-example.yaml
index a0b97da826..9bc9f90ef2 100644
--- a/opentdf-example.yaml
+++ b/opentdf-example.yaml
@@ -123,4 +123,16 @@ server:
alg: ec:secp256r1
private: /keys/kas-ec-private.pem
cert: /keys/kas-ec-cert.pem
+ - kid: x1
+ alg: hpqt:xwing
+ private: /keys/kas-xwing-private.pem
+ cert: /keys/kas-xwing-public.pem
+ - kid: h1
+ alg: hpqt:secp256r1-mlkem768
+ private: /keys/kas-p256mlkem768-private.pem
+ cert: /keys/kas-p256mlkem768-public.pem
+ - kid: h2
+ alg: hpqt:secp384r1-mlkem1024
+ private: /keys/kas-p384mlkem1024-private.pem
+ cert: /keys/kas-p384mlkem1024-public.pem
port: 8080
diff --git a/opentdf-kas-mode.yaml b/opentdf-kas-mode.yaml
index ebcfb6f0c2..4bdd67e376 100644
--- a/opentdf-kas-mode.yaml
+++ b/opentdf-kas-mode.yaml
@@ -33,6 +33,12 @@ services:
- kid: r1
alg: rsa:2048
legacy: true
+ - kid: x1
+ alg: hpqt:xwing
+ - kid: h1
+ alg: hpqt:secp256r1-mlkem768
+ - kid: h2
+ alg: hpqt:secp384r1-mlkem1024
server:
public_hostname: localhost
tls:
@@ -123,4 +129,16 @@ server:
alg: ec:secp256r1
private: kas-ec-private.pem
cert: kas-ec-cert.pem
+ - kid: x1
+ alg: hpqt:xwing
+ private: kas-xwing-private.pem
+ cert: kas-xwing-public.pem
+ - kid: h1
+ alg: hpqt:secp256r1-mlkem768
+ private: kas-p256mlkem768-private.pem
+ cert: kas-p256mlkem768-public.pem
+ - kid: h2
+ alg: hpqt:secp384r1-mlkem1024
+ private: kas-p384mlkem1024-private.pem
+ cert: kas-p384mlkem1024-public.pem
port: 8181
diff --git a/protocol/go/kas/kas.pb.go b/protocol/go/kas/kas.pb.go
index 6d6fb574e3..a6ec21ddb1 100644
--- a/protocol/go/kas/kas.pb.go
+++ b/protocol/go/kas/kas.pb.go
@@ -7,14 +7,15 @@
package kas
import (
+ reflect "reflect"
+ sync "sync"
+
_ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options"
_ "google.golang.org/genproto/googleapis/api/annotations"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
structpb "google.golang.org/protobuf/types/known/structpb"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
- reflect "reflect"
- sync "sync"
)
const (
@@ -244,7 +245,7 @@ type KeyAccess struct {
Protocol string `protobuf:"bytes,3,opt,name=protocol,proto3" json:"protocol,omitempty"`
// Type of key wrapping used for the data encryption key
// Required: Always
- // Values: 'wrapped' (RSA-wrapped for ZTDF), 'ec-wrapped' (experimental ECDH-wrapped)
+ // Values: 'wrapped' (RSA-wrapped for ZTDF), 'ec-wrapped' (experimental ECDH-wrapped), 'hybrid-wrapped' (experimental X-Wing-wrapped)
KeyType string `protobuf:"bytes,4,opt,name=key_type,json=type,proto3" json:"key_type,omitempty"`
// URL of the Key Access Server that can unwrap this key
// Optional: May be omitted if KAS URL is known from context
@@ -271,7 +272,7 @@ type KeyAccess struct {
Header []byte `protobuf:"bytes,9,opt,name=header,proto3" json:"header,omitempty"`
// Ephemeral public key for ECDH key derivation (ec-wrapped type only)
// Required: When key_type="ec-wrapped" (experimental ECDH-based ZTDF)
- // Omitted: When key_type="wrapped" (RSA-based ZTDF)
+ // Omitted: When key_type="wrapped" or key_type="hybrid-wrapped"
// Should be a PEM-encoded PKCS#8 (ASN.1) formatted public key
// Used to derive the symmetric key for unwrapping the DEK
EphemeralPublicKey string `protobuf:"bytes,10,opt,name=ephemeral_public_key,json=ephemeralPublicKey,proto3" json:"ephemeral_public_key,omitempty"`
@@ -856,7 +857,7 @@ type RewrapResponse struct {
EntityWrappedKey []byte `protobuf:"bytes,2,opt,name=entity_wrapped_key,json=entityWrappedKey,proto3" json:"entity_wrapped_key,omitempty"`
// KAS's ephemeral session public key in PEM format
// Required: For EC-based operations (key_type="ec-wrapped")
- // Optional: Empty for RSA-based ZTDF (key_type="wrapped")
+ // Optional: Empty for RSA-based or X-Wing-based ZTDF (key_type="wrapped" or key_type="hybrid-wrapped")
// Used by client to perform ECDH key agreement and decrypt the kas_wrapped_key values
SessionPublicKey string `protobuf:"bytes,3,opt,name=session_public_key,json=sessionPublicKey,proto3" json:"session_public_key,omitempty"`
// Deprecated: Legacy schema version identifier
@@ -1344,28 +1345,30 @@ func file_kas_kas_proto_rawDescGZIP() []byte {
return file_kas_kas_proto_rawDescData
}
-var file_kas_kas_proto_msgTypes = make([]protoimpl.MessageInfo, 17)
-var file_kas_kas_proto_goTypes = []interface{}{
- (*InfoRequest)(nil), // 0: kas.InfoRequest
- (*InfoResponse)(nil), // 1: kas.InfoResponse
- (*LegacyPublicKeyRequest)(nil), // 2: kas.LegacyPublicKeyRequest
- (*PolicyBinding)(nil), // 3: kas.PolicyBinding
- (*KeyAccess)(nil), // 4: kas.KeyAccess
- (*UnsignedRewrapRequest)(nil), // 5: kas.UnsignedRewrapRequest
- (*PublicKeyRequest)(nil), // 6: kas.PublicKeyRequest
- (*PublicKeyResponse)(nil), // 7: kas.PublicKeyResponse
- (*RewrapRequest)(nil), // 8: kas.RewrapRequest
- (*KeyAccessRewrapResult)(nil), // 9: kas.KeyAccessRewrapResult
- (*PolicyRewrapResult)(nil), // 10: kas.PolicyRewrapResult
- (*RewrapResponse)(nil), // 11: kas.RewrapResponse
- (*UnsignedRewrapRequest_WithPolicy)(nil), // 12: kas.UnsignedRewrapRequest.WithPolicy
- (*UnsignedRewrapRequest_WithKeyAccessObject)(nil), // 13: kas.UnsignedRewrapRequest.WithKeyAccessObject
- (*UnsignedRewrapRequest_WithPolicyRequest)(nil), // 14: kas.UnsignedRewrapRequest.WithPolicyRequest
- nil, // 15: kas.KeyAccessRewrapResult.MetadataEntry
- nil, // 16: kas.RewrapResponse.MetadataEntry
- (*structpb.Value)(nil), // 17: google.protobuf.Value
- (*wrapperspb.StringValue)(nil), // 18: google.protobuf.StringValue
-}
+var (
+ file_kas_kas_proto_msgTypes = make([]protoimpl.MessageInfo, 17)
+ file_kas_kas_proto_goTypes = []interface{}{
+ (*InfoRequest)(nil), // 0: kas.InfoRequest
+ (*InfoResponse)(nil), // 1: kas.InfoResponse
+ (*LegacyPublicKeyRequest)(nil), // 2: kas.LegacyPublicKeyRequest
+ (*PolicyBinding)(nil), // 3: kas.PolicyBinding
+ (*KeyAccess)(nil), // 4: kas.KeyAccess
+ (*UnsignedRewrapRequest)(nil), // 5: kas.UnsignedRewrapRequest
+ (*PublicKeyRequest)(nil), // 6: kas.PublicKeyRequest
+ (*PublicKeyResponse)(nil), // 7: kas.PublicKeyResponse
+ (*RewrapRequest)(nil), // 8: kas.RewrapRequest
+ (*KeyAccessRewrapResult)(nil), // 9: kas.KeyAccessRewrapResult
+ (*PolicyRewrapResult)(nil), // 10: kas.PolicyRewrapResult
+ (*RewrapResponse)(nil), // 11: kas.RewrapResponse
+ (*UnsignedRewrapRequest_WithPolicy)(nil), // 12: kas.UnsignedRewrapRequest.WithPolicy
+ (*UnsignedRewrapRequest_WithKeyAccessObject)(nil), // 13: kas.UnsignedRewrapRequest.WithKeyAccessObject
+ (*UnsignedRewrapRequest_WithPolicyRequest)(nil), // 14: kas.UnsignedRewrapRequest.WithPolicyRequest
+ nil, // 15: kas.KeyAccessRewrapResult.MetadataEntry
+ nil, // 16: kas.RewrapResponse.MetadataEntry
+ (*structpb.Value)(nil), // 17: google.protobuf.Value
+ (*wrapperspb.StringValue)(nil), // 18: google.protobuf.StringValue
+ }
+)
var file_kas_kas_proto_depIdxs = []int32{
3, // 0: kas.KeyAccess.policy_binding:type_name -> kas.PolicyBinding
14, // 1: kas.UnsignedRewrapRequest.requests:type_name -> kas.UnsignedRewrapRequest.WithPolicyRequest
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 8e5c7b58b5..fed7623120 100644
--- a/protocol/go/policy/kasregistry/key_access_server_registry.pb.go
+++ b/protocol/go/policy/kasregistry/key_access_server_registry.pb.go
@@ -7,14 +7,15 @@
package kasregistry
import (
+ reflect "reflect"
+ sync "sync"
+
_ "buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate"
common "github.com/opentdf/platform/protocol/go/common"
policy "github.com/opentdf/platform/protocol/go/policy"
_ "google.golang.org/genproto/googleapis/api/annotations"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
)
const (
@@ -4012,248 +4013,52 @@ var file_policy_kasregistry_key_access_server_registry_proto_rawDesc = []byte{
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, 0x3a, 0x02, 0x18, 0x01, 0x22, 0xcc, 0x0c, 0x0a, 0x10, 0x43,
+ 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x02, 0x18, 0x01, 0x22, 0xcf, 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, 0xa4, 0x01, 0x0a, 0x0d, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74,
+ 0x12, 0xa7, 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, 0x6c, 0xba, 0x48, 0x69,
- 0xba, 0x01, 0x66, 0x0a, 0x15, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74,
+ 0x79, 0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x42, 0x6f, 0xba, 0x48, 0x6c,
+ 0xba, 0x01, 0x69, 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, 0x17, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x5b, 0x31, 0x2c, 0x20, 0x32, 0x2c,
- 0x20, 0x33, 0x2c, 0x20, 0x34, 0x2c, 0x20, 0x35, 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,
+ 0x1a, 0x1a, 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, 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,
- 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, 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, 0x96,
- 0x03, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
- 0x73, 0x74, 0x12, 0xa7, 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, 0x6f, 0xba,
- 0x48, 0x6c, 0xba, 0x01, 0x69, 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, 0x1a, 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, 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, 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, 0xe5, 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, 0xcf, 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, 0x9d, 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, 0x6c, 0xba,
- 0x48, 0x69, 0xba, 0x01, 0x66, 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, 0x17, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x5b, 0x31, 0x2c, 0x20,
- 0x32, 0x2c, 0x20, 0x33, 0x2c, 0x20, 0x34, 0x2c, 0x20, 0x35, 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,
@@ -4264,277 +4069,474 @@ var file_policy_kasregistry_key_access_server_registry_proto_rawDesc = []byte{
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,
+ 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, 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,
+ 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, 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,
+ 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,
- 0xb5, 0x03, 0x0a, 0x26, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e,
+ 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, 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,
+ 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, 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, 0x99, 0x03, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xaa, 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, 0x72, 0xba, 0x48, 0x6f, 0xba, 0x01, 0x6c, 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, 0x1d, 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, 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, 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, 0xe8, 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, 0xd2, 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, 0xa0, 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, 0x6f, 0xba, 0x48, 0x6c, 0xba, 0x01, 0x69, 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, 0x1a, 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, 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,
+ 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, 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,
+ 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, 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,
+ 0x64, 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,
+ 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, 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, 0x32, 0xb5, 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, 0x99, 0x01,
- 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, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02,
- 0x15, 0x12, 0x13, 0x2f, 0x6b, 0x65, 0x79, 0x2d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x2d, 0x73,
- 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 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, 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,
+ 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, 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,
+ 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, 0x32, 0xb5, 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, 0x99, 0x01, 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, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x6b, 0x65, 0x79,
+ 0x2d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 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,
- 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, 0x2e, 0x70,
+ 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, 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,
+ 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, 0x6b, 0x61,
+ 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,
+ 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 (
@@ -4549,77 +4551,79 @@ func file_policy_kasregistry_key_access_server_registry_proto_rawDescGZIP() []by
return file_policy_kasregistry_key_access_server_registry_proto_rawDescData
}
-var file_policy_kasregistry_key_access_server_registry_proto_msgTypes = make([]protoimpl.MessageInfo, 53)
-var file_policy_kasregistry_key_access_server_registry_proto_goTypes = []interface{}{
- (*GetKeyAccessServerRequest)(nil), // 0: policy.kasregistry.GetKeyAccessServerRequest
- (*GetKeyAccessServerResponse)(nil), // 1: policy.kasregistry.GetKeyAccessServerResponse
- (*ListKeyAccessServersRequest)(nil), // 2: policy.kasregistry.ListKeyAccessServersRequest
- (*ListKeyAccessServersResponse)(nil), // 3: policy.kasregistry.ListKeyAccessServersResponse
- (*CreateKeyAccessServerRequest)(nil), // 4: policy.kasregistry.CreateKeyAccessServerRequest
- (*CreateKeyAccessServerResponse)(nil), // 5: policy.kasregistry.CreateKeyAccessServerResponse
- (*UpdateKeyAccessServerRequest)(nil), // 6: policy.kasregistry.UpdateKeyAccessServerRequest
- (*UpdateKeyAccessServerResponse)(nil), // 7: policy.kasregistry.UpdateKeyAccessServerResponse
- (*DeleteKeyAccessServerRequest)(nil), // 8: policy.kasregistry.DeleteKeyAccessServerRequest
- (*DeleteKeyAccessServerResponse)(nil), // 9: policy.kasregistry.DeleteKeyAccessServerResponse
- (*GrantedPolicyObject)(nil), // 10: policy.kasregistry.GrantedPolicyObject
- (*KeyAccessServerGrants)(nil), // 11: policy.kasregistry.KeyAccessServerGrants
- (*CreatePublicKeyRequest)(nil), // 12: policy.kasregistry.CreatePublicKeyRequest
- (*CreatePublicKeyResponse)(nil), // 13: policy.kasregistry.CreatePublicKeyResponse
- (*GetPublicKeyRequest)(nil), // 14: policy.kasregistry.GetPublicKeyRequest
- (*GetPublicKeyResponse)(nil), // 15: policy.kasregistry.GetPublicKeyResponse
- (*ListPublicKeysRequest)(nil), // 16: policy.kasregistry.ListPublicKeysRequest
- (*ListPublicKeysResponse)(nil), // 17: policy.kasregistry.ListPublicKeysResponse
- (*ListPublicKeyMappingRequest)(nil), // 18: policy.kasregistry.ListPublicKeyMappingRequest
- (*ListPublicKeyMappingResponse)(nil), // 19: policy.kasregistry.ListPublicKeyMappingResponse
- (*UpdatePublicKeyRequest)(nil), // 20: policy.kasregistry.UpdatePublicKeyRequest
- (*UpdatePublicKeyResponse)(nil), // 21: policy.kasregistry.UpdatePublicKeyResponse
- (*DeactivatePublicKeyRequest)(nil), // 22: policy.kasregistry.DeactivatePublicKeyRequest
- (*DeactivatePublicKeyResponse)(nil), // 23: policy.kasregistry.DeactivatePublicKeyResponse
- (*ActivatePublicKeyRequest)(nil), // 24: policy.kasregistry.ActivatePublicKeyRequest
- (*ActivatePublicKeyResponse)(nil), // 25: policy.kasregistry.ActivatePublicKeyResponse
- (*ListKeyAccessServerGrantsRequest)(nil), // 26: policy.kasregistry.ListKeyAccessServerGrantsRequest
- (*ListKeyAccessServerGrantsResponse)(nil), // 27: policy.kasregistry.ListKeyAccessServerGrantsResponse
- (*CreateKeyRequest)(nil), // 28: policy.kasregistry.CreateKeyRequest
- (*CreateKeyResponse)(nil), // 29: policy.kasregistry.CreateKeyResponse
- (*GetKeyRequest)(nil), // 30: policy.kasregistry.GetKeyRequest
- (*GetKeyResponse)(nil), // 31: policy.kasregistry.GetKeyResponse
- (*ListKeysRequest)(nil), // 32: policy.kasregistry.ListKeysRequest
- (*ListKeysResponse)(nil), // 33: policy.kasregistry.ListKeysResponse
- (*UpdateKeyRequest)(nil), // 34: policy.kasregistry.UpdateKeyRequest
- (*UpdateKeyResponse)(nil), // 35: policy.kasregistry.UpdateKeyResponse
- (*KasKeyIdentifier)(nil), // 36: policy.kasregistry.KasKeyIdentifier
- (*RotateKeyRequest)(nil), // 37: policy.kasregistry.RotateKeyRequest
- (*ChangeMappings)(nil), // 38: policy.kasregistry.ChangeMappings
- (*RotatedResources)(nil), // 39: policy.kasregistry.RotatedResources
- (*RotateKeyResponse)(nil), // 40: policy.kasregistry.RotateKeyResponse
- (*SetBaseKeyRequest)(nil), // 41: policy.kasregistry.SetBaseKeyRequest
- (*GetBaseKeyRequest)(nil), // 42: policy.kasregistry.GetBaseKeyRequest
- (*GetBaseKeyResponse)(nil), // 43: policy.kasregistry.GetBaseKeyResponse
- (*SetBaseKeyResponse)(nil), // 44: policy.kasregistry.SetBaseKeyResponse
- (*MappedPolicyObject)(nil), // 45: policy.kasregistry.MappedPolicyObject
- (*KeyMapping)(nil), // 46: policy.kasregistry.KeyMapping
- (*ListKeyMappingsRequest)(nil), // 47: policy.kasregistry.ListKeyMappingsRequest
- (*ListKeyMappingsResponse)(nil), // 48: policy.kasregistry.ListKeyMappingsResponse
- (*ListPublicKeyMappingResponse_PublicKeyMapping)(nil), // 49: policy.kasregistry.ListPublicKeyMappingResponse.PublicKeyMapping
- (*ListPublicKeyMappingResponse_PublicKey)(nil), // 50: policy.kasregistry.ListPublicKeyMappingResponse.PublicKey
- (*ListPublicKeyMappingResponse_Association)(nil), // 51: policy.kasregistry.ListPublicKeyMappingResponse.Association
- (*RotateKeyRequest_NewKey)(nil), // 52: policy.kasregistry.RotateKeyRequest.NewKey
- (*policy.KeyAccessServer)(nil), // 53: policy.KeyAccessServer
- (*policy.PageRequest)(nil), // 54: policy.PageRequest
- (*policy.PageResponse)(nil), // 55: policy.PageResponse
- (*policy.PublicKey)(nil), // 56: policy.PublicKey
- (policy.SourceType)(0), // 57: policy.SourceType
- (*common.MetadataMutable)(nil), // 58: common.MetadataMutable
- (common.MetadataUpdateEnum)(0), // 59: common.MetadataUpdateEnum
- (*policy.KasPublicKey)(nil), // 60: policy.KasPublicKey
- (*policy.Key)(nil), // 61: policy.Key
- (policy.Algorithm)(0), // 62: policy.Algorithm
- (policy.KeyMode)(0), // 63: policy.KeyMode
- (*policy.PublicKeyCtx)(nil), // 64: policy.PublicKeyCtx
- (*policy.PrivateKeyCtx)(nil), // 65: policy.PrivateKeyCtx
- (*policy.KasKey)(nil), // 66: policy.KasKey
- (*policy.SimpleKasKey)(nil), // 67: policy.SimpleKasKey
-}
+var (
+ file_policy_kasregistry_key_access_server_registry_proto_msgTypes = make([]protoimpl.MessageInfo, 53)
+ file_policy_kasregistry_key_access_server_registry_proto_goTypes = []interface{}{
+ (*GetKeyAccessServerRequest)(nil), // 0: policy.kasregistry.GetKeyAccessServerRequest
+ (*GetKeyAccessServerResponse)(nil), // 1: policy.kasregistry.GetKeyAccessServerResponse
+ (*ListKeyAccessServersRequest)(nil), // 2: policy.kasregistry.ListKeyAccessServersRequest
+ (*ListKeyAccessServersResponse)(nil), // 3: policy.kasregistry.ListKeyAccessServersResponse
+ (*CreateKeyAccessServerRequest)(nil), // 4: policy.kasregistry.CreateKeyAccessServerRequest
+ (*CreateKeyAccessServerResponse)(nil), // 5: policy.kasregistry.CreateKeyAccessServerResponse
+ (*UpdateKeyAccessServerRequest)(nil), // 6: policy.kasregistry.UpdateKeyAccessServerRequest
+ (*UpdateKeyAccessServerResponse)(nil), // 7: policy.kasregistry.UpdateKeyAccessServerResponse
+ (*DeleteKeyAccessServerRequest)(nil), // 8: policy.kasregistry.DeleteKeyAccessServerRequest
+ (*DeleteKeyAccessServerResponse)(nil), // 9: policy.kasregistry.DeleteKeyAccessServerResponse
+ (*GrantedPolicyObject)(nil), // 10: policy.kasregistry.GrantedPolicyObject
+ (*KeyAccessServerGrants)(nil), // 11: policy.kasregistry.KeyAccessServerGrants
+ (*CreatePublicKeyRequest)(nil), // 12: policy.kasregistry.CreatePublicKeyRequest
+ (*CreatePublicKeyResponse)(nil), // 13: policy.kasregistry.CreatePublicKeyResponse
+ (*GetPublicKeyRequest)(nil), // 14: policy.kasregistry.GetPublicKeyRequest
+ (*GetPublicKeyResponse)(nil), // 15: policy.kasregistry.GetPublicKeyResponse
+ (*ListPublicKeysRequest)(nil), // 16: policy.kasregistry.ListPublicKeysRequest
+ (*ListPublicKeysResponse)(nil), // 17: policy.kasregistry.ListPublicKeysResponse
+ (*ListPublicKeyMappingRequest)(nil), // 18: policy.kasregistry.ListPublicKeyMappingRequest
+ (*ListPublicKeyMappingResponse)(nil), // 19: policy.kasregistry.ListPublicKeyMappingResponse
+ (*UpdatePublicKeyRequest)(nil), // 20: policy.kasregistry.UpdatePublicKeyRequest
+ (*UpdatePublicKeyResponse)(nil), // 21: policy.kasregistry.UpdatePublicKeyResponse
+ (*DeactivatePublicKeyRequest)(nil), // 22: policy.kasregistry.DeactivatePublicKeyRequest
+ (*DeactivatePublicKeyResponse)(nil), // 23: policy.kasregistry.DeactivatePublicKeyResponse
+ (*ActivatePublicKeyRequest)(nil), // 24: policy.kasregistry.ActivatePublicKeyRequest
+ (*ActivatePublicKeyResponse)(nil), // 25: policy.kasregistry.ActivatePublicKeyResponse
+ (*ListKeyAccessServerGrantsRequest)(nil), // 26: policy.kasregistry.ListKeyAccessServerGrantsRequest
+ (*ListKeyAccessServerGrantsResponse)(nil), // 27: policy.kasregistry.ListKeyAccessServerGrantsResponse
+ (*CreateKeyRequest)(nil), // 28: policy.kasregistry.CreateKeyRequest
+ (*CreateKeyResponse)(nil), // 29: policy.kasregistry.CreateKeyResponse
+ (*GetKeyRequest)(nil), // 30: policy.kasregistry.GetKeyRequest
+ (*GetKeyResponse)(nil), // 31: policy.kasregistry.GetKeyResponse
+ (*ListKeysRequest)(nil), // 32: policy.kasregistry.ListKeysRequest
+ (*ListKeysResponse)(nil), // 33: policy.kasregistry.ListKeysResponse
+ (*UpdateKeyRequest)(nil), // 34: policy.kasregistry.UpdateKeyRequest
+ (*UpdateKeyResponse)(nil), // 35: policy.kasregistry.UpdateKeyResponse
+ (*KasKeyIdentifier)(nil), // 36: policy.kasregistry.KasKeyIdentifier
+ (*RotateKeyRequest)(nil), // 37: policy.kasregistry.RotateKeyRequest
+ (*ChangeMappings)(nil), // 38: policy.kasregistry.ChangeMappings
+ (*RotatedResources)(nil), // 39: policy.kasregistry.RotatedResources
+ (*RotateKeyResponse)(nil), // 40: policy.kasregistry.RotateKeyResponse
+ (*SetBaseKeyRequest)(nil), // 41: policy.kasregistry.SetBaseKeyRequest
+ (*GetBaseKeyRequest)(nil), // 42: policy.kasregistry.GetBaseKeyRequest
+ (*GetBaseKeyResponse)(nil), // 43: policy.kasregistry.GetBaseKeyResponse
+ (*SetBaseKeyResponse)(nil), // 44: policy.kasregistry.SetBaseKeyResponse
+ (*MappedPolicyObject)(nil), // 45: policy.kasregistry.MappedPolicyObject
+ (*KeyMapping)(nil), // 46: policy.kasregistry.KeyMapping
+ (*ListKeyMappingsRequest)(nil), // 47: policy.kasregistry.ListKeyMappingsRequest
+ (*ListKeyMappingsResponse)(nil), // 48: policy.kasregistry.ListKeyMappingsResponse
+ (*ListPublicKeyMappingResponse_PublicKeyMapping)(nil), // 49: policy.kasregistry.ListPublicKeyMappingResponse.PublicKeyMapping
+ (*ListPublicKeyMappingResponse_PublicKey)(nil), // 50: policy.kasregistry.ListPublicKeyMappingResponse.PublicKey
+ (*ListPublicKeyMappingResponse_Association)(nil), // 51: policy.kasregistry.ListPublicKeyMappingResponse.Association
+ (*RotateKeyRequest_NewKey)(nil), // 52: policy.kasregistry.RotateKeyRequest.NewKey
+ (*policy.KeyAccessServer)(nil), // 53: policy.KeyAccessServer
+ (*policy.PageRequest)(nil), // 54: policy.PageRequest
+ (*policy.PageResponse)(nil), // 55: policy.PageResponse
+ (*policy.PublicKey)(nil), // 56: policy.PublicKey
+ (policy.SourceType)(0), // 57: policy.SourceType
+ (*common.MetadataMutable)(nil), // 58: common.MetadataMutable
+ (common.MetadataUpdateEnum)(0), // 59: common.MetadataUpdateEnum
+ (*policy.KasPublicKey)(nil), // 60: policy.KasPublicKey
+ (*policy.Key)(nil), // 61: policy.Key
+ (policy.Algorithm)(0), // 62: policy.Algorithm
+ (policy.KeyMode)(0), // 63: policy.KeyMode
+ (*policy.PublicKeyCtx)(nil), // 64: policy.PublicKeyCtx
+ (*policy.PrivateKeyCtx)(nil), // 65: policy.PrivateKeyCtx
+ (*policy.KasKey)(nil), // 66: policy.KasKey
+ (*policy.SimpleKasKey)(nil), // 67: policy.SimpleKasKey
+ }
+)
var file_policy_kasregistry_key_access_server_registry_proto_depIdxs = []int32{
53, // 0: policy.kasregistry.GetKeyAccessServerResponse.key_access_server:type_name -> policy.KeyAccessServer
54, // 1: policy.kasregistry.ListKeyAccessServersRequest.pagination:type_name -> policy.PageRequest
diff --git a/protocol/go/policy/objects.pb.go b/protocol/go/policy/objects.pb.go
index d2c0921c8b..2e58cf7c33 100644
--- a/protocol/go/policy/objects.pb.go
+++ b/protocol/go/policy/objects.pb.go
@@ -7,13 +7,14 @@
package policy
import (
+ reflect "reflect"
+ sync "sync"
+
_ "buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate"
common "github.com/opentdf/platform/protocol/go/common"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
- reflect "reflect"
- sync "sync"
)
const (
@@ -243,25 +244,34 @@ const (
KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1 KasPublicKeyAlgEnum = 5
KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1 KasPublicKeyAlgEnum = 6
KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1 KasPublicKeyAlgEnum = 7
+ 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
)
// Enum value maps for KasPublicKeyAlgEnum.
var (
KasPublicKeyAlgEnum_name = map[int32]string{
- 0: "KAS_PUBLIC_KEY_ALG_ENUM_UNSPECIFIED",
- 1: "KAS_PUBLIC_KEY_ALG_ENUM_RSA_2048",
- 2: "KAS_PUBLIC_KEY_ALG_ENUM_RSA_4096",
- 5: "KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1",
- 6: "KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1",
- 7: "KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1",
+ 0: "KAS_PUBLIC_KEY_ALG_ENUM_UNSPECIFIED",
+ 1: "KAS_PUBLIC_KEY_ALG_ENUM_RSA_2048",
+ 2: "KAS_PUBLIC_KEY_ALG_ENUM_RSA_4096",
+ 5: "KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1",
+ 6: "KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1",
+ 7: "KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1",
+ 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",
}
KasPublicKeyAlgEnum_value = map[string]int32{
- "KAS_PUBLIC_KEY_ALG_ENUM_UNSPECIFIED": 0,
- "KAS_PUBLIC_KEY_ALG_ENUM_RSA_2048": 1,
- "KAS_PUBLIC_KEY_ALG_ENUM_RSA_4096": 2,
- "KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1": 5,
- "KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1": 6,
- "KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1": 7,
+ "KAS_PUBLIC_KEY_ALG_ENUM_UNSPECIFIED": 0,
+ "KAS_PUBLIC_KEY_ALG_ENUM_RSA_2048": 1,
+ "KAS_PUBLIC_KEY_ALG_ENUM_RSA_4096": 2,
+ "KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1": 5,
+ "KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1": 6,
+ "KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1": 7,
+ "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,
}
)
@@ -302,6 +312,9 @@ const (
Algorithm_ALGORITHM_EC_P256 Algorithm = 3
Algorithm_ALGORITHM_EC_P384 Algorithm = 4
Algorithm_ALGORITHM_EC_P521 Algorithm = 5
+ Algorithm_ALGORITHM_HPQT_XWING Algorithm = 6
+ Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768 Algorithm = 7
+ Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024 Algorithm = 8
)
// Enum value maps for Algorithm.
@@ -313,14 +326,20 @@ var (
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",
}
Algorithm_value = map[string]int32{
- "ALGORITHM_UNSPECIFIED": 0,
- "ALGORITHM_RSA_2048": 1,
- "ALGORITHM_RSA_4096": 2,
- "ALGORITHM_EC_P256": 3,
- "ALGORITHM_EC_P384": 4,
- "ALGORITHM_EC_P521": 5,
+ "ALGORITHM_UNSPECIFIED": 0,
+ "ALGORITHM_RSA_2048": 1,
+ "ALGORITHM_RSA_4096": 2,
+ "ALGORITHM_EC_P256": 3,
+ "ALGORITHM_EC_P384": 4,
+ "ALGORITHM_EC_P521": 5,
+ "ALGORITHM_HPQT_XWING": 6,
+ "ALGORITHM_HPQT_SECP256R1_MLKEM768": 7,
+ "ALGORITHM_HPQT_SECP384R1_MLKEM1024": 8,
}
)
@@ -3697,7 +3716,7 @@ var file_policy_objects_proto_rawDesc = []byte{
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, 0x88, 0x02, 0x0a, 0x13, 0x4b, 0x61, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65,
+ 0x2a, 0xb0, 0x02, 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, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10,
@@ -3713,41 +3732,45 @@ var file_policy_objects_proto_rawDesc = []byte{
0x55, 0x4d, 0x5f, 0x45, 0x43, 0x5f, 0x53, 0x45, 0x43, 0x50, 0x33, 0x38, 0x34, 0x52, 0x31, 0x10,
0x06, 0x12, 0x28, 0x0a, 0x24, 0x4b, 0x41, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f,
0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x45, 0x43, 0x5f,
- 0x53, 0x45, 0x43, 0x50, 0x35, 0x32, 0x31, 0x52, 0x31, 0x10, 0x07, 0x2a, 0x9b, 0x01, 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, 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,
+ 0x53, 0x45, 0x43, 0x50, 0x35, 0x32, 0x31, 0x52, 0x31, 0x10, 0x07, 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, 0x48, 0x50, 0x51, 0x54, 0x5f, 0x58, 0x57, 0x49, 0x4e,
+ 0x47, 0x10, 0x0a, 0x2a, 0xb5, 0x01, 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, 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 (
@@ -3762,54 +3785,56 @@ func file_policy_objects_proto_rawDescGZIP() []byte {
return file_policy_objects_proto_rawDescData
}
-var file_policy_objects_proto_enumTypes = make([]protoimpl.EnumInfo, 9)
-var file_policy_objects_proto_msgTypes = make([]protoimpl.MessageInfo, 33)
-var file_policy_objects_proto_goTypes = []interface{}{
- (AttributeRuleTypeEnum)(0), // 0: policy.AttributeRuleTypeEnum
- (SubjectMappingOperatorEnum)(0), // 1: policy.SubjectMappingOperatorEnum
- (ConditionBooleanTypeEnum)(0), // 2: policy.ConditionBooleanTypeEnum
- (SourceType)(0), // 3: policy.SourceType
- (KasPublicKeyAlgEnum)(0), // 4: policy.KasPublicKeyAlgEnum
- (Algorithm)(0), // 5: policy.Algorithm
- (KeyStatus)(0), // 6: policy.KeyStatus
- (KeyMode)(0), // 7: policy.KeyMode
- (Action_StandardAction)(0), // 8: policy.Action.StandardAction
- (*SimpleKasPublicKey)(nil), // 9: policy.SimpleKasPublicKey
- (*SimpleKasKey)(nil), // 10: policy.SimpleKasKey
- (*KeyProviderConfig)(nil), // 11: policy.KeyProviderConfig
- (*Namespace)(nil), // 12: policy.Namespace
- (*Attribute)(nil), // 13: policy.Attribute
- (*Value)(nil), // 14: policy.Value
- (*Action)(nil), // 15: policy.Action
- (*SubjectMapping)(nil), // 16: policy.SubjectMapping
- (*Condition)(nil), // 17: policy.Condition
- (*ConditionGroup)(nil), // 18: policy.ConditionGroup
- (*SubjectSet)(nil), // 19: policy.SubjectSet
- (*SubjectConditionSet)(nil), // 20: policy.SubjectConditionSet
- (*SubjectProperty)(nil), // 21: policy.SubjectProperty
- (*ResourceMappingGroup)(nil), // 22: policy.ResourceMappingGroup
- (*ResourceMapping)(nil), // 23: policy.ResourceMapping
- (*KeyAccessServer)(nil), // 24: policy.KeyAccessServer
- (*Key)(nil), // 25: policy.Key
- (*KasPublicKey)(nil), // 26: policy.KasPublicKey
- (*KasPublicKeySet)(nil), // 27: policy.KasPublicKeySet
- (*PublicKey)(nil), // 28: policy.PublicKey
- (*RegisteredResource)(nil), // 29: policy.RegisteredResource
- (*RegisteredResourceValue)(nil), // 30: policy.RegisteredResourceValue
- (*PolicyEnforcementPoint)(nil), // 31: policy.PolicyEnforcementPoint
- (*RequestContext)(nil), // 32: policy.RequestContext
- (*Obligation)(nil), // 33: policy.Obligation
- (*ObligationValue)(nil), // 34: policy.ObligationValue
- (*ObligationTrigger)(nil), // 35: policy.ObligationTrigger
- (*KasKey)(nil), // 36: policy.KasKey
- (*PublicKeyCtx)(nil), // 37: policy.PublicKeyCtx
- (*PrivateKeyCtx)(nil), // 38: policy.PrivateKeyCtx
- (*AsymmetricKey)(nil), // 39: policy.AsymmetricKey
- (*SymmetricKey)(nil), // 40: policy.SymmetricKey
- (*RegisteredResourceValue_ActionAttributeValue)(nil), // 41: policy.RegisteredResourceValue.ActionAttributeValue
- (*common.Metadata)(nil), // 42: common.Metadata
- (*wrapperspb.BoolValue)(nil), // 43: google.protobuf.BoolValue
-}
+var (
+ file_policy_objects_proto_enumTypes = make([]protoimpl.EnumInfo, 9)
+ file_policy_objects_proto_msgTypes = make([]protoimpl.MessageInfo, 33)
+ file_policy_objects_proto_goTypes = []interface{}{
+ (AttributeRuleTypeEnum)(0), // 0: policy.AttributeRuleTypeEnum
+ (SubjectMappingOperatorEnum)(0), // 1: policy.SubjectMappingOperatorEnum
+ (ConditionBooleanTypeEnum)(0), // 2: policy.ConditionBooleanTypeEnum
+ (SourceType)(0), // 3: policy.SourceType
+ (KasPublicKeyAlgEnum)(0), // 4: policy.KasPublicKeyAlgEnum
+ (Algorithm)(0), // 5: policy.Algorithm
+ (KeyStatus)(0), // 6: policy.KeyStatus
+ (KeyMode)(0), // 7: policy.KeyMode
+ (Action_StandardAction)(0), // 8: policy.Action.StandardAction
+ (*SimpleKasPublicKey)(nil), // 9: policy.SimpleKasPublicKey
+ (*SimpleKasKey)(nil), // 10: policy.SimpleKasKey
+ (*KeyProviderConfig)(nil), // 11: policy.KeyProviderConfig
+ (*Namespace)(nil), // 12: policy.Namespace
+ (*Attribute)(nil), // 13: policy.Attribute
+ (*Value)(nil), // 14: policy.Value
+ (*Action)(nil), // 15: policy.Action
+ (*SubjectMapping)(nil), // 16: policy.SubjectMapping
+ (*Condition)(nil), // 17: policy.Condition
+ (*ConditionGroup)(nil), // 18: policy.ConditionGroup
+ (*SubjectSet)(nil), // 19: policy.SubjectSet
+ (*SubjectConditionSet)(nil), // 20: policy.SubjectConditionSet
+ (*SubjectProperty)(nil), // 21: policy.SubjectProperty
+ (*ResourceMappingGroup)(nil), // 22: policy.ResourceMappingGroup
+ (*ResourceMapping)(nil), // 23: policy.ResourceMapping
+ (*KeyAccessServer)(nil), // 24: policy.KeyAccessServer
+ (*Key)(nil), // 25: policy.Key
+ (*KasPublicKey)(nil), // 26: policy.KasPublicKey
+ (*KasPublicKeySet)(nil), // 27: policy.KasPublicKeySet
+ (*PublicKey)(nil), // 28: policy.PublicKey
+ (*RegisteredResource)(nil), // 29: policy.RegisteredResource
+ (*RegisteredResourceValue)(nil), // 30: policy.RegisteredResourceValue
+ (*PolicyEnforcementPoint)(nil), // 31: policy.PolicyEnforcementPoint
+ (*RequestContext)(nil), // 32: policy.RequestContext
+ (*Obligation)(nil), // 33: policy.Obligation
+ (*ObligationValue)(nil), // 34: policy.ObligationValue
+ (*ObligationTrigger)(nil), // 35: policy.ObligationTrigger
+ (*KasKey)(nil), // 36: policy.KasKey
+ (*PublicKeyCtx)(nil), // 37: policy.PublicKeyCtx
+ (*PrivateKeyCtx)(nil), // 38: policy.PrivateKeyCtx
+ (*AsymmetricKey)(nil), // 39: policy.AsymmetricKey
+ (*SymmetricKey)(nil), // 40: policy.SymmetricKey
+ (*RegisteredResourceValue_ActionAttributeValue)(nil), // 41: policy.RegisteredResourceValue.ActionAttributeValue
+ (*common.Metadata)(nil), // 42: common.Metadata
+ (*wrapperspb.BoolValue)(nil), // 43: google.protobuf.BoolValue
+ }
+)
var file_policy_objects_proto_depIdxs = []int32{
5, // 0: policy.SimpleKasPublicKey.algorithm:type_name -> policy.Algorithm
9, // 1: policy.SimpleKasKey.public_key:type_name -> policy.SimpleKasPublicKey
diff --git a/scripts/README.md b/scripts/README.md
new file mode 100644
index 0000000000..68b624bfc0
--- /dev/null
+++ b/scripts/README.md
@@ -0,0 +1,112 @@
+# E2E Hybrid Key Testing Scripts
+
+End-to-end testing of TDF encrypt/decrypt with all supported key algorithms, including hybrid post-quantum (X-Wing, P256+ML-KEM-768, P384+ML-KEM-1024).
+
+## Prerequisites
+
+- Go toolchain (matching `go.work` version)
+- Docker and Docker Compose
+- `curl`
+
+## Quick Start (Single Command)
+
+Run everything — setup, tests, and teardown — in one shot:
+
+```bash
+./scripts/e2e-hybrid-test.sh all
+```
+
+## Two-Terminal Workflow (Recommended)
+
+This approach lets you keep the platform running and re-run tests as you iterate.
+
+### Terminal 1: Start services
+
+```bash
+./scripts/e2e-hybrid-test.sh setup
+```
+
+This will:
+1. Generate KAS keys (RSA, EC, X-Wing, P256+ML-KEM-768, P384+ML-KEM-1024)
+2. Copy `opentdf-dev.yaml` to `opentdf.yaml`
+3. Start Docker containers (Keycloak + PostgreSQL)
+4. Provision Keycloak realm and policy fixtures
+5. Start the OpenTDF platform on `http://localhost:8080`
+
+The terminal stays attached to the platform process so you can see server logs.
+
+### Terminal 2: Run tests
+
+```bash
+# Run all algorithms
+./scripts/e2e-hybrid-test.sh test
+
+# Run a single algorithm
+./scripts/e2e-hybrid-test.sh test --alg hpqt:xwing
+```
+
+### Teardown
+
+When done, stop everything:
+
+```bash
+# Ctrl+C in Terminal 1 to stop the platform, then:
+./scripts/e2e-hybrid-test.sh teardown
+```
+
+This stops any platform process, tears down Docker containers, and cleans up test artifacts.
+
+## Supported Algorithms
+
+| Algorithm | Key Type | Description |
+|-----------|----------|-------------|
+| `rsa:2048` | `wrapped` | RSA 2048-bit (classic) |
+| `ec:secp256r1` | `ec-wrapped` | NIST P-256 Elliptic Curve (classic) |
+| `hpqt:xwing` | `hybrid-wrapped` | X-Wing hybrid post-quantum KEM |
+| `hpqt:secp256r1-mlkem768` | `hybrid-wrapped` | P-256 + ML-KEM-768 (NIST Level 3) |
+| `hpqt:secp384r1-mlkem1024` | `hybrid-wrapped` | P-384 + ML-KEM-1024 (NIST Level 5) |
+
+## What the Tests Do
+
+For each algorithm, the test:
+
+1. **Encrypts** a unique plaintext string into a TDF file using the specified algorithm
+2. **Dumps the manifest** showing the key access object, wrapping type, and key ID
+3. **Decrypts** the TDF file back to plaintext
+4. **Verifies** the decrypted output matches the original plaintext
+
+## Configuration
+
+The tests require `ec_tdf_enabled` and `hybrid_tdf_enabled` preview flags to be set to `true` in `opentdf-dev.yaml` under `services.kas.preview`. Without these, the KAS will reject non-RSA rewrap requests.
+
+```yaml
+services:
+ kas:
+ preview:
+ ec_tdf_enabled: true
+ hybrid_tdf_enabled: true
+```
+
+## Key Generation Tool
+
+The hybrid PEM key files are generated by a Go tool at `service/cmd/keygen/`:
+
+```bash
+# Generate all hybrid key pairs to a directory
+go run ./service/cmd/keygen -output /path/to/keys
+```
+
+This produces:
+- `kas-xwing-private.pem` / `kas-xwing-public.pem`
+- `kas-p256mlkem768-private.pem` / `kas-p256mlkem768-public.pem`
+- `kas-p384mlkem1024-private.pem` / `kas-p384mlkem1024-public.pem`
+
+## Troubleshooting
+
+| Error | Cause | Fix |
+|-------|-------|-----|
+| `address already in use` | Platform from a previous run is still on port 8080 | `lsof -ti :8080 \| xargs kill` or `./scripts/e2e-hybrid-test.sh teardown` |
+| `http: server gave HTTP response to HTTPS client` | Using `https://` but TLS is disabled | The script uses `http://localhost:8080` by default; ensure you don't override with HTTPS |
+| `dial tcp [::1]:8888: connect: connection refused` | Keycloak is not running | Run `./scripts/e2e-hybrid-test.sh setup` or `docker compose up -d` |
+| `rewrap request 400 / bad request` | EC or hybrid TDF preview flags are disabled | Set `ec_tdf_enabled: true` and `hybrid_tdf_enabled: true` in `opentdf-dev.yaml` |
+| `unable to retrieve public key from KAS at kas.example.com` | Autoconfigure resolved to a non-local KAS | The script passes `--autoconfigure=false`; ensure you're using the script, not manual commands |
diff --git a/scripts/e2e-hybrid-test.sh b/scripts/e2e-hybrid-test.sh
new file mode 100755
index 0000000000..a504759c84
--- /dev/null
+++ b/scripts/e2e-hybrid-test.sh
@@ -0,0 +1,379 @@
+#!/usr/bin/env bash
+# e2e-hybrid-test.sh
+# End-to-end test of TDF encrypt/decrypt with all supported key algorithms,
+# including hybrid post-quantum (X-Wing, P256+ML-KEM-768, P384+ML-KEM-1024).
+#
+# Usage:
+# ./scripts/e2e-hybrid-test.sh setup Start services (docker + platform)
+# ./scripts/e2e-hybrid-test.sh test [OPTIONS] Run encrypt/decrypt tests
+# ./scripts/e2e-hybrid-test.sh teardown Stop services and clean up
+# ./scripts/e2e-hybrid-test.sh all [OPTIONS] Setup + test + teardown (legacy mode)
+#
+# Test options:
+# --alg ALGORITHM Test only a specific algorithm (e.g. hpqt:xwing)
+#
+# Examples:
+# ./scripts/e2e-hybrid-test.sh setup # Terminal 1: start everything
+# ./scripts/e2e-hybrid-test.sh test # Terminal 2: run all tests
+# ./scripts/e2e-hybrid-test.sh test --alg hpqt:xwing # test one algorithm
+# ./scripts/e2e-hybrid-test.sh teardown # Terminal 1: stop everything
+
+set -euo pipefail
+
+REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
+cd "$REPO_ROOT"
+
+PLATFORM_ENDPOINT="http://localhost:8080"
+CREDS="opentdf-sdk:secret"
+PLATFORM_PID_FILE="/tmp/opentdf-e2e-platform.pid"
+
+ALL_ALGS=(
+ "rsa:2048"
+ "ec:secp256r1"
+ "hpqt:xwing"
+ "hpqt:secp256r1-mlkem768"
+ "hpqt:secp384r1-mlkem1024"
+)
+
+usage() {
+ sed -n '2,17p' "$0" | sed 's/^# \?//'
+ exit 1
+}
+
+#
+# ── SETUP ──────────────────────────────────────────────────────────────
+#
+do_setup() {
+ echo "============================================"
+ echo " OpenTDF E2E Setup"
+ echo "============================================"
+ echo ""
+
+ # Clean slate: stop any existing services
+ echo "==> Tearing down any existing services..."
+ if [ -f "$PLATFORM_PID_FILE" ]; then
+ local old_pid
+ old_pid=$(cat "$PLATFORM_PID_FILE")
+ kill "$old_pid" 2>/dev/null || true
+ wait "$old_pid" 2>/dev/null || true
+ rm -f "$PLATFORM_PID_FILE"
+ fi
+ local port_pid
+ port_pid=$(lsof -ti :8080 2>/dev/null || true)
+ if [ -n "$port_pid" ]; then
+ kill "$port_pid" 2>/dev/null || true
+ fi
+ docker compose down 2>/dev/null || true
+ echo ""
+
+ # Step 1: Generate keys
+ echo "==> Generating KAS keys (RSA, EC, hybrid PQ)..."
+ .github/scripts/init-temp-keys.sh
+ echo ""
+
+ # Step 2: Create runtime config
+ echo "==> Creating runtime config..."
+ cp opentdf-dev.yaml opentdf.yaml
+ echo ""
+
+ # Step 3: Start docker services
+ echo "==> Starting docker services (Keycloak + PostgreSQL)..."
+ docker compose up -d
+ echo " Waiting for Keycloak to be ready..."
+ for i in $(seq 1 60); do
+ if curl -sf http://localhost:8888/auth/realms/master > /dev/null 2>&1; then
+ echo " Keycloak is ready."
+ break
+ fi
+ if [ "$i" -eq 60 ]; then
+ echo " ERROR: Keycloak did not become ready in time."
+ exit 1
+ fi
+ sleep 2
+ done
+ echo ""
+
+ # Step 4: Provision
+ echo "==> Provisioning Keycloak realm and fixtures..."
+ go run ./service provision keycloak
+ go run ./service provision fixtures
+ echo ""
+
+ # Step 5: Start platform
+ echo "==> Starting platform..."
+ go run ./service start &
+ local pid=$!
+ echo "$pid" > "$PLATFORM_PID_FILE"
+ echo " Platform PID: $pid (saved to $PLATFORM_PID_FILE)"
+ echo " Waiting for platform to be ready..."
+ for i in $(seq 1 60); do
+ if curl -sf "$PLATFORM_ENDPOINT/.well-known/opentdf-configuration" > /dev/null 2>&1; then
+ echo " Platform is ready."
+ break
+ fi
+ if [ "$i" -eq 60 ]; then
+ echo " ERROR: Platform did not become ready in time."
+ exit 1
+ fi
+ sleep 2
+ done
+
+ echo ""
+ echo "============================================"
+ echo " Setup complete. Platform running on $PLATFORM_ENDPOINT"
+ echo " Run tests with: ./scripts/e2e-hybrid-test.sh test"
+ echo " Teardown with: ./scripts/e2e-hybrid-test.sh teardown"
+ echo "============================================"
+
+ # Wait for platform so this terminal stays attached
+ wait "$pid" 2>/dev/null || true
+}
+
+#
+# ── TEST ───────────────────────────────────────────────────────────────
+#
+do_test() {
+ local test_alg=""
+
+ while [ $# -gt 0 ]; do
+ case "$1" in
+ --alg) test_alg="$2"; shift 2 ;;
+ *) echo "Unknown test option: $1"; usage ;;
+ esac
+ done
+
+ # Select algorithms
+ local algs=()
+ if [ -n "$test_alg" ]; then
+ algs=("$test_alg")
+ else
+ algs=("${ALL_ALGS[@]}")
+ fi
+
+ # Verify platform is reachable
+ if ! curl -sf "$PLATFORM_ENDPOINT/.well-known/opentdf-configuration" > /dev/null 2>&1; then
+ echo "ERROR: Platform is not reachable at $PLATFORM_ENDPOINT"
+ echo " Run './scripts/e2e-hybrid-test.sh setup' first."
+ exit 1
+ fi
+
+ echo "============================================"
+ echo " OpenTDF Hybrid Key E2E Tests"
+ echo "============================================"
+ echo ""
+
+ # Build examples CLI
+ echo "==> Building examples CLI..."
+ (cd examples && go build -o examples .)
+ echo ""
+
+ echo "==> Running encrypt/decrypt tests..."
+ echo ""
+
+ local passed=0
+ local failed=0
+ local results=()
+
+ for alg in "${algs[@]}"; do
+ local safe_name="${alg//:/-}"
+ local outfile="test-output-${safe_name}.tdf"
+ local manifest_file="test-manifest-${safe_name}.json"
+ local plaintext="Hello from ${alg} at $(date +%s)!"
+
+ echo "--- Testing algorithm: $alg ---"
+
+ # Encrypt
+ echo " Encrypting..."
+ if ! examples/examples encrypt "$plaintext" \
+ -e "$PLATFORM_ENDPOINT" \
+ --insecurePlaintextConn \
+ --creds "$CREDS" \
+ --autoconfigure=false \
+ -A "$alg" \
+ -o "$outfile" > "$manifest_file" 2>&1; then
+ echo " FAIL: Encrypt failed for $alg"
+ cat "$manifest_file" 2>/dev/null
+ failed=$((failed + 1))
+ results+=("FAIL $alg (encrypt)")
+ rm -f "$manifest_file"
+ continue
+ fi
+ echo " Encrypted -> $outfile ($(wc -c < "$outfile") bytes)"
+ echo ""
+ echo " Key Access ($alg):"
+ echo " ----------------------------------------"
+ python3 -c "
+import json, sys
+m = json.load(open(sys.argv[1]))
+ka = m.get('encryptionInformation', {}).get('keyAccess', [])
+print(json.dumps(ka, indent=2))
+" "$manifest_file" | sed 's/^/ /'
+ echo " ----------------------------------------"
+ rm -f "$manifest_file"
+
+ # Decrypt (session key type defaults to rsa:2048 — independent of wrapping algorithm)
+ echo " Decrypting..."
+ local decrypted
+ decrypted=$(examples/examples decrypt "$outfile" \
+ -e "$PLATFORM_ENDPOINT" \
+ --insecurePlaintextConn \
+ --creds "$CREDS" 2>&1) || true
+
+ if [ "$decrypted" = "$plaintext" ]; then
+ echo " PASS: Round-trip successful"
+ passed=$((passed + 1))
+ results+=("PASS $alg")
+ else
+ echo " FAIL: Decrypted text does not match"
+ echo " Expected: $plaintext"
+ echo " Got: $decrypted"
+ failed=$((failed + 1))
+ results+=("FAIL $alg (decrypt mismatch)")
+ fi
+
+ rm -f "$outfile"
+ echo ""
+ done
+
+ # Summary
+ echo "============================================"
+ echo " Results: $passed passed, $failed failed"
+ echo "============================================"
+ for result in "${results[@]}"; do
+ echo " $result"
+ done
+ echo ""
+
+ if [ "$failed" -gt 0 ]; then
+ exit 1
+ fi
+}
+
+#
+# ── TEARDOWN ───────────────────────────────────────────────────────────
+#
+do_teardown() {
+ echo "============================================"
+ echo " OpenTDF E2E Teardown"
+ echo "============================================"
+ echo ""
+
+ # Stop platform
+ if [ -f "$PLATFORM_PID_FILE" ]; then
+ local pid
+ pid=$(cat "$PLATFORM_PID_FILE")
+ echo "==> Stopping platform (PID $pid)..."
+ kill "$pid" 2>/dev/null || true
+ wait "$pid" 2>/dev/null || true
+ rm -f "$PLATFORM_PID_FILE"
+ else
+ # Try to kill anything on port 8080
+ local pid
+ pid=$(lsof -ti :8080 2>/dev/null || true)
+ if [ -n "$pid" ]; then
+ echo "==> Stopping process on port 8080 (PID $pid)..."
+ kill "$pid" 2>/dev/null || true
+ fi
+ fi
+
+ # Stop docker
+ echo "==> Stopping docker services..."
+ docker compose down 2>/dev/null || true
+
+ # Clean up test artifacts
+ echo "==> Cleaning up test artifacts..."
+ rm -f test-output-*.tdf test-manifest-*.json examples/examples
+
+ echo ""
+ echo " Teardown complete."
+}
+
+#
+# ── ALL (legacy: setup + test + teardown) ──────────────────────────────
+#
+do_all() {
+ # Setup in background-ish: we need to not block on `wait`
+ echo "============================================"
+ echo " OpenTDF E2E Full Run (setup + test + teardown)"
+ echo "============================================"
+ echo ""
+
+ # Generate keys
+ echo "==> Generating KAS keys (RSA, EC, hybrid PQ)..."
+ .github/scripts/init-temp-keys.sh
+ echo ""
+
+ echo "==> Creating runtime config..."
+ cp opentdf-dev.yaml opentdf.yaml
+ echo ""
+
+ echo "==> Starting docker services (Keycloak + PostgreSQL)..."
+ docker compose up -d
+ echo " Waiting for Keycloak to be ready..."
+ for i in $(seq 1 60); do
+ if curl -sf http://localhost:8888/auth/realms/master > /dev/null 2>&1; then
+ echo " Keycloak is ready."
+ break
+ fi
+ if [ "$i" -eq 60 ]; then
+ echo " ERROR: Keycloak did not become ready in time."
+ exit 1
+ fi
+ sleep 2
+ done
+ echo ""
+
+ echo "==> Provisioning Keycloak realm and fixtures..."
+ go run ./service provision keycloak
+ go run ./service provision fixtures
+ echo ""
+
+ echo "==> Starting platform..."
+ go run ./service start &
+ local platform_pid=$!
+ echo "$platform_pid" > "$PLATFORM_PID_FILE"
+ echo " Platform PID: $platform_pid"
+ echo " Waiting for platform to be ready..."
+ for i in $(seq 1 60); do
+ if curl -sf "$PLATFORM_ENDPOINT/.well-known/opentdf-configuration" > /dev/null 2>&1; then
+ echo " Platform is ready."
+ break
+ fi
+ if [ "$i" -eq 60 ]; then
+ echo " ERROR: Platform did not become ready in time."
+ kill "$platform_pid" 2>/dev/null || true
+ exit 1
+ fi
+ sleep 2
+ done
+ echo ""
+
+ # Run tests (pass remaining args like --alg)
+ local test_exit=0
+ do_test "$@" || test_exit=$?
+
+ # Teardown
+ echo ""
+ do_teardown
+
+ exit "$test_exit"
+}
+
+#
+# ── MAIN ───────────────────────────────────────────────────────────────
+#
+if [ $# -eq 0 ]; then
+ usage
+fi
+
+COMMAND="$1"
+shift
+
+case "$COMMAND" in
+ setup) do_setup "$@" ;;
+ test) do_test "$@" ;;
+ teardown) do_teardown "$@" ;;
+ all) do_all "$@" ;;
+ -h|--help) usage ;;
+ *) echo "Unknown command: $COMMAND"; usage ;;
+esac
diff --git a/sdk/basekey.go b/sdk/basekey.go
index 5f3cc12004..45a2634ac5 100644
--- a/sdk/basekey.go
+++ b/sdk/basekey.go
@@ -33,6 +33,12 @@ func getKasKeyAlg(alg string) policy.Algorithm {
return policy.Algorithm_ALGORITHM_EC_P384
case string(ocrypto.EC521Key):
return policy.Algorithm_ALGORITHM_EC_P521
+ case string(ocrypto.HybridXWingKey):
+ return policy.Algorithm_ALGORITHM_HPQT_XWING
+ case string(ocrypto.HybridSecp256r1MLKEM768Key):
+ return policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768
+ case string(ocrypto.HybridSecp384r1MLKEM1024Key):
+ return policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024
default:
return policy.Algorithm_ALGORITHM_UNSPECIFIED
}
@@ -51,6 +57,12 @@ func formatAlg(alg policy.Algorithm) (string, error) {
return string(ocrypto.EC384Key), nil
case policy.Algorithm_ALGORITHM_EC_P521:
return string(ocrypto.EC521Key), nil
+ case policy.Algorithm_ALGORITHM_HPQT_XWING:
+ return string(ocrypto.HybridXWingKey), nil
+ case policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768:
+ return string(ocrypto.HybridSecp256r1MLKEM768Key), nil
+ case policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024:
+ return string(ocrypto.HybridSecp384r1MLKEM1024Key), nil
case policy.Algorithm_ALGORITHM_UNSPECIFIED:
fallthrough
default:
diff --git a/sdk/basekey_test.go b/sdk/basekey_test.go
index ea0210bdf0..9703da4275 100644
--- a/sdk/basekey_test.go
+++ b/sdk/basekey_test.go
@@ -93,6 +93,21 @@ func TestGetKasKeyAlg(t *testing.T) {
algStr: string(ocrypto.EC521Key),
expected: policy.Algorithm_ALGORITHM_EC_P521,
},
+ {
+ name: "hybrid xwing",
+ algStr: string(ocrypto.HybridXWingKey),
+ expected: policy.Algorithm_ALGORITHM_HPQT_XWING,
+ },
+ {
+ name: "hybrid p256 mlkem768",
+ algStr: string(ocrypto.HybridSecp256r1MLKEM768Key),
+ expected: policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768,
+ },
+ {
+ name: "hybrid p384 mlkem1024",
+ algStr: string(ocrypto.HybridSecp384r1MLKEM1024Key),
+ expected: policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024,
+ },
{
name: "unsupported algorithm",
algStr: "unsupported",
@@ -150,6 +165,24 @@ func TestFormatAlg(t *testing.T) {
expected: string(ocrypto.EC521Key), // Note: This matches the implementation
expectError: false,
},
+ {
+ name: "Hybrid X-Wing",
+ alg: policy.Algorithm_ALGORITHM_HPQT_XWING,
+ expected: string(ocrypto.HybridXWingKey),
+ expectError: false,
+ },
+ {
+ name: "Hybrid P256+ML-KEM-768",
+ alg: policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768,
+ expected: string(ocrypto.HybridSecp256r1MLKEM768Key),
+ expectError: false,
+ },
+ {
+ name: "Hybrid P384+ML-KEM-1024",
+ alg: policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024,
+ expected: string(ocrypto.HybridSecp384r1MLKEM1024Key),
+ expectError: false,
+ },
{
name: "Unspecified algorithm",
alg: policy.Algorithm_ALGORITHM_UNSPECIFIED,
@@ -324,6 +357,9 @@ func TestFormatAlg_GetKasKeyAlg_RoundTrip(t *testing.T) {
{"EC-P256", policy.Algorithm_ALGORITHM_EC_P256},
{"EC-P384", policy.Algorithm_ALGORITHM_EC_P384},
{"EC-P521", policy.Algorithm_ALGORITHM_EC_P521},
+ {"HPQT-XWing", policy.Algorithm_ALGORITHM_HPQT_XWING},
+ {"HPQT-P256-MLKEM768", policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768},
+ {"HPQT-P384-MLKEM1024", policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024},
}
for _, tc := range supportedAlgs {
diff --git a/sdk/experimental/tdf/key_access.go b/sdk/experimental/tdf/key_access.go
index 6e97701ad5..5ee557aa15 100644
--- a/sdk/experimental/tdf/key_access.go
+++ b/sdk/experimental/tdf/key_access.go
@@ -4,6 +4,7 @@ package tdf
import (
"crypto/sha256"
+ "encoding/asn1"
"encoding/hex"
"encoding/json"
"errors"
@@ -165,6 +166,9 @@ 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.IsECKeyType(ktype) {
// Handle EC key wrapping
return wrapKeyWithEC(ktype, pubKeyInfo.PEM, symKey)
@@ -245,3 +249,65 @@ 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) {
+ // Step 1: Parse public key and perform hybrid KEM encapsulation (ECDH + ML-KEM)
+ var (
+ pubKey []byte
+ sharedSecret, kemCiphertext []byte
+ err error
+ )
+
+ switch ktype { //nolint:exhaustive // only handle hybrid types
+ case ocrypto.HybridXWingKey:
+ pubKey, err = ocrypto.XWingPubKeyFromPem([]byte(kasPublicKeyPEM))
+ if err != nil {
+ return "", "", "", fmt.Errorf("failed to parse X-Wing public key: %w", err)
+ }
+ sharedSecret, kemCiphertext, err = ocrypto.XWingEncapsulate(pubKey)
+ case ocrypto.HybridSecp256r1MLKEM768Key:
+ pubKey, err = ocrypto.P256MLKEM768PubKeyFromPem([]byte(kasPublicKeyPEM))
+ if err != nil {
+ return "", "", "", fmt.Errorf("failed to parse P256+ML-KEM-768 public key: %w", err)
+ }
+ sharedSecret, kemCiphertext, err = ocrypto.P256MLKEM768Encapsulate(pubKey)
+ case ocrypto.HybridSecp384r1MLKEM1024Key:
+ pubKey, err = ocrypto.P384MLKEM1024PubKeyFromPem([]byte(kasPublicKeyPEM))
+ if err != nil {
+ return "", "", "", fmt.Errorf("failed to parse P384+ML-KEM-1024 public key: %w", err)
+ }
+ sharedSecret, kemCiphertext, err = ocrypto.P384MLKEM1024Encapsulate(pubKey)
+ default:
+ return "", "", "", fmt.Errorf("unsupported hybrid algorithm: %s", ktype)
+ }
+ if err != nil {
+ return "", "", "", fmt.Errorf("failed to encapsulate with %s: %w", ktype, err)
+ }
+
+ // Step 2: Derive wrap key from shared secret via HKDF
+ wrapKey, err := ocrypto.CalculateHKDF(tdfSalt(), sharedSecret)
+ if err != nil {
+ return "", "", "", fmt.Errorf("failed to derive HKDF key: %w", err)
+ }
+
+ // Step 3: AES-GCM encrypt at SDK layer
+ gcm, err := ocrypto.NewAESGcm(wrapKey)
+ if err != nil {
+ return "", "", "", fmt.Errorf("failed to create AES-GCM: %w", err)
+ }
+ encryptedDEK, err := gcm.Encrypt(symKey)
+ if err != nil {
+ return "", "", "", fmt.Errorf("failed to AES-GCM encrypt: %w", err)
+ }
+
+ // Step 4: ASN1 marshal at SDK layer
+ wrappedDER, err := asn1.Marshal(ocrypto.HybridNISTWrappedKey{
+ HybridCiphertext: kemCiphertext,
+ EncryptedDEK: encryptedDEK,
+ })
+ if err != nil {
+ return "", "", "", fmt.Errorf("failed to ASN1 marshal: %w", err)
+ }
+
+ return string(ocrypto.Base64Encode(wrappedDER)), "hybrid-wrapped", "", nil
+}
diff --git a/sdk/experimental/tdf/key_access_test.go b/sdk/experimental/tdf/key_access_test.go
index 9dac3ca3b6..daea79b69c 100644
--- a/sdk/experimental/tdf/key_access_test.go
+++ b/sdk/experimental/tdf/key_access_test.go
@@ -35,7 +35,7 @@ SQIDAQAB
)
// createTestSplitResult creates a mock SplitResult for testing key access operations
-func createTestSplitResult(kasURL, pubKey string, algorithm string) *keysplit.SplitResult {
+func createTestSplitResult(pubKey string, algorithm string) *keysplit.SplitResult {
// Generate random split data
splitData := make([]byte, 32)
_, err := rand.Read(splitData)
@@ -46,11 +46,11 @@ func createTestSplitResult(kasURL, pubKey string, algorithm string) *keysplit.Sp
split := keysplit.Split{
ID: "test-split-1",
Data: splitData,
- KASURLs: []string{kasURL},
+ KASURLs: []string{testKAS1URL},
}
pubKeyInfo := keysplit.KASPublicKey{
- URL: kasURL,
+ URL: testKAS1URL,
Algorithm: algorithm,
KID: "test-kid-1",
PEM: pubKey,
@@ -58,14 +58,14 @@ func createTestSplitResult(kasURL, pubKey string, algorithm string) *keysplit.Sp
return &keysplit.SplitResult{
Splits: []keysplit.Split{split},
- KASPublicKeys: map[string]keysplit.KASPublicKey{kasURL: pubKeyInfo},
+ KASPublicKeys: map[string]keysplit.KASPublicKey{testKAS1URL: pubKeyInfo},
}
}
func TestBuildKeyAccessObjects(t *testing.T) {
t.Run("successfully creates key access objects with RSA public key", func(t *testing.T) {
// Test that buildKeyAccessObjects correctly processes RSA keys and creates valid KeyAccess objects
- splitResult := createTestSplitResult(testKAS1URL, testRSAPublicKey, "rsa:2048")
+ splitResult := createTestSplitResult(testRSAPublicKey, "rsa:2048")
policyBytes := []byte(testPolicyJSON)
metadata := testMetadata
@@ -96,7 +96,7 @@ func TestBuildKeyAccessObjects(t *testing.T) {
ecPublicKeyPEM, err := ecKeyPair.PublicKeyInPemFormat()
require.NoError(t, err, "Should get public key in PEM format")
- splitResult := createTestSplitResult(testKAS1URL, ecPublicKeyPEM, "ec:secp256r1")
+ splitResult := createTestSplitResult(ecPublicKeyPEM, "ec:secp256r1")
policyBytes := []byte(testPolicyJSON)
metadata := testMetadata
@@ -112,6 +112,69 @@ func TestBuildKeyAccessObjects(t *testing.T) {
assert.NotEmpty(t, keyAccess.WrappedKey, "Should contain wrapped key data")
})
+ t.Run("successfully creates key access objects with X-Wing public key", func(t *testing.T) {
+ xwingKeyPair, err := ocrypto.NewXWingKeyPair()
+ require.NoError(t, err)
+
+ xwingPublicKeyPEM, err := xwingKeyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+
+ splitResult := createTestSplitResult(xwingPublicKeyPEM, string(ocrypto.HybridXWingKey))
+ policyBytes := []byte(testPolicyJSON)
+
+ keyAccessList, err := buildKeyAccessObjects(splitResult, policyBytes, testMetadata)
+
+ require.NoError(t, err, "Should successfully create key access objects with valid X-Wing key")
+ require.Len(t, keyAccessList, 1)
+
+ keyAccess := keyAccessList[0]
+ assert.Equal(t, "hybrid-wrapped", keyAccess.KeyType)
+ assert.NotEmpty(t, keyAccess.WrappedKey)
+ assert.Empty(t, keyAccess.EphemeralPublicKey)
+ })
+
+ t.Run("successfully creates key access objects with P256+ML-KEM-768 public key", func(t *testing.T) {
+ keyPair, err := ocrypto.NewP256MLKEM768KeyPair()
+ require.NoError(t, err)
+
+ publicKeyPEM, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+
+ splitResult := createTestSplitResult(publicKeyPEM, string(ocrypto.HybridSecp256r1MLKEM768Key))
+ policyBytes := []byte(testPolicyJSON)
+
+ keyAccessList, err := buildKeyAccessObjects(splitResult, policyBytes, testMetadata)
+
+ require.NoError(t, err, "Should successfully create key access objects with valid P256+ML-KEM-768 key")
+ require.Len(t, keyAccessList, 1)
+
+ keyAccess := keyAccessList[0]
+ assert.Equal(t, "hybrid-wrapped", keyAccess.KeyType)
+ assert.NotEmpty(t, keyAccess.WrappedKey)
+ assert.Empty(t, keyAccess.EphemeralPublicKey)
+ })
+
+ t.Run("successfully creates key access objects with P384+ML-KEM-1024 public key", func(t *testing.T) {
+ keyPair, err := ocrypto.NewP384MLKEM1024KeyPair()
+ require.NoError(t, err)
+
+ publicKeyPEM, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+
+ splitResult := createTestSplitResult(publicKeyPEM, string(ocrypto.HybridSecp384r1MLKEM1024Key))
+ policyBytes := []byte(testPolicyJSON)
+
+ keyAccessList, err := buildKeyAccessObjects(splitResult, policyBytes, testMetadata)
+
+ require.NoError(t, err, "Should successfully create key access objects with valid P384+ML-KEM-1024 key")
+ require.Len(t, keyAccessList, 1)
+
+ keyAccess := keyAccessList[0]
+ assert.Equal(t, "hybrid-wrapped", keyAccess.KeyType)
+ assert.NotEmpty(t, keyAccess.WrappedKey)
+ assert.Empty(t, keyAccess.EphemeralPublicKey)
+ })
+
t.Run("handles multiple KAS URLs in single split", func(t *testing.T) {
// Test that multiple KAS URLs in one split create separate KeyAccess objects
splitData := make([]byte, 32)
@@ -172,7 +235,7 @@ func TestBuildKeyAccessObjects(t *testing.T) {
t.Run("handles empty metadata correctly", func(t *testing.T) {
// Test that empty metadata is handled without creating encrypted metadata
- splitResult := createTestSplitResult(testKAS1URL, testRSAPublicKey, "rsa:2048")
+ splitResult := createTestSplitResult(testRSAPublicKey, "rsa:2048")
keyAccessList, err := buildKeyAccessObjects(splitResult, []byte(testPolicyJSON), "")
@@ -424,6 +487,120 @@ func TestWrapKeyWithPublicKey(t *testing.T) {
"Ephemeral key should end with PEM footer")
})
+ t.Run("wraps key with X-Wing public key", func(t *testing.T) {
+ symKey := make([]byte, 32)
+ _, err := rand.Read(symKey)
+ require.NoError(t, err)
+
+ xwingKeyPair, err := ocrypto.NewXWingKeyPair()
+ require.NoError(t, err)
+
+ xwingPublicKeyPEM, err := xwingKeyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+
+ pubKeyInfo := keysplit.KASPublicKey{
+ URL: testKAS1URL,
+ Algorithm: string(ocrypto.HybridXWingKey),
+ KID: "test-kid",
+ PEM: xwingPublicKeyPEM,
+ }
+
+ wrappedKey, keyType, ephemeralPubKey, err := wrapKeyWithPublicKey(symKey, pubKeyInfo)
+
+ require.NoError(t, err, "Should wrap key with X-Wing public key")
+ assert.NotEmpty(t, wrappedKey)
+ assert.Equal(t, "hybrid-wrapped", keyType)
+ assert.Empty(t, ephemeralPubKey)
+
+ decodedWrappedKey, err := ocrypto.Base64Decode([]byte(wrappedKey))
+ require.NoError(t, err)
+
+ privateKeyPEM, err := xwingKeyPair.PrivateKeyInPemFormat()
+ require.NoError(t, err)
+ privateKey, err := ocrypto.XWingPrivateKeyFromPem([]byte(privateKeyPEM))
+ require.NoError(t, err)
+
+ plaintext, err := ocrypto.XWingUnwrapDEK(privateKey, decodedWrappedKey)
+ require.NoError(t, err)
+ assert.Equal(t, symKey, plaintext)
+ })
+
+ t.Run("wraps key with P256+ML-KEM-768 public key", func(t *testing.T) {
+ symKey := make([]byte, 32)
+ _, err := rand.Read(symKey)
+ require.NoError(t, err)
+
+ keyPair, err := ocrypto.NewP256MLKEM768KeyPair()
+ require.NoError(t, err)
+
+ publicKeyPEM, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+
+ pubKeyInfo := keysplit.KASPublicKey{
+ URL: testKAS1URL,
+ Algorithm: string(ocrypto.HybridSecp256r1MLKEM768Key),
+ KID: "test-kid",
+ PEM: publicKeyPEM,
+ }
+
+ wrappedKey, keyType, ephemeralPubKey, err := wrapKeyWithPublicKey(symKey, pubKeyInfo)
+
+ require.NoError(t, err, "Should wrap key with P256+ML-KEM-768 public key")
+ assert.NotEmpty(t, wrappedKey)
+ assert.Equal(t, "hybrid-wrapped", keyType)
+ assert.Empty(t, ephemeralPubKey)
+
+ decodedWrappedKey, err := ocrypto.Base64Decode([]byte(wrappedKey))
+ require.NoError(t, err)
+
+ privateKeyPEM, err := keyPair.PrivateKeyInPemFormat()
+ require.NoError(t, err)
+ privateKey, err := ocrypto.P256MLKEM768PrivateKeyFromPem([]byte(privateKeyPEM))
+ require.NoError(t, err)
+
+ plaintext, err := ocrypto.P256MLKEM768UnwrapDEK(privateKey, decodedWrappedKey)
+ require.NoError(t, err)
+ assert.Equal(t, symKey, plaintext)
+ })
+
+ t.Run("wraps key with P384+ML-KEM-1024 public key", func(t *testing.T) {
+ symKey := make([]byte, 32)
+ _, err := rand.Read(symKey)
+ require.NoError(t, err)
+
+ keyPair, err := ocrypto.NewP384MLKEM1024KeyPair()
+ require.NoError(t, err)
+
+ publicKeyPEM, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+
+ pubKeyInfo := keysplit.KASPublicKey{
+ URL: testKAS1URL,
+ Algorithm: string(ocrypto.HybridSecp384r1MLKEM1024Key),
+ KID: "test-kid",
+ PEM: publicKeyPEM,
+ }
+
+ wrappedKey, keyType, ephemeralPubKey, err := wrapKeyWithPublicKey(symKey, pubKeyInfo)
+
+ require.NoError(t, err, "Should wrap key with P384+ML-KEM-1024 public key")
+ assert.NotEmpty(t, wrappedKey)
+ assert.Equal(t, "hybrid-wrapped", keyType)
+ assert.Empty(t, ephemeralPubKey)
+
+ decodedWrappedKey, err := ocrypto.Base64Decode([]byte(wrappedKey))
+ require.NoError(t, err)
+
+ privateKeyPEM, err := keyPair.PrivateKeyInPemFormat()
+ require.NoError(t, err)
+ privateKey, err := ocrypto.P384MLKEM1024PrivateKeyFromPem([]byte(privateKeyPEM))
+ require.NoError(t, err)
+
+ plaintext, err := ocrypto.P384MLKEM1024UnwrapDEK(privateKey, decodedWrappedKey)
+ require.NoError(t, err)
+ assert.Equal(t, symKey, plaintext)
+ })
+
t.Run("returns error for empty PEM", func(t *testing.T) {
// Test error handling for missing public key PEM
symKey := make([]byte, 32)
diff --git a/sdk/experimental/tdf/keysplit/attributes.go b/sdk/experimental/tdf/keysplit/attributes.go
index e12d838e97..a74b1882ba 100644
--- a/sdk/experimental/tdf/keysplit/attributes.go
+++ b/sdk/experimental/tdf/keysplit/attributes.go
@@ -199,6 +199,12 @@ func formatAlgorithm(alg policy.Algorithm) string {
return "rsa:2048"
case policy.Algorithm_ALGORITHM_RSA_4096:
return "rsa:4096"
+ case policy.Algorithm_ALGORITHM_HPQT_XWING:
+ return "hpqt:xwing"
+ case policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768:
+ return "hpqt:secp256r1-mlkem768"
+ case policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024:
+ return "hpqt:secp384r1-mlkem1024"
default:
return unknownAlgorithm
}
@@ -217,6 +223,12 @@ func convertAlgEnum2Simple(a policy.KasPublicKeyAlgEnum) policy.Algorithm {
return policy.Algorithm_ALGORITHM_RSA_2048
case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_RSA_4096:
return policy.Algorithm_ALGORITHM_RSA_4096
+ case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING:
+ return policy.Algorithm_ALGORITHM_HPQT_XWING
+ case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768:
+ 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_UNSPECIFIED:
return policy.Algorithm_ALGORITHM_UNSPECIFIED
default:
diff --git a/sdk/experimental/tdf/keysplit/attributes_test.go b/sdk/experimental/tdf/keysplit/attributes_test.go
index 4ed96d38a2..b7095e801d 100644
--- a/sdk/experimental/tdf/keysplit/attributes_test.go
+++ b/sdk/experimental/tdf/keysplit/attributes_test.go
@@ -46,6 +46,21 @@ func TestFormatAlgorithm(t *testing.T) {
alg: policy.Algorithm_ALGORITHM_RSA_4096,
expected: "rsa:4096",
},
+ {
+ name: "HPQT X-Wing",
+ alg: policy.Algorithm_ALGORITHM_HPQT_XWING,
+ expected: "hpqt:xwing",
+ },
+ {
+ name: "HPQT P256+ML-KEM-768",
+ alg: policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768,
+ expected: "hpqt:secp256r1-mlkem768",
+ },
+ {
+ name: "HPQT P384+ML-KEM-1024",
+ alg: policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024,
+ expected: "hpqt:secp384r1-mlkem1024",
+ },
{
name: "unknown algorithm value",
alg: policy.Algorithm(999),
@@ -97,6 +112,21 @@ func TestConvertAlgEnum2Simple(t *testing.T) {
algEnum: policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_RSA_4096,
expected: policy.Algorithm_ALGORITHM_RSA_4096,
},
+ {
+ name: "HPQT X-Wing",
+ algEnum: policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING,
+ expected: policy.Algorithm_ALGORITHM_HPQT_XWING,
+ },
+ {
+ name: "HPQT P256+ML-KEM-768",
+ algEnum: policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768,
+ expected: policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768,
+ },
+ {
+ name: "HPQT P384+ML-KEM-1024",
+ algEnum: policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP384R1_MLKEM1024,
+ expected: policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024,
+ },
{
name: "unknown enum value",
algEnum: policy.KasPublicKeyAlgEnum(999),
diff --git a/sdk/experimental/tdf/writer_test.go b/sdk/experimental/tdf/writer_test.go
index 296c582041..e05e50f180 100644
--- a/sdk/experimental/tdf/writer_test.go
+++ b/sdk/experimental/tdf/writer_test.go
@@ -58,6 +58,9 @@ func TestWriterEndToEnd(t *testing.T) {
{"GetManifestIncludesInitialPolicy", testGetManifestIncludesInitialPolicy},
{"SparseIndicesInOrder", testSparseIndicesInOrder},
{"SparseIndicesOutOfOrder", testSparseIndicesOutOfOrder},
+ {"HybridXWingFlow", testHybridXWingFlow},
+ {"HybridP256MLKEM768Flow", testHybridP256MLKEM768Flow},
+ {"HybridP384MLKEM1024Flow", testHybridP384MLKEM1024Flow},
}
for _, tc := range testCases {
@@ -877,6 +880,105 @@ func createTestAttributeWithRule(fqn, kasURL, kid string, rule policy.AttributeR
return value
}
+func createTestAttributeWithAlgorithm(fqn, kasURL, kid string, alg policy.Algorithm, pem string) *policy.Value {
+ value := createTestAttribute(fqn, kasURL, kid)
+ if len(value.GetGrants()) > 0 && len(value.GetGrants()[0].GetKasKeys()) > 0 {
+ value.GetGrants()[0].GetKasKeys()[0].PublicKey.Algorithm = alg
+ value.GetGrants()[0].GetKasKeys()[0].PublicKey.Pem = pem
+ }
+ return value
+}
+
+func testHybridXWingFlow(t *testing.T) {
+ ctx := t.Context()
+
+ keyPair, err := ocrypto.NewXWingKeyPair()
+ require.NoError(t, err)
+ pubPEM, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+
+ writer, err := NewWriter(ctx)
+ require.NoError(t, err)
+
+ _, err = writer.WriteSegment(ctx, 0, []byte("hybrid xwing test data"))
+ require.NoError(t, err)
+
+ attributes := []*policy.Value{
+ createTestAttributeWithAlgorithm(
+ "https://example.com/attr/Classification/value/Secret",
+ testKAS1, "xwing-kid",
+ policy.Algorithm_ALGORITHM_HPQT_XWING, pubPEM,
+ ),
+ }
+ result, err := writer.Finalize(ctx, WithAttributeValues(attributes))
+ require.NoError(t, err)
+ assert.NotEmpty(t, result.Data)
+
+ keyAccess := result.Manifest.KeyAccessObjs[0]
+ assert.Equal(t, "hybrid-wrapped", keyAccess.KeyType)
+ assert.NotEmpty(t, keyAccess.WrappedKey)
+}
+
+func testHybridP256MLKEM768Flow(t *testing.T) {
+ ctx := t.Context()
+
+ keyPair, err := ocrypto.NewP256MLKEM768KeyPair()
+ require.NoError(t, err)
+ pubPEM, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+
+ writer, err := NewWriter(ctx)
+ require.NoError(t, err)
+
+ _, err = writer.WriteSegment(ctx, 0, []byte("hybrid p256 mlkem768 test data"))
+ require.NoError(t, err)
+
+ attributes := []*policy.Value{
+ createTestAttributeWithAlgorithm(
+ "https://example.com/attr/Classification/value/Secret",
+ testKAS1, "p256mlkem768-kid",
+ policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768, pubPEM,
+ ),
+ }
+ result, err := writer.Finalize(ctx, WithAttributeValues(attributes))
+ require.NoError(t, err)
+ assert.NotEmpty(t, result.Data)
+
+ keyAccess := result.Manifest.KeyAccessObjs[0]
+ assert.Equal(t, "hybrid-wrapped", keyAccess.KeyType)
+ assert.NotEmpty(t, keyAccess.WrappedKey)
+}
+
+func testHybridP384MLKEM1024Flow(t *testing.T) {
+ ctx := t.Context()
+
+ keyPair, err := ocrypto.NewP384MLKEM1024KeyPair()
+ require.NoError(t, err)
+ pubPEM, err := keyPair.PublicKeyInPemFormat()
+ require.NoError(t, err)
+
+ writer, err := NewWriter(ctx)
+ require.NoError(t, err)
+
+ _, err = writer.WriteSegment(ctx, 0, []byte("hybrid p384 mlkem1024 test data"))
+ require.NoError(t, err)
+
+ attributes := []*policy.Value{
+ createTestAttributeWithAlgorithm(
+ "https://example.com/attr/Classification/value/Secret",
+ testKAS1, "p384mlkem1024-kid",
+ policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024, pubPEM,
+ ),
+ }
+ result, err := writer.Finalize(ctx, WithAttributeValues(attributes))
+ require.NoError(t, err)
+ assert.NotEmpty(t, result.Data)
+
+ keyAccess := result.Manifest.KeyAccessObjs[0]
+ assert.Equal(t, "hybrid-wrapped", keyAccess.KeyType)
+ assert.NotEmpty(t, keyAccess.WrappedKey)
+}
+
// validateManifestSchema validates a TDF manifest against the JSON schema
func validateManifestSchema(t *testing.T, manifest *Manifest) {
t.Helper()
diff --git a/sdk/granter.go b/sdk/granter.go
index 8275a04f42..251be7a323 100644
--- a/sdk/granter.go
+++ b/sdk/granter.go
@@ -286,6 +286,12 @@ func convertAlgEnum2Simple(a policy.KasPublicKeyAlgEnum) policy.Algorithm {
return policy.Algorithm_ALGORITHM_RSA_2048
case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_RSA_4096:
return policy.Algorithm_ALGORITHM_RSA_4096
+ case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING:
+ return policy.Algorithm_ALGORITHM_HPQT_XWING
+ case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768:
+ 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_UNSPECIFIED:
return policy.Algorithm_ALGORITHM_UNSPECIFIED
default:
@@ -306,6 +312,12 @@ func convertStringToAlgorithm(alg string) policy.Algorithm {
return policy.Algorithm_ALGORITHM_RSA_2048
case ocrypto.RSA4096Key:
return policy.Algorithm_ALGORITHM_RSA_4096
+ case ocrypto.HybridXWingKey:
+ return policy.Algorithm_ALGORITHM_HPQT_XWING
+ case ocrypto.HybridSecp256r1MLKEM768Key:
+ return policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768
+ case ocrypto.HybridSecp384r1MLKEM1024Key:
+ return policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024
default:
return policy.Algorithm_ALGORITHM_UNSPECIFIED
}
@@ -490,6 +502,12 @@ func algProto2String(e policy.KasPublicKeyAlgEnum) string {
return string(ocrypto.RSA2048Key)
case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_RSA_4096:
return string(ocrypto.RSA4096Key)
+ case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING:
+ return string(ocrypto.HybridXWingKey)
+ case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_SECP256R1_MLKEM768:
+ 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_UNSPECIFIED:
return ""
}
@@ -508,6 +526,12 @@ func algProto2OcryptoKeyType(e policy.Algorithm) ocrypto.KeyType {
return ocrypto.RSA2048Key
case policy.Algorithm_ALGORITHM_RSA_4096:
return ocrypto.RSA4096Key
+ case policy.Algorithm_ALGORITHM_HPQT_XWING:
+ return ocrypto.HybridXWingKey
+ case policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768:
+ return ocrypto.HybridSecp256r1MLKEM768Key
+ case policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024:
+ return ocrypto.HybridSecp384r1MLKEM1024Key
case policy.Algorithm_ALGORITHM_UNSPECIFIED:
return ocrypto.KeyType("")
default:
diff --git a/sdk/schema/manifest-lax.schema.json b/sdk/schema/manifest-lax.schema.json
index a31abd75fb..eb605f0e91 100644
--- a/sdk/schema/manifest-lax.schema.json
+++ b/sdk/schema/manifest-lax.schema.json
@@ -52,7 +52,7 @@
"type": {
"description": "The type of key access object.",
"type": "string",
- "enum": ["wrapped", "remote"]
+ "enum": ["wrapped", "hybrid-wrapped", "remote"]
},
"url": {
"description": "A fully qualified URL pointing to a key access service responsible for managing access to the encryption keys.",
diff --git a/sdk/schema/manifest.schema.json b/sdk/schema/manifest.schema.json
index 6488623fa2..8a0e47ac94 100644
--- a/sdk/schema/manifest.schema.json
+++ b/sdk/schema/manifest.schema.json
@@ -52,7 +52,7 @@
"type": {
"description": "The type of key access object.",
"type": "string",
- "enum": ["ec-wrapped", "remote", "wrapped"]
+ "enum": ["ec-wrapped", "hybrid-wrapped", "remote", "wrapped"]
},
"url": {
"description": "A fully qualified URL pointing to a key access service responsible for managing access to the encryption keys.",
@@ -239,4 +239,4 @@
}
},
"required": ["payload", "encryptionInformation"]
- }
\ No newline at end of file
+ }
diff --git a/sdk/tdf.go b/sdk/tdf.go
index dbfdedabf3..06130771d5 100644
--- a/sdk/tdf.go
+++ b/sdk/tdf.go
@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"crypto/sha256"
+ "encoding/asn1"
"encoding/hex"
"encoding/json"
"errors"
@@ -43,6 +44,7 @@ const (
kKeySize = 32
kWrapped = "wrapped"
kECWrapped = "ec-wrapped"
+ kHybridWrapped = "hybrid-wrapped"
kKasProtocol = "kas"
kSplitKeyType = "split"
kGCMCipherAlgorithm = "AES-256-GCM"
@@ -674,7 +676,15 @@ func createKeyAccess(kasInfo KASInfo, symKey []byte, policyBinding PolicyBinding
}
ktype := ocrypto.KeyType(kasInfo.Algorithm)
- if ocrypto.IsECKeyType(ktype) {
+ switch {
+ case ocrypto.IsHybridKeyType(ktype):
+ wrappedKey, err := generateWrapKeyWithHybrid(kasInfo.Algorithm, kasInfo.PublicKey, symKey)
+ if err != nil {
+ return KeyAccess{}, err
+ }
+ keyAccess.KeyType = kHybridWrapped
+ keyAccess.WrappedKey = wrappedKey
+ case ocrypto.IsECKeyType(ktype):
mode, err := ocrypto.ECKeyTypeToMode(ktype)
if err != nil {
return KeyAccess{}, err
@@ -686,7 +696,7 @@ func createKeyAccess(kasInfo KASInfo, symKey []byte, policyBinding PolicyBinding
keyAccess.KeyType = kECWrapped
keyAccess.WrappedKey = wrappedKeyInfo.wrappedKey
keyAccess.EphemeralPublicKey = wrappedKeyInfo.publicKey
- } else {
+ default:
wrappedKey, err := generateWrapKeyWithRSA(kasInfo.PublicKey, symKey)
if err != nil {
return KeyAccess{}, err
@@ -761,6 +771,70 @@ func generateWrapKeyWithRSA(publicKey string, symKey []byte) (string, error) {
return string(ocrypto.Base64Encode(wrappedKey)), nil
}
+func generateWrapKeyWithHybrid(algorithm, publicKeyPEM string, symKey []byte) (string, error) {
+ // Step 1: Parse public key and perform hybrid KEM encapsulation (ECDH + ML-KEM)
+ // This produces a shared secret and KEM ciphertext without applying KDF.
+ var (
+ pubKey []byte
+ sharedSecret, kemCiphertext []byte
+ err error
+ )
+
+ ktype := ocrypto.KeyType(algorithm)
+ switch ktype { //nolint:exhaustive // only handle hybrid types
+ case ocrypto.HybridXWingKey:
+ pubKey, err = ocrypto.XWingPubKeyFromPem([]byte(publicKeyPEM))
+ if err != nil {
+ return "", fmt.Errorf("generateWrapKeyWithHybrid: XWingPubKeyFromPem failed: %w", err)
+ }
+ sharedSecret, kemCiphertext, err = ocrypto.XWingEncapsulate(pubKey)
+ case ocrypto.HybridSecp256r1MLKEM768Key:
+ pubKey, err = ocrypto.P256MLKEM768PubKeyFromPem([]byte(publicKeyPEM))
+ if err != nil {
+ return "", fmt.Errorf("generateWrapKeyWithHybrid: P256MLKEM768PubKeyFromPem failed: %w", err)
+ }
+ sharedSecret, kemCiphertext, err = ocrypto.P256MLKEM768Encapsulate(pubKey)
+ case ocrypto.HybridSecp384r1MLKEM1024Key:
+ pubKey, err = ocrypto.P384MLKEM1024PubKeyFromPem([]byte(publicKeyPEM))
+ if err != nil {
+ return "", fmt.Errorf("generateWrapKeyWithHybrid: P384MLKEM1024PubKeyFromPem failed: %w", err)
+ }
+ sharedSecret, kemCiphertext, err = ocrypto.P384MLKEM1024Encapsulate(pubKey)
+ default:
+ return "", fmt.Errorf("unsupported hybrid algorithm: %s", algorithm)
+ }
+ if err != nil {
+ return "", fmt.Errorf("generateWrapKeyWithHybrid: encapsulate failed: %w", err)
+ }
+
+ // Step 2: Derive wrap key from shared secret via HKDF
+ wrapKey, err := ocrypto.CalculateHKDF(tdfSalt(), sharedSecret)
+ if err != nil {
+ return "", fmt.Errorf("generateWrapKeyWithHybrid: ocrypto.CalculateHKDF failed: %w", err)
+ }
+
+ // Step 3: AES-GCM encrypt the DEK with the derived wrap key
+ gcm, err := ocrypto.NewAESGcm(wrapKey)
+ if err != nil {
+ return "", fmt.Errorf("generateWrapKeyWithHybrid: ocrypto.NewAESGcm failed: %w", err)
+ }
+ encryptedDEK, err := gcm.Encrypt(symKey)
+ if err != nil {
+ return "", fmt.Errorf("generateWrapKeyWithHybrid: ocrypto.AESGcm.Encrypt failed: %w", err)
+ }
+
+ // Step 4: ASN1 marshal at SDK layer
+ wrappedDER, err := asn1.Marshal(ocrypto.HybridNISTWrappedKey{
+ HybridCiphertext: kemCiphertext,
+ EncryptedDEK: encryptedDEK,
+ })
+ if err != nil {
+ return "", fmt.Errorf("generateWrapKeyWithHybrid: asn1.Marshal failed: %w", err)
+ }
+
+ return string(ocrypto.Base64Encode(wrappedDER)), nil
+}
+
// create policy object
func createPolicyObject(attributes []AttributeValueFQN) (PolicyObject, error) {
uuidObj, err := uuid.NewUUID()
diff --git a/sdk/tdf_hybrid_test.go b/sdk/tdf_hybrid_test.go
new file mode 100644
index 0000000000..86eb1e98e5
--- /dev/null
+++ b/sdk/tdf_hybrid_test.go
@@ -0,0 +1,84 @@
+package sdk
+
+import (
+ "testing"
+
+ "github.com/opentdf/platform/lib/ocrypto"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestCreateKeyAccessWithXWingKey(t *testing.T) {
+ symKey := []byte("0123456789abcdef0123456789abcdef")
+ keyAccess, err := createKeyAccess(KASInfo{
+ URL: "https://kas.example.com",
+ KID: "xwing-kid",
+ Algorithm: string(ocrypto.HybridXWingKey),
+ PublicKey: mockHybridXWingPublicKey,
+ }, symKey, PolicyBinding{}, "", "")
+ require.NoError(t, err)
+
+ assert.Equal(t, kHybridWrapped, keyAccess.KeyType)
+ assert.Empty(t, keyAccess.EphemeralPublicKey)
+ assert.NotEmpty(t, keyAccess.WrappedKey)
+
+ privateKey, err := ocrypto.XWingPrivateKeyFromPem([]byte(mockHybridXWingPrivateKey))
+ require.NoError(t, err)
+
+ wrappedKey, err := ocrypto.Base64Decode([]byte(keyAccess.WrappedKey))
+ require.NoError(t, err)
+
+ plaintext, err := ocrypto.XWingUnwrapDEK(privateKey, wrappedKey)
+ require.NoError(t, err)
+ assert.Equal(t, symKey, plaintext)
+}
+
+func TestCreateKeyAccessWithP256MLKEM768Key(t *testing.T) {
+ symKey := []byte("0123456789abcdef0123456789abcdef")
+ keyAccess, err := createKeyAccess(KASInfo{
+ URL: "https://kas.example.com",
+ KID: "p256mlkem768-kid",
+ Algorithm: string(ocrypto.HybridSecp256r1MLKEM768Key),
+ PublicKey: mockHybridP256MLKEM768PublicKey,
+ }, symKey, PolicyBinding{}, "", "")
+ require.NoError(t, err)
+
+ assert.Equal(t, kHybridWrapped, keyAccess.KeyType)
+ assert.Empty(t, keyAccess.EphemeralPublicKey)
+ assert.NotEmpty(t, keyAccess.WrappedKey)
+
+ privateKey, err := ocrypto.P256MLKEM768PrivateKeyFromPem([]byte(mockHybridP256MLKEM768PrivateKey))
+ require.NoError(t, err)
+
+ wrappedKey, err := ocrypto.Base64Decode([]byte(keyAccess.WrappedKey))
+ require.NoError(t, err)
+
+ plaintext, err := ocrypto.P256MLKEM768UnwrapDEK(privateKey, wrappedKey)
+ require.NoError(t, err)
+ assert.Equal(t, symKey, plaintext)
+}
+
+func TestCreateKeyAccessWithP384MLKEM1024Key(t *testing.T) {
+ symKey := []byte("0123456789abcdef0123456789abcdef")
+ keyAccess, err := createKeyAccess(KASInfo{
+ URL: "https://kas.example.com",
+ KID: "p384mlkem1024-kid",
+ Algorithm: string(ocrypto.HybridSecp384r1MLKEM1024Key),
+ PublicKey: mockHybridP384MLKEM1024PublicKey,
+ }, symKey, PolicyBinding{}, "", "")
+ require.NoError(t, err)
+
+ assert.Equal(t, kHybridWrapped, keyAccess.KeyType)
+ assert.Empty(t, keyAccess.EphemeralPublicKey)
+ assert.NotEmpty(t, keyAccess.WrappedKey)
+
+ privateKey, err := ocrypto.P384MLKEM1024PrivateKeyFromPem([]byte(mockHybridP384MLKEM1024PrivateKey))
+ require.NoError(t, err)
+
+ wrappedKey, err := ocrypto.Base64Decode([]byte(keyAccess.WrappedKey))
+ require.NoError(t, err)
+
+ plaintext, err := ocrypto.P384MLKEM1024UnwrapDEK(privateKey, wrappedKey)
+ require.NoError(t, err)
+ assert.Equal(t, symKey, plaintext)
+}
diff --git a/sdk/tdf_test.go b/sdk/tdf_test.go
index b1d5c0acf3..b5b89d30ff 100644
--- a/sdk/tdf_test.go
+++ b/sdk/tdf_test.go
@@ -259,6 +259,233 @@ A1UdIwQYMBaAFLg9mMeD25ZGvmjSYaunIPoeekzlMA8GA1UdEwEB/wQFMAMBAf8w
CgYIKoZIzj0EAwIDSAAwRQIhALYXC70t37RlmIkRDlUTehiVEHpSQXz04wQ9Ivw+
4h4hAiBNR3rD3KieiJaiJrCfM6TPJL7TIch7pAhMHdG6IPJMoQ==
-----END CERTIFICATE-----`
+
+ mockHybridXWingPublicKey = `-----BEGIN XWING PUBLIC KEY-----
+4pKOW2Z+TqohuAO7Z8m1J9Ik5jbLOZgpfKKTdEXD4mqLgXa8D5RNaYhtkfJn4js6
+MWO35ZJqlfVuCoBnruillfoEY2VD6OVB7AQqBJyzhLeAFsOYgwLIF9UBXixSo6ym
+eAA6GhYvzViUx/oQSHCI6JWhKhINXqar7usmFlxC/da4rolS9AGAkpx3S8F1VRyN
+tBahkbcLDptIqzRgOJWaXuYdtRqiuqahJyEWLjal/FQa0+dTA5oWn4IWUZRGvVut
+T/AFXMHMPdY7JmmmhNJAJTqcblHJ+FJ1YTBi0bEQE7F4XlqpdRxwISJSAGCZN6WD
+eTVF9CmpM0iJbnlN5cvAcwCFGamL5II0wwEhftMDIoCb+IiR8NQcQfJnFus9DvhR
+k5k7HVtjoumWWksL+tOudUtmYaOnV4CwyAunc8W+vsQ6edoCQWy8peRMvVcoaDUE
+tVuACiiwIWADLbsmGyiBR6x4/ashJLs46XsB4pmB1BfIf4yis+B5VvLCnZIsMvKH
+jLl81PMH4AsIytN0H/GOkJI/y1iGZsJkCZN15WJ2tAuwyMqz0yooh1lZIedgTheE
+lBKYx1YlFvmSCZBfLnKOIWFHpqkQ8OTGXWgBfvhwyhEui3ZhJbhmgBQrYAeN8ZcP
+s2isMmmzKVRcMzVFXaynv+UIiWVAH5BeXUbL0BVIkJulgXJptEyXs6JPGbEu1/ug
+uvaWx6xWQ3NiR+BOA5eIigwjoQEtyYRczlg0kUcivca+/TiE3yh2gkU2xhLNFXdL
+mHw1jNIbD5O5UPoGEdJ2XRLLVZJhhdmSWpN51FoW/OA6tJaMedtaNwjKD9wjJYEM
+izoy9cSNuWZNKMlNdNc9aPfIcQoD2xKKKZR7iHdVNpRQEYiWFrxqT8aY3JN8UjEy
+hdqeS7VAbQc28Ts7kxNa2xRmBQaOn3pb/eO+5LV/Y0Y4E7U7TXt3eBwbo5luf6Sg
+dnBjypqJAmUzpEl6MrOs7Hh7RxByyKDIgYiNAaNUnwOI7USjxlN5sKhpj+iKvCYF
+oCmRBMQ8w+p2s3GiXtB/whh1gwtIzTGkBpyaJrpjrFm67Bp88aUG3GJ5QKy/YPct
+tVKRPcNRhlsrOsEwB0qE/+Qj2gcPDAydGIp3hxiJxFgun1RQp/BkiEJW22xN2Vim
+n+tyUcRRvQCEoSU0+NXHddQvkzwHJVpdvsgRfgxHIlpTGXBReaQnRGZl2zEDVZGb
+vva6ubOu8XhMJAs1n9M41aVlP4bDmwmNv/oTKwi2kSdObkZv2INLucxtiJZ3BhbC
+NMiEXVU9DdS/USqZFpcQHqYB63hAMdmRsaM1wVW7HbRumglJY+A/hqgaV2wGtjNR
+5qNHS4FTT7euxsOs0PIxE3sOgDmseTd0UditGXd3O5xx7LkBe4GdNTuXq+rMgiZf
+P0i2ugDCV4McS4zKfpamYPQKqBufsiNkbMSVu+Mb7kQcgZZBY8gTnEyEY2k9oiJ5
+v6dH/oNa5ohGvHJjEcm4/3y3C7er0OKKM8JLkuIuUYsP7yqPY0V8LPjKI/wS0wxS
+yv8kgAJe+QrgMAOzPsw5fAeK5Lrz+OhSRsF/hRJnlAgbv/UAHZQR7ueSrL6Tj8tY
+Ubd0E5EZlOEecFd/41z5QA==
+-----END XWING PUBLIC KEY-----`
+
+ // X-Wing private key is a 32-byte seed; the full X25519 + ML-KEM-768
+ // components are derived from it at runtime by circl.
+ mockHybridXWingPrivateKey = `-----BEGIN XWING PRIVATE KEY-----
+7uCvk28wGoVrwW5nU2huW28UXWa5tZMom6Zds8uohrA=
+-----END XWING PRIVATE KEY-----`
+
+ mockHybridP256MLKEM768PublicKey = `-----BEGIN SECP256R1 MLKEM768 PUBLIC KEY-----
+BPYx2u2gwPgPG8Jzeu94dWjTTcGpEHKTzGVkGQTAR8dVWr7HP8U9UZpe5tlhOeUF
+r34nX9M9Lg+nf6feva6iYNb0aLMPIiRc7IaOVb+rhR5ZysvEMTsHiw3GU40dfFD6
+obRGY37RSElKw6xRKmDha2mt2Lrk0bF30IpRjMDwR6a4IJMdulGzPDa8HCXrypq3
+CJmx0W8b86mlMBsX1slFN6qZg8sQjCwRYVMlVnfWKg1CyE1FQUeF2suIElT+BEyn
+wiB1pSOwLLkVEki1Y0CEJr1rq6IRlzd6Cac8TA476mFME3diR04IWDNS+BK/+2Or
+tYHwqbYJgggKvCrbibRMXBV8Wj2bGcZFijxhF18VGkl08KFl4SGd5hTfZh7vcqQt
+zARs00da93WH2M7DFhvQ86GMezhY04aUoLUXMxS3ya01NbEB5z++U6O30CycYCI4
+Ib0Ae6BnHFoRuola9Ekz/CqBFRGxQchqwG3t+Afsk42yCcMFvL6tFCdNNEUA/bGU
+7Bbo+68Rgh0/UUTjAVSM6b21YU8ld1cf1q/SRnOw6xkcSa23qKP+Sz6RM2Vi4Vyp
+1GYvMoFuA1y5VMMPHCBUvCt2Sh0qYsPRcMCPQaMbWRQIRwDXNBzsAJSSJBoicCt3
+GxSaVqi7Vyqo28XFyQ5W53CbtRO4wU25UMYL1kO0KplHCFIk9iOToaa5LL1O0HcR
+BITaRLNL5pFFjAyQWrJN9xXCojNce1+DxVNC28POKk8Gh4pWgm59xbzxjDOA6XQ3
+YJsawpaU90mZeiATU1B9ORynIVQnlzQIhnREGDEjuCHkCsM/4RE4MRsx1hkgiD1j
+VhIA8ZGivG3ikwNc8Ue5KQurcc5UmYGwR4T0J5sJOhgBDHpZgXFZR5+dokLBmIlR
+LLZFVB0x+3cXfAWSrIdi6Yi2SakueMzuU206+KwmtBxVABJXeVh+WC1luwgXgGsM
+AFmqlxtmdBjd0bUU1LUIoRuVWROrEsfLIkgfVFt9bBwlscEZpnz+U3/89oYbQj+R
+6rkiK0+RcgQYh27fyjW4/FTFFWLdVmOK+TWkrCIbEa0mPColi8mfh8SqFSphcXYd
+JsLZe3Pnw3G3hauX6TntFA4PIjiEpXvL968fg48Fly7iaCSW2Q8EtHz+oYpLew6l
+wjvcEEG9XJ3ahD0yM4FF2jKbiDPuvKJZaLMetEGOZxtgMz+OwmEf1pnZJUqGN3r9
+EaAoDMxAxCpCA3+Accar0RUBqmdzQWYai3YdaT7vkX9IMAae+7vQiT90FCdoQh8c
+tHhL+i0I8UXRHKZUpySzAB53t3n702twa2U4BHr0eBbKVn7z92seI2mV2zRRClQL
+gnTMGj0DMq9m9kDV+ZOGtlpLuzxW9sZ9DF2YzJvgXHwjTH0QKzgj8cF8JZB5R8zI
+9j3hOrzWkrxUxk20Oqhqm1Xla5uDW6LTq57BlBo92F+FchmGAU6bNJj+2l91aK+P
+aYx65yRfpUxD2k5pZKmg+4qWZmIvgsiVqyV3iGtQGbi1CxYpPB4SVR3juF2Mygf/
+0GN8EIozpWBfnBw/12a20GnFGw2EZyHGxRjJ+7rGRoca9TZG0MFygnHVcJfxxSki
+EyMyy34IliaD+xOCFSMMOlz6suUgEsDfVZEw/FwWOISUwfT9wOLO4K9V2VdFNAD9
+MA==
+-----END SECP256R1 MLKEM768 PUBLIC KEY-----`
+
+ mockHybridP256MLKEM768PrivateKey = `-----BEGIN SECP256R1 MLKEM768 PRIVATE KEY-----
+n1klZ0/US1beIf9dVVOZXCmw947L71pDnbkZq2BlWd5nqIiZppeHg2plJm8MhL68
+9lFGATAH20fqtbLvbHw8dTqFClKmm2tPFotJFs55mnnyKHGQxHhckiOzlp8YOEZT
+cWA2RQvVVG1nGLiFeZUDMzZqZRVe1MVsAh28eEAIskmzVqkvWIi9hqJuW6/vlXJx
+WW68xry4e86xCTBxhZOeS4ysJKlSgkgRCFEV2M3HPKGtZWR75RWQxBzSgmJ0MsIE
+FmKSA2K4dCSLRIJHlASao5l1N7dIJFP74ZqWJ45LZwUnG8WAMmDWwZlDWBBgiyWa
+hmfeymYdJmBASVcRdxwqixLiezOqkAgfZKBFdDaeIoAmR3cc4AYaBhwxWZtAEpky
+6cQ39MmTvDWcBb/x7H3SawABkbNzZFmuMiOkMQQkAZ8f2xUaDLNc+XliorYupGEM
+Es/rg6T1KaKD5U+aBHMGAsGl129J+1DUdUtxy2m2XMVQFB37EEFGQw+5M8jhuIXL
+p8ScZbfrikrbFln0qRO70MFFt8AdlZxxWHpjpIh486/CeB5zw23MRZGqQ19AkahW
+SHy8Arr8J74/3Dc6sBvTFaRGKlOUBxnN/I5XRzZANShsC0SGsEF6pLrKwSz11jP+
+NHlx22CUYhWkvBO6mZcDoTJR83cHmHOxYDh0sGI9AXU9RIvjZRFzBrrtR6Gu0sUs
+KS4gYE/GJ4RXhgR39yxfHKzJllAJCr4lKLV6xVTKBjxy6JcM5lNcRBTgcz6e5S36
+9KcYhTF1F5y2pIaK8qXsWaB88Hjb9cN/ZRnDOSXkQgxvaY78QFzd4ccs9jDf920b
+NymdmiUZsXUjqIqRHCCLgHNnRYAOrDo0eyVXNmidExCJeQJWtj7AcIQZJsHlmkvw
+kMWetSb6uGIkFpIvo4jp+3baJSmERMUNF1WfS8B3e0bCDEnY6h8nBbIw6CHEC1gx
+x49oErGiAlAnA8QFRU/ghBPS4YWPVAfLOoPlek7/wMwn0LBvOo1WwbOmUpVfqwtW
+NzVCipG0AFVy+QbSKhpAsVcxuSbTZI0W9LZF67S0ixe6E2SGtj+WGm6/6JjGOExo
+CQToAVDhoUDEU8asJowbZH5eCgwPK4Nh7Ahr6s+NUSpxBRa/FTyTlKPUJ3bl6Enz
+CxbIgTOCtVGC1JUu8y6P8BgsMUSG9BxZkc3Cd5sbQwQNwmzfRzPh6Dqrdrxay6DF
+mc2A4Yr40D4jZ3Hdaaq+BQZqOqX6jLxcRAB3aS8Des+TqjWq5pMzA7dDt8odbHqP
+9kn/xMPX6jtLV2hlQIbmdRwx+IRroF5jNjZW+s785SN8+He6qyw4Kby4gA5rHDS0
+x4POl2PJBqeCu0vI/Mb5jFePplYxJ4eUVrHpkjdVmDKtVm/TYL0oGFeYksV0NJ5v
+YiIJZAYpCxulODL4IB9WBM+gS8v5ZgctOa/Su7limVqB6TSeViiVBGE+a0OlsU0f
+c8oXTBWIy808crb5NcAgB8A0ZyPG1ESuFm25YXh80x3Pookk2MD4krCYm3hPVqaT
+42VaRkAcm1SgsUNzyZQlxrSIS73JZW7ymij0QjMexDH0aLMPIiRc7IaOVb+rhR5Z
+ysvEMTsHiw3GU40dfFD6obRGY37RSElKw6xRKmDha2mt2Lrk0bF30IpRjMDwR6a4
+IJMdulGzPDa8HCXrypq3CJmx0W8b86mlMBsX1slFN6qZg8sQjCwRYVMlVnfWKg1C
+yE1FQUeF2suIElT+BEynwiB1pSOwLLkVEki1Y0CEJr1rq6IRlzd6Cac8TA476mFM
+E3diR04IWDNS+BK/+2OrtYHwqbYJgggKvCrbibRMXBV8Wj2bGcZFijxhF18VGkl0
+8KFl4SGd5hTfZh7vcqQtzARs00da93WH2M7DFhvQ86GMezhY04aUoLUXMxS3ya01
+NbEB5z++U6O30CycYCI4Ib0Ae6BnHFoRuola9Ekz/CqBFRGxQchqwG3t+Afsk42y
+CcMFvL6tFCdNNEUA/bGU7Bbo+68Rgh0/UUTjAVSM6b21YU8ld1cf1q/SRnOw6xkc
+Sa23qKP+Sz6RM2Vi4Vyp1GYvMoFuA1y5VMMPHCBUvCt2Sh0qYsPRcMCPQaMbWRQI
+RwDXNBzsAJSSJBoicCt3GxSaVqi7Vyqo28XFyQ5W53CbtRO4wU25UMYL1kO0KplH
+CFIk9iOToaa5LL1O0HcRBITaRLNL5pFFjAyQWrJN9xXCojNce1+DxVNC28POKk8G
+h4pWgm59xbzxjDOA6XQ3YJsawpaU90mZeiATU1B9ORynIVQnlzQIhnREGDEjuCHk
+CsM/4RE4MRsx1hkgiD1jVhIA8ZGivG3ikwNc8Ue5KQurcc5UmYGwR4T0J5sJOhgB
+DHpZgXFZR5+dokLBmIlRLLZFVB0x+3cXfAWSrIdi6Yi2SakueMzuU206+KwmtBxV
+ABJXeVh+WC1luwgXgGsMAFmqlxtmdBjd0bUU1LUIoRuVWROrEsfLIkgfVFt9bBwl
+scEZpnz+U3/89oYbQj+R6rkiK0+RcgQYh27fyjW4/FTFFWLdVmOK+TWkrCIbEa0m
+PColi8mfh8SqFSphcXYdJsLZe3Pnw3G3hauX6TntFA4PIjiEpXvL968fg48Fly7i
+aCSW2Q8EtHz+oYpLew6lwjvcEEG9XJ3ahD0yM4FF2jKbiDPuvKJZaLMetEGOZxtg
+Mz+OwmEf1pnZJUqGN3r9EaAoDMxAxCpCA3+Accar0RUBqmdzQWYai3YdaT7vkX9I
+MAae+7vQiT90FCdoQh8ctHhL+i0I8UXRHKZUpySzAB53t3n702twa2U4BHr0eBbK
+Vn7z92seI2mV2zRRClQLgnTMGj0DMq9m9kDV+ZOGtlpLuzxW9sZ9DF2YzJvgXHwj
+TH0QKzgj8cF8JZB5R8zI9j3hOrzWkrxUxk20Oqhqm1Xla5uDW6LTq57BlBo92F+F
+chmGAU6bNJj+2l91aK+PaYx65yRfpUxD2k5pZKmg+4qWZmIvgsiVqyV3iGtQGbi1
+CxYpPB4SVR3juF2Mygf/0GN8EIozpWBfnBw/12a20GnFGw2EZyHGxRjJ+7rGRoca
+9TZG0MFygnHVcJfxxSkiEyMyy34IliaD+xOCFSMMOlz6suUgEsDfVZEw/FwWOISU
+wfT9wOLO4K9V2VdFNAD9MNpO9P5ukHVRUM4uu9Zr7SPXt/R7sVivRIoLWxuxAgLh
+RMy1GXVGKwc4Va40UVWAM5VyiiFT3kxsPryyTv8ji5A=
+-----END SECP256R1 MLKEM768 PRIVATE KEY-----`
+
+ mockHybridP384MLKEM1024PublicKey = `-----BEGIN SECP384R1 MLKEM1024 PUBLIC KEY-----
+BH1Lgfame2/B1mB7EVQPtrSOb4lNa/H03q1K6X1KIFhR4HeelPtS75jhDyIQZDAH
+qCTI8MpxDBRn+1H1vQZTCOMr9oa/RDicb3UGQsEZVM9pApSZlzurFctZR1nzDpE9
+ASqhC3dlqElBJgxKZGhDFETKkeuzesG0Q4WslBfpVNcHYUTRQg7XptKnmeYDq79w
+V8kUFv3xutPLLtfXWlxJg2zRlxDljbnEtsuGR7D0pegzZi3buTspYjZEXznmgCnU
+HqpjoVfnVZkhChuAbHw8fXi3Kwgnt7dgiwWiVshmQqYXIVW6LX7imjP0BGpcMKJM
+Fjf7rOCKH8Bhj7c7ygE7MaVhR4x5T7UjwMVky7CILjvBhmj6wNd4CmcazGMVzVPq
+aiMFwq7II0vmT68XN54UtMt0bdpFa/9SVWILReEJYo4ZN8hAtAZ5o2BitCYYZ56b
+Lf6SVEfWCg20zikpRSvLRFooRAcIr+2jQHOcMoiJHhUQj/Jzlg5GCJa2GTv7qsBm
+GemDLN/KXgHIxUYzVFgQMBplCqjsQ7lpfVKZCivHuqCnJ4HJHkiZPwvbdkEyD8+r
+Ir/xyFS0ZkSmCVtaF2LQImHxL5VBP2C3N9zHwcdnbEiixTJyoY8SKHZHLBpYM155
+l3F7kDCpVjliErF7zo4QZdX8YlZkwDYMIgGlB9tsDzSYMr1ZNL/ZDAHSE7NMRL6m
+I2zblG2GlN2FIPWTEHLVX5i0sbw3aZcYaIABZ6wxB8O1hsbrWsjxolVTNK8HAsgy
+mWZBbIwifxrqphjgzNt6I8WBN3aSdh9jnLVKnTlsrvh5eqSkgu/HVVxsr430zNTF
+TOKMya62Jf0HNbcbaDXxSTmQr3qZA148cs5kpiWYudyse22giQQmTiXgHIUAR4mD
+vSTrk5P6azwkqR0AxBBqXMBsBt2aAygEo6/LjrNjerSlbAbRBv3VNJVihCe8DVOn
+gN8XuKl8X3JcnggwxNriubJaDemDN3GIzvtBJwFGMMzpQmxciksiKgC7iXenJfQ7
+B95kFcQWZcsDWBdZfXVWfDv5GeXxnMHczD3IisJgnNq1twqYrBQZg2+UjgWFylxE
+C/5JK6bVfy6TuYewIsAwniZBYcBhVpQGzPj3snGYi6YbUjNinbJLq545e3MwrMD1
+XELGd+SRLQDbFTE8jTuUAKuUiUqULfiMfo/mYr5cM16XhjRVdhwbTJ8VFAaJM3Ok
+hoK7alSFBq92lpKYzlVUwHKTRxQgViPJMirgdfscC0ViQUrGD2YpoIfbgvjkHxFq
+x7iJzF6Cq1tSHE5gMCK1a8e1tAJ5pvDUqc1XCu9WAnERrQ1Lb2xDnogJzJkMhIyM
+LqmxMzwRH1TZSOMWvrAXfCHhh7IlnWmVBGh4wtCUbD4kG5uRWbW3e1JhbgHJg3Kz
+z7qoQRcyfniCntAcOCBpe1+7VV32TWfKyJaLblaAPndAK2AwQgRcyafnVGUklB/c
+SVDjNci4HiOAi4eWDJOYyuBrdOYTdfUBYlO5vm+rfOyIFIBCMWmlIvNMaFGibUeg
+b5WUo9cSlpTgNsdLsqHjM4E0kViBricsYgoVe4ekGpyjRcIbK0GSOfhYupxqsWUM
+a+38LMZyJKCVUhAcP/GqcXCDYSRqmgjDv39wkhmVHibhQvuGJx/MfN9btMWTQCRD
+f1TXyCVsCyU5znhEOM+WDAvhr/iiyrcVFAcwnPTstSqRfrszH53CjNVVyzAzaOhh
+Q+4MneLWQWfxCicWrLzMa1DSh3hMrUyzxdn4MFEWGgnoVsJjBqfcAzEsK8AUDsnp
+kfTAZyVFF7SJoi9osvkxVYbBAj/gDGvFKb/RIjhFEwQclsj0jiV6onA2vHzbNJd8
+hiJAdYGad6FUEAsFN7isQI/KdN2QF8vZKC4qynNarEJKTMJ3U3jBNUPZFKA6rpJK
+IF1hRi+aOVdjLLCoEMYmSHsysn8Gkh+VrSLng3EEQRkMljPoe3lTD+QGyg6Ff/Vm
+DI1EPCTga6j5YU7qMKZrztRlTqwXILe8h6tgRE10PPPhk3UahdSsdLT1J5YYAbK4
+C0T3A+dFYRq3o3NZwQj5EWIKA/RpWTi8vP2khX7HUfhgSNFjAk/DDoTkYpxkNkPj
+U6rGHS2VxplYlFpMtumqPjQ4x6oruVGrM7FEEpaCCRgXwxZ1cLpzlL61WcR6Bb7U
+S4SKDN195Gc9OmEyAhREZc2p5VJFZJEyL7qj8nYHffuH
+-----END SECP384R1 MLKEM1024 PUBLIC KEY-----`
+
+ mockHybridP384MLKEM1024PrivateKey = `-----BEGIN SECP384R1 MLKEM1024 PRIVATE KEY-----
+M57WXgMFtuzS69e108gvEWxnnIQEsn6NyrIyEVbjSupYJUJ14B5gcprEbvJnWQff
+lqwlTYJxFDtb9JMxodphWkwYkrkaGliKWBC4mzu6S1IyRGKyYByohnc3apZt9dRx
+PRChD8gbUfYN61RMkSUYxveD/HjDcodXYycrKJSrrrJlHZM73ZqklyApIDKJ+caQ
+wHsraHRPjIfEIwR9sfLLYApsPbyoblsKhJVhHxRgyHbD7MOmGHF6rbfEAwSSVuG/
+MMo4CigbYBwOYMKChjwqZqrGl9A6qmqFxTcT9siNSJiM6unIviOXKLqUe8qV3PqX
+ZLM2PylxVYRZ0oGoJUnKJNZCsZJWQOgU0sQFGAaDVdHAdkIb7ltbAzUUhpEpAdkc
+IYFBYODGHdpgjfMYfmemNwpqjUxpj+St+0l0fIEhE5WvvHcp9bOJl6Aal7FjvpMA
+dcsxG+y+Z1Mu0ZxorwGkjYkhRDeGDPAcqNmcFyS+BECg3Uuo7bcCXCjD3Pc5KGJ9
+X+tydEabP2WDyLCYQqoOzTd1riAPRZQG5OSdtOAi0WfP2SvObjCiInzIDms+jYyS
+gqZT7kqgNOsr/hQ5XmtK5lVwg/RzHApn0qEOzJWWQrRQL6EiU1MH6/gyvfe6Pely
++ftjmMnPWTq4E/mVvlmMqlyG09VoH9V65eBimKoysgAbKVl2KkKTUkFjfiRKFYFg
+wvWyj/wp1tARpMxxzDYDmZMdCGJbSyQZ6fm8gTAXGgbD4UfEEbpwBGBwzsh15VU/
+ucOxgrkNJStR44pkTWHE6DV2ofMy/9av8eU4bOgc3iKxV3kYRqdkEJEtxXG143me
+3AwjJTZAHkQoHLkv2bq4sYWfXHC3eFxiRsJLeYUu8pVqOQS6WyBp3yVL7PqPp+OD
+ApE76Ke2VzhLgVxLUNWGFiANm0oVq+A2ieQik8SjUycmO3WLzfp7s2w0y1JpFOt2
+UZWK7pQKNGCL+imn2kVy1GESoJwyADyxUOWSqqLA1CJ1kWZKwHyiqypAt1W67KIW
+KGDAL8GX5YMt4Uk0pcPFJBON/dUZeIkduhaZaGR3pRK2uhAToxAEgJMe1adDmEuu
+vpwyYCgB+0lY/laNgidpyrNcarNneRTKNzC6EveTwxuHjnJNSgiQuxtZLfU0MwqI
+MjZUNrQubDYRBDYZZ4sBr4YxJwcD+5DAdUMwR4FhfcbN9LmDPkNKxClK3Nd0Keof
+oLfCfdgmEHd0O4kz2PfIlUgEzViD6stGKPBdF7K4JYJ4LnKxhxIodaqsaIjGKum/
+TQySQSNbPdGNrAGJR6uAi7gTYmMwa7gKilqg+zZ8FEhglGnDNlsyp8SXqCWb5awJ
+cAM67ZiVdjIEeeaCEMqjhDKIKCpxbPA0bvEhOkEDg9QYVdmR1iYplMMTnaoLSPZi
+mYQsLMKvKlC6fcEelmTHlQogPcZPlnOmOvF+pXm7qbNgPoAjivx1h3s4aSpLmXVJ
+ujYJglIcFhbJ/Be2Smw7WdqlXCTP+pJYAkA1oNsSgbCHI6S0NEzJPQtehoo4KOOM
+6YG4l0E4OXjDUWbOO4gS79xodsG0IeEbpfBaq3eGoAIvuqRitpQEOXkN9iZNUHKc
+vAtjyyM3WXK3XWlQ8ViCO7Rf4yDKR3RQLUUzBbrONgY9pbY71mFlnrGnm1GO2/Gm
+WeMzlQkZVMZxg7NUNSUk5vI0rZZWclPJgqg7tUw7SvGTG6pOpmcFfcnC9WV34XfP
+oNO1t4OcBaY9cawEebOK0WquvZRYmPYSOvDHqaek3LB5TteowSBp4tQlsWB0SJwP
+MNpR0PaIgVFFOwk45EJFMVDEZRRNgPsCerI93qXBOToEVSDElbu+j2UuhKmuxBNg
+/OXEiRqoxreTBHxAXEcZCVux/FhTWbzLJvZU7zYIEfYTgtRxUSZ8wkoD5AuF6yJD
+nLUbXwKXohYdhkuobbTPjFLHacGiYQtf3bxNfRTNYQW4pSeYs9VmEqVrk0KwONLO
+fya1p5rODxg04uZYENrG5hnA7oIhd0UBTqJ8RbqfQ+VYVZATPnBExCmqg6A0vbEt
+87M+gqsSr4k6QvXL1UwsMDrFVwoAlzEeXhZAwcE3kNENYdRjIMQPmZqaKYYhb1th
+KqELd2WoSUEmDEpkaEMURMqR67N6wbRDhayUF+lU1wdhRNFCDtem0qeZ5gOrv3BX
+yRQW/fG608su19daXEmDbNGXEOWNucS2y4ZHsPSl6DNmLdu5OyliNkRfOeaAKdQe
+qmOhV+dVmSEKG4BsfDx9eLcrCCe3t2CLBaJWyGZCphchVbotfuKaM/QEalwwokwW
+N/us4IofwGGPtzvKATsxpWFHjHlPtSPAxWTLsIguO8GGaPrA13gKZxrMYxXNU+pq
+IwXCrsgjS+ZPrxc3nhS0y3Rt2kVr/1JVYgtF4Qlijhk3yEC0BnmjYGK0Jhhnnpst
+/pJUR9YKDbTOKSlFK8tEWihEBwiv7aNAc5wyiIkeFRCP8nOWDkYIlrYZO/uqwGYZ
+6YMs38peAcjFRjNUWBAwGmUKqOxDuWl9UpkKK8e6oKcngckeSJk/C9t2QTIPz6si
+v/HIVLRmRKYJW1oXYtAiYfEvlUE/YLc33MfBx2dsSKLFMnKhjxIodkcsGlgzXnmX
+cXuQMKlWOWISsXvOjhBl1fxiVmTANgwiAaUH22wPNJgyvVk0v9kMAdITs0xEvqYj
+bNuUbYaU3YUg9ZMQctVfmLSxvDdplxhogAFnrDEHw7WGxutayPGiVVM0rwcCyDKZ
+ZkFsjCJ/GuqmGODM23ojxYE3dpJ2H2OctUqdOWyu+Hl6pKSC78dVXGyvjfTM1MVM
+4ozJrrYl/Qc1txtoNfFJOZCvepkDXjxyzmSmJZi53Kx7baCJBCZOJeAchQBHiYO9
+JOuTk/prPCSpHQDEEGpcwGwG3ZoDKASjr8uOs2N6tKVsBtEG/dU0lWKEJ7wNU6eA
+3xe4qXxfclyeCDDE2uK5sloN6YM3cYjO+0EnAUYwzOlCbFyKSyIqALuJd6cl9DsH
+3mQVxBZlywNYF1l9dVZ8O/kZ5fGcwdzMPciKwmCc2rW3CpisFBmDb5SOBYXKXEQL
+/kkrptV/LpO5h7AiwDCeJkFhwGFWlAbM+PeycZiLphtSM2Kdskurnjl7czCswPVc
+QsZ35JEtANsVMTyNO5QAq5SJSpQt+Ix+j+ZivlwzXpeGNFV2HBtMnxUUBokzc6SG
+grtqVIUGr3aWkpjOVVTAcpNHFCBWI8kyKuB1+xwLRWJBSsYPZimgh9uC+OQfEWrH
+uInMXoKrW1IcTmAwIrVrx7W0Anmm8NSpzVcK71YCcRGtDUtvbEOeiAnMmQyEjIwu
+qbEzPBEfVNlI4xa+sBd8IeGHsiWdaZUEaHjC0JRsPiQbm5FZtbd7UmFuAcmDcrPP
+uqhBFzJ+eIKe0Bw4IGl7X7tVXfZNZ8rIlotuVoA+d0ArYDBCBFzJp+dUZSSUH9xJ
+UOM1yLgeI4CLh5YMk5jK4Gt05hN19QFiU7m+b6t87IgUgEIxaaUi80xoUaJtR6Bv
+lZSj1xKWlOA2x0uyoeMzgTSRWIGuJyxiChV7h6QanKNFwhsrQZI5+Fi6nGqxZQxr
+7fwsxnIkoJVSEBw/8apxcINhJGqaCMO/f3CSGZUeJuFC+4YnH8x831u0xZNAJEN/
+VNfIJWwLJTnOeEQ4z5YMC+Gv+KLKtxUUBzCc9Oy1KpF+uzMfncKM1VXLMDNo6GFD
+7gyd4tZBZ/EKJxasvMxrUNKHeEytTLPF2fgwURYaCehWwmMGp9wDMSwrwBQOyemR
+9MBnJUUXtImiL2iy+TFVhsECP+AMa8Upv9EiOEUTBByWyPSOJXqicDa8fNs0l3yG
+IkB1gZp3oVQQCwU3uKxAj8p03ZAXy9koLirKc1qsQkpMwndTeME1Q9kUoDqukkog
+XWFGL5o5V2MssKgQxiZIezKyfwaSH5WtIueDcQRBGQyWM+h7eVMP5AbKDoV/9WYM
+jUQ8JOBrqPlhTuowpmvO1GVOrBcgt7yHq2BETXQ88+GTdRqF1Kx0tPUnlhgBsrgL
+RPcD50VhGrejc1nBCPkRYgoD9GlZOLy8/aSFfsdR+GBI0WMCT8MOhORinGQ2Q+NT
+qsYdLZXGmViUWky26ao+NDjHqiu5UaszsUQSloIJGBfDFnVwunOUvrVZxHoFvtRL
+hIoM3X3kZz06YTICFERlzanlUkVkkTIvuqPydgd9+4eakXODFvtYYpzITAPhjVTY
+MExDqHROecZV6EN78TKr38WTGPPTAlmQOgOjHen8zHNwJNy50uv3fYfFkQ1xzL1y
+-----END SECP384R1 MLKEM1024 PRIVATE KEY-----`
)
type TestReadAt struct {
@@ -349,6 +576,7 @@ func (s *TDFSuite) Test_SimpleTDF() {
tdfOptions []TDFOption
tdfReadOptions []TDFReaderOption
useHex bool
+ expectedSize int64 // override default expectedTdfSize if non-zero
}
metaData := []byte(`{"displayName" : "openTDF go sdk"}`)
@@ -428,6 +656,54 @@ func (s *TDFSuite) Test_SimpleTDF() {
},
useHex: true,
},
+ {
+ name: "metadata-hybrid-p256-mlkem768",
+ tdfOptions: []TDFOption{
+ WithKasInformation(KASInfo{
+ URL: s.kasTestURLLookup["https://f.kas/"],
+ PublicKey: "",
+ }),
+ WithMetaData(string(metaData)),
+ WithDataAttributes(attributes...),
+ WithWrappingKeyAlg(ocrypto.HybridSecp256r1MLKEM768Key),
+ },
+ tdfReadOptions: []TDFReaderOption{
+ WithKasAllowlist([]string{s.kasTestURLLookup["https://f.kas/"]}),
+ },
+ expectedSize: 3364,
+ },
+ {
+ name: "metadata-hybrid-p384-mlkem1024",
+ tdfOptions: []TDFOption{
+ WithKasInformation(KASInfo{
+ URL: s.kasTestURLLookup["https://g.kas/"],
+ PublicKey: "",
+ }),
+ WithMetaData(string(metaData)),
+ WithDataAttributes(attributes...),
+ WithWrappingKeyAlg(ocrypto.HybridSecp384r1MLKEM1024Key),
+ },
+ tdfReadOptions: []TDFReaderOption{
+ WithKasAllowlist([]string{s.kasTestURLLookup["https://g.kas/"]}),
+ },
+ expectedSize: 4048,
+ },
+ {
+ name: "metadata-hybrid-xwing",
+ tdfOptions: []TDFOption{
+ WithKasInformation(KASInfo{
+ URL: s.kasTestURLLookup["https://h.kas/"],
+ PublicKey: "",
+ }),
+ WithMetaData(string(metaData)),
+ WithDataAttributes(attributes...),
+ WithWrappingKeyAlg(ocrypto.HybridXWingKey),
+ },
+ tdfReadOptions: []TDFReaderOption{
+ WithKasAllowlist([]string{s.kasTestURLLookup["https://h.kas/"]}),
+ },
+ expectedSize: 3320,
+ },
}
for _, config := range testConfigs {
@@ -448,11 +724,14 @@ func (s *TDFSuite) Test_SimpleTDF() {
tdfObj, err := s.sdk.CreateTDF(fileWriter, bufReader, config.tdfOptions...)
s.Require().NoError(err)
+ expected := expectedTdfSize
if config.useHex {
- s.InDelta(float64(expectedTdfSizeWithHex), float64(tdfObj.size), 64.0)
- } else {
- s.InDelta(float64(expectedTdfSize), float64(tdfObj.size), 64.0)
+ expected = expectedTdfSizeWithHex
+ }
+ if config.expectedSize != 0 {
+ expected = config.expectedSize
}
+ s.InDelta(float64(expected), float64(tdfObj.size), 64.0)
// test meta data and build meta data
readSeeker, err := os.Open(tdfFilename)
@@ -2630,23 +2909,26 @@ func (s *TDFSuite) startBackend() {
fa := &FakeAttributes{s: s}
kasesToMake := []struct {
- url, private, public, kid string
+ url, private, public, kid, algorithm string
}{
- {"http://localhost:65432/", mockRSAPrivateKey1, mockRSAPublicKey1, defaultKID},
- {"http://[::1]:65432/", mockRSAPrivateKey1, mockRSAPublicKey1, defaultKID},
- {"https://a.kas/", mockRSAPrivateKey1, mockRSAPublicKey1, defaultKID},
- {"https://b.kas/", mockRSAPrivateKey2, mockRSAPublicKey2, defaultKID},
- {"https://c.kas/", mockRSAPrivateKey3, mockRSAPublicKey3, defaultKID},
- {"https://d.kas/", mockECPrivateKey1, mockECPublicKey1, "e1"},
- {"https://e.kas/", mockECPrivateKey2, mockECPublicKey2, defaultKID},
- {kasAu, mockRSAPrivateKey1, mockRSAPublicKey1, defaultKID},
- {kasCa, mockRSAPrivateKey2, mockRSAPublicKey2, defaultKID},
- {kasUk, mockRSAPrivateKey2, mockRSAPublicKey2, defaultKID},
- {kasNz, mockRSAPrivateKey3, mockRSAPublicKey3, defaultKID},
- {kasUs, mockRSAPrivateKey1, mockRSAPublicKey1, defaultKID},
- {baseKeyURL, mockRSAPrivateKey1, mockRSAPublicKey1, baseKeyKID},
- {evenMoreSpecificKas, mockRSAPrivateKey3, mockRSAPublicKey3, "r3"},
- {obligationKas, mockRSAPrivateKey3, mockRSAPublicKey3, "r3"},
+ {"http://localhost:65432/", mockRSAPrivateKey1, mockRSAPublicKey1, defaultKID, "rsa:2048"},
+ {"http://[::1]:65432/", mockRSAPrivateKey1, mockRSAPublicKey1, defaultKID, "rsa:2048"},
+ {"https://a.kas/", mockRSAPrivateKey1, mockRSAPublicKey1, defaultKID, "rsa:2048"},
+ {"https://b.kas/", mockRSAPrivateKey2, mockRSAPublicKey2, defaultKID, "rsa:2048"},
+ {"https://c.kas/", mockRSAPrivateKey3, mockRSAPublicKey3, defaultKID, "rsa:2048"},
+ {"https://d.kas/", mockECPrivateKey1, mockECPublicKey1, "e1", "rsa:2048"},
+ {"https://e.kas/", mockECPrivateKey2, mockECPublicKey2, defaultKID, "rsa:2048"},
+ {kasAu, mockRSAPrivateKey1, mockRSAPublicKey1, defaultKID, "rsa:2048"},
+ {kasCa, mockRSAPrivateKey2, mockRSAPublicKey2, defaultKID, "rsa:2048"},
+ {kasUk, mockRSAPrivateKey2, mockRSAPublicKey2, defaultKID, "rsa:2048"},
+ {kasNz, mockRSAPrivateKey3, mockRSAPublicKey3, defaultKID, "rsa:2048"},
+ {kasUs, mockRSAPrivateKey1, mockRSAPublicKey1, defaultKID, "rsa:2048"},
+ {baseKeyURL, mockRSAPrivateKey1, mockRSAPublicKey1, baseKeyKID, "rsa:2048"},
+ {evenMoreSpecificKas, mockRSAPrivateKey3, mockRSAPublicKey3, "r3", "rsa:2048"},
+ {obligationKas, mockRSAPrivateKey3, mockRSAPublicKey3, "r3", "rsa:2048"},
+ {"https://f.kas/", mockHybridP256MLKEM768PrivateKey, mockHybridP256MLKEM768PublicKey, "h1", string(ocrypto.HybridSecp256r1MLKEM768Key)},
+ {"https://g.kas/", mockHybridP384MLKEM1024PrivateKey, mockHybridP384MLKEM1024PublicKey, "h2", string(ocrypto.HybridSecp384r1MLKEM1024Key)},
+ {"https://h.kas/", mockHybridXWingPrivateKey, mockHybridXWingPublicKey, "h3", string(ocrypto.HybridXWingKey)},
}
fkar := &FakeKASRegistry{kases: kasesToMake, s: s}
@@ -2661,7 +2943,7 @@ func (s *TDFSuite) startBackend() {
s.kases[i] = FakeKas{
s: s, privateKey: ki.private, KASInfo: KASInfo{
- URL: ki.url, PublicKey: ki.public, KID: ki.kid, Algorithm: "rsa:2048",
+ URL: ki.url, PublicKey: ki.public, KID: ki.kid, Algorithm: ki.algorithm,
},
legakeys: map[string]keyInfo{},
attrToRequiredObligations: obligationMap,
@@ -2750,7 +3032,7 @@ type FakeKASRegistry struct {
kasregistryconnect.UnimplementedKeyAccessServerRegistryServiceHandler
s *TDFSuite
kases []struct {
- url, private, public, kid string
+ url, private, public, kid, algorithm string
}
}
@@ -2913,6 +3195,40 @@ func (f *FakeKas) getRewrapResponse(rewrapRequest string, fulfillableObligations
entityWrappedKey, err = asymEncrypt.Encrypt(symmetricKey)
f.s.Require().NoError(err, "ocrypto.AsymEncryption.encrypt failed")
+ case "hybrid-wrapped":
+ kasPrivateKey := strings.ReplaceAll(f.privateKey, "\n\t", "\n")
+ if kao.GetKid() != "" && kao.GetKid() != f.KID {
+ lk, ok := f.legakeys[kaoReq.GetKeyAccessObject().GetKid()]
+ f.s.Require().True(ok, "unable to find key [%s]", kao.GetKid())
+ kasPrivateKey = strings.ReplaceAll(lk.private, "\n\t", "\n")
+ }
+
+ var symmetricKey []byte
+ switch ocrypto.KeyType(f.Algorithm) { //nolint:exhaustive // only handle hybrid types
+ case ocrypto.HybridSecp256r1MLKEM768Key:
+ privateKey, err := ocrypto.P256MLKEM768PrivateKeyFromPem([]byte(kasPrivateKey))
+ f.s.Require().NoError(err, "failed to extract P256+ML-KEM-768 private key from PEM")
+ symmetricKey, err = ocrypto.P256MLKEM768UnwrapDEK(privateKey, wrappedKey)
+ f.s.Require().NoError(err, "failed to unwrap P256+ML-KEM-768 wrapped key")
+ case ocrypto.HybridSecp384r1MLKEM1024Key:
+ privateKey, err := ocrypto.P384MLKEM1024PrivateKeyFromPem([]byte(kasPrivateKey))
+ f.s.Require().NoError(err, "failed to extract P384+ML-KEM-1024 private key from PEM")
+ symmetricKey, err = ocrypto.P384MLKEM1024UnwrapDEK(privateKey, wrappedKey)
+ f.s.Require().NoError(err, "failed to unwrap P384+ML-KEM-1024 wrapped key")
+ case ocrypto.HybridXWingKey:
+ privateKey, err := ocrypto.XWingPrivateKeyFromPem([]byte(kasPrivateKey))
+ f.s.Require().NoError(err, "failed to extract X-Wing private key from PEM")
+ symmetricKey, err = ocrypto.XWingUnwrapDEK(privateKey, wrappedKey)
+ f.s.Require().NoError(err, "failed to unwrap X-Wing wrapped key")
+ default:
+ f.s.Require().Failf("unsupported hybrid algorithm", "algorithm: %s", f.Algorithm)
+ }
+
+ asymEncrypt, err := ocrypto.FromPublicPEM(bodyData.GetClientPublicKey())
+ f.s.Require().NoError(err, "ocrypto.FromPublicPEM failed")
+ entityWrappedKey, err = asymEncrypt.Encrypt(symmetricKey)
+ f.s.Require().NoError(err, "ocrypto.encrypt failed")
+
case "wrapped":
kasPrivateKey := strings.ReplaceAll(f.privateKey, "\n\t", "\n")
if kao.GetKid() != "" && kao.GetKid() != f.KID {
diff --git a/service/cmd/keygen/main.go b/service/cmd/keygen/main.go
new file mode 100644
index 0000000000..721191e286
--- /dev/null
+++ b/service/cmd/keygen/main.go
@@ -0,0 +1,116 @@
+// Package main generates hybrid post-quantum KAS key pairs (X-Wing, P256+ML-KEM-768, P384+ML-KEM-1024)
+// as PEM files for use with the OpenTDF platform.
+package main
+
+import (
+ "flag"
+ "log"
+ "os"
+ "path/filepath"
+
+ "github.com/opentdf/platform/lib/ocrypto"
+)
+
+type keySpec struct {
+ name string
+ newKeyPair func() (privatePEM, publicPEM string, err error)
+ privateOut string
+ publicOut string
+}
+
+func main() {
+ outputDir := flag.String("output", ".", "directory to write PEM files")
+ flag.Parse()
+
+ if err := os.MkdirAll(*outputDir, 0o755); err != nil {
+ log.Fatalf("failed to create output directory: %v", err)
+ }
+
+ specs := []keySpec{
+ {
+ name: "X-Wing",
+ newKeyPair: generateXWing,
+ privateOut: "kas-xwing-private.pem",
+ publicOut: "kas-xwing-public.pem",
+ },
+ {
+ name: "P256+ML-KEM-768",
+ newKeyPair: generateP256MLKEM768,
+ privateOut: "kas-p256mlkem768-private.pem",
+ publicOut: "kas-p256mlkem768-public.pem",
+ },
+ {
+ name: "P384+ML-KEM-1024",
+ newKeyPair: generateP384MLKEM1024,
+ privateOut: "kas-p384mlkem1024-private.pem",
+ publicOut: "kas-p384mlkem1024-public.pem",
+ },
+ }
+
+ for _, s := range specs {
+ privatePEM, publicPEM, err := s.newKeyPair()
+ if err != nil {
+ log.Fatalf("failed to generate %s key pair: %v", s.name, err)
+ }
+
+ privPath := filepath.Join(*outputDir, s.privateOut)
+ pubPath := filepath.Join(*outputDir, s.publicOut)
+
+ if err := os.WriteFile(privPath, []byte(privatePEM), 0o600); err != nil {
+ log.Fatalf("failed to write %s: %v", privPath, err)
+ }
+ if err := os.WriteFile(pubPath, []byte(publicPEM), 0o600); err != nil {
+ log.Fatalf("failed to write %s: %v", pubPath, err)
+ }
+
+ log.Printf("Generated %s key pair:\n - Private: %s\n - Public: %s", s.name, privPath, pubPath)
+ }
+}
+
+func generateXWing() (string, string, error) {
+ kp, err := ocrypto.NewXWingKeyPair()
+ 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 generateP256MLKEM768() (string, string, error) {
+ kp, err := ocrypto.NewP256MLKEM768KeyPair()
+ 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 generateP384MLKEM1024() (string, string, error) {
+ kp, err := ocrypto.NewP384MLKEM1024KeyPair()
+ 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 6197e50eb3..139ae7ce31 100644
--- a/service/internal/security/basic_manager.go
+++ b/service/internal/security/basic_manager.go
@@ -97,6 +97,57 @@ func (b *BasicManager) Decrypt(ctx context.Context, keyDetails trust.KeyDetails,
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:
+ 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)
+ }
+ 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)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create protected key: %w", err)
+ }
+ return protectedKey, nil
}
return nil, fmt.Errorf("unsupported algorithm: %s", keyDetails.Algorithm())
diff --git a/service/internal/security/crypto_provider.go b/service/internal/security/crypto_provider.go
index 24f0f3c2ea..dcbe1ae5a1 100644
--- a/service/internal/security/crypto_provider.go
+++ b/service/internal/security/crypto_provider.go
@@ -11,4 +11,11 @@ const (
// Used for encryption with RSA of the KAO
AlgorithmRSA2048 = "rsa:2048"
AlgorithmRSA4096 = "rsa:4096"
+
+ // Used for hybrid X-Wing wrapping of the KAO
+ AlgorithmHPQTXWing = "hpqt:xwing"
+
+ // Used for hybrid NIST EC + ML-KEM wrapping of the KAO
+ AlgorithmHPQTSecp256r1MLKEM768 = "hpqt:secp256r1-mlkem768"
+ AlgorithmHPQTSecp384r1MLKEM1024 = "hpqt:secp384r1-mlkem1024"
)
diff --git a/service/internal/security/in_process_provider.go b/service/internal/security/in_process_provider.go
index 67c86487aa..0b9249f4aa 100644
--- a/service/internal/security/in_process_provider.go
+++ b/service/internal/security/in_process_provider.go
@@ -65,7 +65,7 @@ func (k *KeyDetailsAdapter) ExportPublicKey(_ context.Context, format trust.KeyT
switch format {
case trust.KeyTypeJWK:
// For JWK format (currently only supported for RSA)
- if k.algorithm == AlgorithmRSA2048 {
+ if k.algorithm == AlgorithmRSA2048 || k.algorithm == AlgorithmRSA4096 {
return k.cryptoProvider.RSAPublicKeyAsJSON(kid)
}
// For EC keys, we return the public key in PEM format
@@ -84,6 +84,12 @@ 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
+ }
return k.cryptoProvider.ECPublicKey(kid)
default:
return "", ErrCertNotFound
@@ -170,31 +176,17 @@ func (a *InProcessProvider) FindKeyByAlgorithm(_ context.Context, algorithm stri
// FindKeyByID finds a key by ID
func (a *InProcessProvider) FindKeyByID(_ context.Context, id trust.KeyIdentifier) (trust.KeyDetails, error) {
- // Try to determine the algorithm by checking if the key works with known algorithms
- for _, alg := range []string{AlgorithmECP256R1, AlgorithmRSA2048} {
- // This is a hack since the original provider doesn't have a way to check if a key exists
- switch alg {
- case AlgorithmECP256R1:
- if _, err := a.cryptoProvider.ECPublicKey(string(id)); err == nil {
- return &KeyDetailsAdapter{
- id: id,
- algorithm: ocrypto.KeyType(alg),
- legacy: a.legacyKeys[string(id)],
- cryptoProvider: a.cryptoProvider,
- }, nil
- }
- case AlgorithmRSA2048:
- if _, err := a.cryptoProvider.RSAPublicKey(string(id)); err == nil {
- return &KeyDetailsAdapter{
- id: id,
- algorithm: ocrypto.KeyType(alg),
- legacy: a.legacyKeys[string(id)],
- cryptoProvider: a.cryptoProvider,
- }, nil
- }
- }
+ keyType, err := a.determineKeyType(string(id))
+ if err != nil {
+ return nil, ErrCertNotFound
}
- return nil, ErrCertNotFound
+
+ return &KeyDetailsAdapter{
+ id: id,
+ algorithm: ocrypto.KeyType(keyType),
+ legacy: a.legacyKeys[string(id)],
+ cryptoProvider: a.cryptoProvider,
+ }, nil
}
// ListKeys lists all available keys
@@ -207,7 +199,7 @@ func (a *InProcessProvider) ListKeysWith(ctx context.Context, opts trust.ListKey
var keys []trust.KeyDetails
// Try to find keys for known algorithms
- for _, alg := range []string{AlgorithmRSA2048, AlgorithmECP256R1} {
+ for _, alg := range []string{AlgorithmRSA2048, AlgorithmRSA4096, AlgorithmECP256R1, AlgorithmHPQTXWing, AlgorithmHPQTSecp256r1MLKEM768, AlgorithmHPQTSecp384r1MLKEM1024} {
if kids, err := a.cryptoProvider.ListKIDsByAlgorithm(alg); err == nil && len(kids) > 0 {
for _, kid := range kids {
if opts.LegacyOnly && !a.legacyKeys[kid] {
@@ -242,7 +234,7 @@ func (a *InProcessProvider) Decrypt(ctx context.Context, keyDetails trust.KeyDet
var err error
// Try to determine the key type
- keyType, err := a.determineKeyType(ctx, kid)
+ keyType, err := a.determineKeyType(kid)
if err != nil {
return nil, err
}
@@ -250,6 +242,8 @@ func (a *InProcessProvider) Decrypt(ctx context.Context, keyDetails trust.KeyDet
var rawKey []byte
switch keyType {
case AlgorithmRSA2048:
+ fallthrough
+ case AlgorithmRSA4096:
if len(ephemeralPublicKey) > 0 {
return nil, errors.New("ephemeral public key should not be provided for RSA decryption")
}
@@ -261,6 +255,12 @@ func (a *InProcessProvider) Decrypt(ctx context.Context, keyDetails trust.KeyDet
}
protectedKey, err = a.cryptoProvider.ECDecrypt(ctx, kid, ephemeralPublicKey, ciphertext)
+ case AlgorithmHPQTXWing, AlgorithmHPQTSecp256r1MLKEM768, AlgorithmHPQTSecp384r1MLKEM1024:
+ if len(ephemeralPublicKey) > 0 {
+ return nil, errors.New("ephemeral public key should not be provided for hybrid decryption")
+ }
+ return a.cryptoProvider.Decrypt(ctx, trust.KeyIdentifier(kid), ciphertext, nil)
+
default:
return nil, errors.New("unsupported key algorithm")
}
@@ -335,17 +335,22 @@ func (a *InProcessProvider) Close() {
a.cryptoProvider.Close()
}
-// determineKeyType tries to determine the algorithm of a key based on its ID
-// This is a helper method for the Decrypt method
-func (a *InProcessProvider) determineKeyType(_ context.Context, kid string) (string, error) {
- // First try RSA
- if _, err := a.cryptoProvider.RSAPublicKey(kid); err == nil {
- return AlgorithmRSA2048, nil
+// determineKeyType returns the configured algorithm for a loaded key.
+func (a *InProcessProvider) determineKeyType(kid string) (string, error) {
+ key, ok := a.cryptoProvider.keysByID[kid]
+ if !ok {
+ return "", errors.New("could not determine key type")
}
- // Then try EC
- if _, err := a.cryptoProvider.ECPublicKey(kid); err == nil {
- return AlgorithmECP256R1, nil
+ switch key := key.(type) {
+ case StandardRSACrypto:
+ return key.Algorithm, nil
+ case StandardECCrypto:
+ return key.Algorithm, nil
+ case StandardXWingCrypto:
+ return key.Algorithm, nil
+ case StandardHybridCrypto:
+ return key.Algorithm, nil
}
return "", errors.New("could not determine key type")
diff --git a/service/internal/security/standard_crypto.go b/service/internal/security/standard_crypto.go
index 6b86abdcbe..59953a8523 100644
--- a/service/internal/security/standard_crypto.go
+++ b/service/internal/security/standard_crypto.go
@@ -67,6 +67,18 @@ type StandardECCrypto struct {
sk *ecdh.PrivateKey
}
+type StandardXWingCrypto struct {
+ KeyPairInfo
+ xwingPrivateKeyPem string
+ xwingPublicKeyPem string
+}
+
+type StandardHybridCrypto struct {
+ KeyPairInfo
+ hybridPrivateKeyPem string
+ hybridPublicKeyPem string
+}
+
// List of keys by identifier
type keylist map[string]any
@@ -150,6 +162,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),
+ }, nil
case AlgorithmRSA2048, AlgorithmRSA4096:
asymDecryption, err := ocrypto.NewAsymDecryption(string(privatePEM))
if err != nil {
@@ -329,6 +353,42 @@ func (s StandardCrypto) ECPublicKey(kid string) (string, error) {
return string(pemBytes), nil
}
+func (s StandardCrypto) XWingPublicKey(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)
+ }
+ if xw.xwingPublicKeyPem == "" {
+ return "", fmt.Errorf("no X-Wing public key with id [%s]: %w", kid, ErrCertNotFound)
+ }
+ return xw.xwingPublicKeyPem, nil
+}
+
+func (s StandardCrypto) HybridPublicKey(kid string) (string, error) {
+ k, ok := s.keysByID[kid]
+ if !ok {
+ return "", fmt.Errorf("no hybrid key with id [%s]: %w", kid, ErrCertNotFound)
+ }
+ switch h := k.(type) {
+ case StandardXWingCrypto:
+ if h.xwingPublicKeyPem == "" {
+ return "", fmt.Errorf("no hybrid public key with id [%s]: %w", kid, ErrCertNotFound)
+ }
+ return h.xwingPublicKeyPem, nil
+ case StandardHybridCrypto:
+ if h.hybridPublicKeyPem == "" {
+ return "", fmt.Errorf("no hybrid public key with id [%s]: %w", kid, ErrCertNotFound)
+ }
+ return h.hybridPublicKeyPem, nil
+ default:
+ return "", fmt.Errorf("key with id [%s] is not a hybrid key: %w", kid, ErrCertNotFound)
+ }
+}
+
func (s StandardCrypto) RSADecrypt(_ crypto.Hash, kid string, _ string, ciphertext []byte) ([]byte, error) {
k, ok := s.keysByID[kid]
if !ok {
@@ -439,6 +499,49 @@ func (s *StandardCrypto) Decrypt(_ context.Context, keyID trust.KeyIdentifier, c
return nil, fmt.Errorf("error decrypting data: %w", err)
}
+ case StandardXWingCrypto:
+ if len(ephemeralPublicKey) > 0 {
+ return nil, errors.New("ephemeral public key should not be provided for X-Wing decryption")
+ }
+
+ privateKey, err := ocrypto.XWingPrivateKeyFromPem([]byte(key.xwingPrivateKeyPem))
+ 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)
+ }
+
default:
return nil, fmt.Errorf("unsupported key type for key ID [%s]", kid)
}
diff --git a/service/kas/access/provider.go b/service/kas/access/provider.go
index e9c01dbe0c..89f90b5e85 100644
--- a/service/kas/access/provider.go
+++ b/service/kas/access/provider.go
@@ -52,13 +52,15 @@ type KASConfig struct {
// Enabling is required to parse KAOs with the `ec-wrapped` type,
// and (currently) also enables responding with ECIES encrypted responses.
ECTDFEnabled bool `mapstructure:"ec_tdf_enabled" json:"ec_tdf_enabled"`
+ HybridTDFEnabled bool `mapstructure:"hybrid_tdf_enabled" json:"hybrid_tdf_enabled"`
Preview Preview `mapstructure:"preview" json:"preview"`
RegisteredKASURI string `mapstructure:"registered_kas_uri" json:"registered_kas_uri"`
}
type Preview struct {
- ECTDFEnabled bool `mapstructure:"ec_tdf_enabled" json:"ec_tdf_enabled"`
- KeyManagement bool `mapstructure:"key_management" json:"key_management"`
+ ECTDFEnabled bool `mapstructure:"ec_tdf_enabled" json:"ec_tdf_enabled"`
+ HybridTDFEnabled bool `mapstructure:"hybrid_tdf_enabled" json:"hybrid_tdf_enabled"`
+ KeyManagement bool `mapstructure:"key_management" json:"key_management"`
}
// Specifies the preferred/default key for a given algorithm type.
@@ -143,13 +145,14 @@ func (kasCfg KASConfig) String() string {
}
return fmt.Sprintf(
- "KASConfig{Keyring:%v, ECCertID:%q, RSACertID:%q, RootKey:%s, KeyCacheExpiration:%s, ECTDFEnabled:%t, Preview:%+v, RegisteredKASURI:%q}",
+ "KASConfig{Keyring:%v, ECCertID:%q, RSACertID:%q, RootKey:%s, KeyCacheExpiration:%s, ECTDFEnabled:%t, HybridTDFEnabled:%t, Preview:%+v, RegisteredKASURI:%q}",
kasCfg.Keyring,
kasCfg.ECCertID,
kasCfg.RSACertID,
rootKeySummary,
kasCfg.KeyCacheExpiration,
kasCfg.ECTDFEnabled,
+ kasCfg.HybridTDFEnabled,
kasCfg.Preview,
kasCfg.RegisteredKASURI,
)
@@ -168,6 +171,7 @@ func (kasCfg KASConfig) LogValue() slog.Value {
slog.String("root_key", rootKeyVal),
slog.Duration("key_cache_expiration", kasCfg.KeyCacheExpiration),
slog.Bool("ec_tdf_enabled", kasCfg.ECTDFEnabled),
+ slog.Bool("hybrid_tdf_enabled", kasCfg.HybridTDFEnabled),
slog.Any("preview", kasCfg.Preview),
slog.String("registered_kas_uri", kasCfg.RegisteredKASURI),
)
diff --git a/service/kas/access/publicKey.go b/service/kas/access/publicKey.go
index eb5b1fe780..d7f381c307 100644
--- a/service/kas/access/publicKey.go
+++ b/service/kas/access/publicKey.go
@@ -76,9 +76,8 @@ func (p *Provider) LegacyPublicKey(ctx context.Context, req *connect.Request[kas
p.Logger.ErrorContext(ctx, "keyDetails.ExportCertificate failed", slog.Any("error", err))
return nil, connect.NewError(connect.CodeInternal, errors.Join(ErrConfig, errors.New("configuration error")))
}
- case security.AlgorithmRSA2048:
- fallthrough
- case "":
+ case security.AlgorithmRSA2048, security.AlgorithmHPQTXWing,
+ security.AlgorithmHPQTSecp256r1MLKEM768, security.AlgorithmHPQTSecp384r1MLKEM1024, "":
// For RSA keys, return the public key in PKCS8 format
pem, err = keyDetails.ExportPublicKey(ctx, trust.KeyTypePKCS8)
if err != nil {
@@ -153,6 +152,14 @@ func (p *Provider) PublicKey(ctx context.Context, req *connect.Request[kaspb.Pub
// For EC keys, export the public key
ecPublicKeyPem, err := keyDetails.ExportPublicKey(ctx, trust.KeyTypePKCS8)
return r(ecPublicKeyPem, kid, err)
+ case security.AlgorithmHPQTXWing,
+ security.AlgorithmHPQTSecp256r1MLKEM768,
+ security.AlgorithmHPQTSecp384r1MLKEM1024:
+ switch fmt {
+ case "pkcs8", "":
+ publicKeyPEM, err := keyDetails.ExportPublicKey(ctx, trust.KeyTypePKCS8)
+ return r(publicKeyPEM, kid, err)
+ }
case security.AlgorithmRSA2048:
fallthrough
case "":
diff --git a/service/kas/access/rewrap.go b/service/kas/access/rewrap.go
index 274e09e256..71db5e4922 100644
--- a/service/kas/access/rewrap.go
+++ b/service/kas/access/rewrap.go
@@ -734,6 +734,20 @@ func (p *Provider) verifyRewrapRequests(ctx context.Context, req *kaspb.Unsigned
failedKAORewrap(results, kao, err400("bad request"))
continue
}
+ case "hybrid-wrapped":
+ if !p.HybridTDFEnabled && !p.Preview.HybridTDFEnabled {
+ p.Logger.WarnContext(ctx, "hybrid-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 hybrid key", slog.Any("error", err))
+ failedKAORewrap(results, kao, err400("bad request"))
+ continue
+ }
case "wrapped":
var kidsToCheck []trust.KeyIdentifier
if kao.GetKeyAccessObject().GetKid() != "" {
diff --git a/service/kas/kas.go b/service/kas/kas.go
index caaff1d6df..26c86c4efb 100644
--- a/service/kas/kas.go
+++ b/service/kas/kas.go
@@ -192,7 +192,7 @@ func initSecurityProviderAdapter(cryptoProvider *security.StandardCrypto, kasCfg
}
}
if len(defaults) == 0 && len(legacies) == 0 {
- for _, alg := range []string{security.AlgorithmECP256R1, security.AlgorithmRSA2048} {
+ for _, alg := range []string{security.AlgorithmECP256R1, security.AlgorithmRSA2048, security.AlgorithmHPQTXWing} {
kid := cryptoProvider.FindKID(alg)
if kid != "" {
defaults = append(defaults, kid)
diff --git a/service/kas/kas.proto b/service/kas/kas.proto
index 7563a25e49..aad584ed18 100644
--- a/service/kas/kas.proto
+++ b/service/kas/kas.proto
@@ -68,7 +68,7 @@ message KeyAccess {
// Type of key wrapping used for the data encryption key
// Required: Always
- // Values: 'wrapped' (RSA-wrapped for ZTDF), 'ec-wrapped' (experimental ECDH-wrapped)
+ // Values: 'wrapped' (RSA-wrapped for ZTDF), 'ec-wrapped' (experimental ECDH-wrapped), 'hybrid-wrapped' (experimental X-Wing-wrapped)
string key_type = 4 [json_name = "type"];
// URL of the Key Access Server that can unwrap this key
@@ -101,7 +101,7 @@ message KeyAccess {
// Ephemeral public key for ECDH key derivation (ec-wrapped type only)
// Required: When key_type="ec-wrapped" (experimental ECDH-based ZTDF)
- // Omitted: When key_type="wrapped" (RSA-based ZTDF)
+ // Omitted: When key_type="wrapped" or key_type="hybrid-wrapped"
// Should be a PEM-encoded PKCS#8 (ASN.1) formatted public key
// Used to derive the symmetric key for unwrapping the DEK
string ephemeral_public_key = 10;
@@ -258,7 +258,7 @@ message RewrapResponse {
// KAS's ephemeral session public key in PEM format
// Required: For EC-based operations (key_type="ec-wrapped")
- // Optional: Empty for RSA-based ZTDF (key_type="wrapped")
+ // Optional: Empty for RSA-based or X-Wing-based ZTDF (key_type="wrapped" or key_type="hybrid-wrapped")
// Used by client to perform ECDH key agreement and decrypt the kas_wrapped_key values
string session_public_key = 3;
diff --git a/service/kas/key_indexer.go b/service/kas/key_indexer.go
index 021b3f418a..3cacbed882 100644
--- a/service/kas/key_indexer.go
+++ b/service/kas/key_indexer.go
@@ -58,6 +58,12 @@ func convertEnumToAlg(alg policy.Algorithm) ocrypto.KeyType {
return ocrypto.EC384Key
case policy.Algorithm_ALGORITHM_EC_P521:
return ocrypto.EC521Key
+ case policy.Algorithm_ALGORITHM_HPQT_XWING:
+ return ocrypto.HybridXWingKey
+ case policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768:
+ return ocrypto.HybridSecp256r1MLKEM768Key
+ case policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024:
+ return ocrypto.HybridSecp384r1MLKEM1024Key
case policy.Algorithm_ALGORITHM_UNSPECIFIED:
fallthrough
default:
@@ -77,6 +83,12 @@ func convertAlgToEnum(alg string) (policy.Algorithm, error) {
return policy.Algorithm_ALGORITHM_EC_P384, nil
case string(ocrypto.EC521Key):
return policy.Algorithm_ALGORITHM_EC_P521, nil
+ case string(ocrypto.HybridXWingKey):
+ return policy.Algorithm_ALGORITHM_HPQT_XWING, nil
+ case string(ocrypto.HybridSecp256r1MLKEM768Key):
+ return policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768, nil
+ case string(ocrypto.HybridSecp384r1MLKEM1024Key):
+ return policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024, nil
default:
return policy.Algorithm_ALGORITHM_UNSPECIFIED, fmt.Errorf("unsupported algorithm: %s", alg)
}
diff --git a/service/kas/key_indexer_test.go b/service/kas/key_indexer_test.go
index eba2f8278d..5557ba857d 100644
--- a/service/kas/key_indexer_test.go
+++ b/service/kas/key_indexer_test.go
@@ -168,6 +168,14 @@ func (s *KeyIndexTestSuite) TestKeyDetails_Legacy() {
s.True(legacyKey.IsLegacy())
}
+func (s *KeyIndexTestSuite) TestAlgorithmConversions_HybridXWing() {
+ s.Equal(ocrypto.HybridXWingKey, convertEnumToAlg(policy.Algorithm_ALGORITHM_HPQT_XWING))
+
+ alg, err := convertAlgToEnum(string(ocrypto.HybridXWingKey))
+ s.Require().NoError(err)
+ s.Equal(policy.Algorithm_ALGORITHM_HPQT_XWING, alg)
+}
+
func (s *KeyIndexTestSuite) TestListKeysWith() {
mockClient := new(MockKeyAccessServerRegistryClient)
keyIndexer := &KeyIndexer{
diff --git a/service/pkg/db/marshalHelpers.go b/service/pkg/db/marshalHelpers.go
index 667ab27e21..c78b91ab5f 100644
--- a/service/pkg/db/marshalHelpers.go
+++ b/service/pkg/db/marshalHelpers.go
@@ -157,6 +157,12 @@ func FormatAlg(alg policy.Algorithm) (string, error) {
return "ec:secp384r1", nil
case policy.Algorithm_ALGORITHM_EC_P521:
return "ec:secp521r1", nil
+ case policy.Algorithm_ALGORITHM_HPQT_XWING:
+ return "hpqt:xwing", nil
+ case policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768:
+ return "hpqt:secp256r1-mlkem768", nil
+ case policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024:
+ return "hpqt:secp384r1-mlkem1024", nil
case policy.Algorithm_ALGORITHM_UNSPECIFIED:
fallthrough
default:
diff --git a/service/pkg/db/marshalHelpers_test.go b/service/pkg/db/marshalHelpers_test.go
index a516a3b129..16a4234e8d 100644
--- a/service/pkg/db/marshalHelpers_test.go
+++ b/service/pkg/db/marshalHelpers_test.go
@@ -12,11 +12,14 @@ import (
// reverseAlgMap mirrors the SDK's getKasKeyAlg mapping: ocrypto.KeyType string → policy.Algorithm.
// If FormatAlg produces a string that isn't in this map, the SDK would return ALGORITHM_UNSPECIFIED.
var reverseAlgMap = map[string]policy.Algorithm{
- string(ocrypto.RSA2048Key): policy.Algorithm_ALGORITHM_RSA_2048,
- string(ocrypto.RSA4096Key): policy.Algorithm_ALGORITHM_RSA_4096,
- string(ocrypto.EC256Key): policy.Algorithm_ALGORITHM_EC_P256,
- string(ocrypto.EC384Key): policy.Algorithm_ALGORITHM_EC_P384,
- string(ocrypto.EC521Key): policy.Algorithm_ALGORITHM_EC_P521,
+ string(ocrypto.RSA2048Key): policy.Algorithm_ALGORITHM_RSA_2048,
+ string(ocrypto.RSA4096Key): policy.Algorithm_ALGORITHM_RSA_4096,
+ string(ocrypto.EC256Key): policy.Algorithm_ALGORITHM_EC_P256,
+ string(ocrypto.EC384Key): policy.Algorithm_ALGORITHM_EC_P384,
+ string(ocrypto.EC521Key): policy.Algorithm_ALGORITHM_EC_P521,
+ string(ocrypto.HybridXWingKey): policy.Algorithm_ALGORITHM_HPQT_XWING,
+ string(ocrypto.HybridSecp256r1MLKEM768Key): policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768,
+ string(ocrypto.HybridSecp384r1MLKEM1024Key): policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024,
}
func TestFormatAlg_RoundTrip(t *testing.T) {
@@ -32,6 +35,9 @@ func TestFormatAlg_RoundTrip(t *testing.T) {
{"EC-P256", policy.Algorithm_ALGORITHM_EC_P256},
{"EC-P384", policy.Algorithm_ALGORITHM_EC_P384},
{"EC-P521", policy.Algorithm_ALGORITHM_EC_P521},
+ {"HPQT-XWing", policy.Algorithm_ALGORITHM_HPQT_XWING},
+ {"HPQT-P256-MLKEM768", policy.Algorithm_ALGORITHM_HPQT_SECP256R1_MLKEM768},
+ {"HPQT-P384-MLKEM1024", policy.Algorithm_ALGORITHM_HPQT_SECP384R1_MLKEM1024},
}
for _, tc := range supportedAlgs {
diff --git a/service/pkg/server/testdata/all-no-config.yaml b/service/pkg/server/testdata/all-no-config.yaml
index d6db2ae334..29dcd5fe8c 100644
--- a/service/pkg/server/testdata/all-no-config.yaml
+++ b/service/pkg/server/testdata/all-no-config.yaml
@@ -16,6 +16,12 @@ services:
- kid: r1
alg: rsa:2048
legacy: true
+ - kid: x1
+ alg: hpqt:xwing
+ - kid: h1
+ alg: hpqt:secp256r1-mlkem768
+ - kid: h2
+ alg: hpqt:secp384r1-mlkem1024
entityresolution:
log_level: info
url: http://localhost:8888/auth
@@ -117,3 +123,15 @@ server:
alg: ec:secp256r1
private: ./testdata/kas-ec-private.pem
cert: ./testdata/kas-ec-cert.pem
+ - kid: x1
+ alg: hpqt:xwing
+ private: ./testdata/kas-xwing-private.pem
+ cert: ./testdata/kas-xwing-public.pem
+ - kid: h1
+ alg: hpqt:secp256r1-mlkem768
+ private: ./testdata/kas-p256mlkem768-private.pem
+ cert: ./testdata/kas-p256mlkem768-public.pem
+ - kid: h2
+ alg: hpqt:secp384r1-mlkem1024
+ private: ./testdata/kas-p384mlkem1024-private.pem
+ cert: ./testdata/kas-p384mlkem1024-public.pem
diff --git a/service/policy/db/grant_mappings.go b/service/policy/db/grant_mappings.go
index 7c3688af58..7de6a12626 100644
--- a/service/policy/db/grant_mappings.go
+++ b/service/policy/db/grant_mappings.go
@@ -22,6 +22,8 @@ func mapAlgorithmToKasPublicKeyAlg(alg policy.Algorithm) policy.KasPublicKeyAlgE
return policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1
case policy.Algorithm_ALGORITHM_EC_P521: // ALGORITHM_EC_P521 is an alias
return policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1
+ case policy.Algorithm_ALGORITHM_HPQT_XWING:
+ return policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HPQT_XWING
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 f7c4bdf7f8..bee4e695bd 100644
--- a/service/policy/kasregistry/key_access_server_registry.proto
+++ b/service/policy/kasregistry/key_access_server_registry.proto
@@ -403,7 +403,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]" // Allow ALGORITHM_RSA_2048, ALGORITHM_RSA_4096, ALGORITHM_EC_P256, ALGORITHM_EC_P384, ALGORITHM_EC_P521
+ 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
}]; // The algorithm to be used for the key
// Required
KeyMode key_mode = 4 [(buf.validate.field).cel = {
@@ -447,7 +447,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]" // Allow unspecified and object.Algorithm values for currently supported RSA bit sizes and EC curve types
+ expression: "this in [0, 1, 2, 3, 4, 5, 6, 7, 8]" // Allow unspecified and all supported algorithm values
}]; // Filter keys by algorithm
oneof kas_filter {
@@ -550,7 +550,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]" // Allow ALGORITHM_RSA_2048, ALGORITHM_RSA_4096, ALGORITHM_EC_P256, ALGORITHM_EC_P384, ALGORITHM_EC_P521
+ 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
}];
// Required
KeyMode key_mode = 3 [
diff --git a/service/policy/objects.proto b/service/policy/objects.proto
index a54bc2517a..8f6b5da374 100644
--- a/service/policy/objects.proto
+++ b/service/policy/objects.proto
@@ -388,6 +388,9 @@ enum KasPublicKeyAlgEnum {
KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1 = 5;
KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP384R1 = 6;
KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP521R1 = 7;
+ 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;
}
// Deprecated
@@ -553,6 +556,9 @@ enum Algorithm {
ALGORITHM_EC_P256 = 3;
ALGORITHM_EC_P384 = 4;
ALGORITHM_EC_P521 = 5;
+ ALGORITHM_HPQT_XWING = 6;
+ ALGORITHM_HPQT_SECP256R1_MLKEM768 = 7;
+ ALGORITHM_HPQT_SECP384R1_MLKEM1024 = 8;
}
// The status of the key
diff --git a/test/start-up-with-containers/action.yaml b/test/start-up-with-containers/action.yaml
index 1babf8e737..1fd87abb89 100644
--- a/test/start-up-with-containers/action.yaml
+++ b/test/start-up-with-containers/action.yaml
@@ -111,8 +111,8 @@ runs:
set -e
allowed_algorithms=(ec:secp256r1 rsa:2048)
if echo $PLATFORM_VERSION | awk -F. '{ if ($1 > 0 || ($1 == 0 && $2 > 7) || ($1 == 0 && $2 == 7 && $3 >= 1)) exit 0; else exit 1; }'; then
- # For versions 0.7.1 and later, we allow rsa:4096 ec:secp384r1 ec:secp521r1
- allowed_algorithms+=(rsa:4096 ec:secp384r1 ec:secp521r1)
+ # For versions 0.7.1 and later, we allow rsa:4096 ec:secp384r1 ec:secp521r1
+ allowed_algorithms+=(rsa:4096 ec:secp384r1 ec:secp521r1 hpqt:xwing hpqt:secp256r1-mlkem768 hpqt:secp384r1-mlkem1024)
fi
keyring='[{"kid":"ec1","alg":"ec:secp256r1"},{"kid":"r1","alg":"rsa:2048"}]'
keys='[{"kid":"e1","alg":"ec:secp256r1","private":"kas-ec-private.pem","cert":"kas-ec-cert.pem"},{"kid":"ec1","alg":"ec:secp256r1","private":"kas-ec-private.pem","cert":"kas-ec-cert.pem"},{"kid":"r1","alg":"rsa:2048","private":"kas-private.pem","cert":"kas-cert.pem"}]'
diff --git a/tests-bdd/cukes/utils/utils_genKeys.go b/tests-bdd/cukes/utils/utils_genKeys.go
index 9038e185ed..3ad0b57599 100644
--- a/tests-bdd/cukes/utils/utils_genKeys.go
+++ b/tests-bdd/cukes/utils/utils_genKeys.go
@@ -15,6 +15,8 @@ import (
"os/exec"
"path"
"time"
+
+ "github.com/opentdf/platform/lib/ocrypto"
)
const (
@@ -33,6 +35,7 @@ func GenerateTempKeys(ctx context.Context, outputPath string) {
generateRSACertificate(outputPath)
generateECParameters(outputPath)
generateECCertificate(outputPath)
+ generateHybridKeys(outputPath)
generateJavaKeystore(ctx, outputPath)
}
@@ -203,3 +206,86 @@ 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.
+func generateHybridKeys(outputPath string) {
+ specs := []struct {
+ name string
+ newKeyPair func() (priv, pub string, err error)
+ privateOut string
+ publicOut 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"},
+ }
+
+ for _, s := range specs {
+ priv, pub, err := s.newKeyPair()
+ if err != nil {
+ log.Fatalf("Failed to generate %s key pair: %v", s.name, err)
+ }
+
+ privPath := path.Join(outputPath, s.privateOut)
+ pubPath := path.Join(outputPath, s.publicOut)
+
+ if err := os.WriteFile(privPath, []byte(priv), 0o600); err != nil {
+ log.Fatalf("Failed to write %s: %v", privPath, err)
+ }
+ if err := os.WriteFile(pubPath, []byte(pub), 0o600); err != nil {
+ log.Fatalf("Failed to write %s: %v", pubPath, err)
+ }
+
+ log.Printf("%s key pair generated successfully:", s.name)
+ log.Printf(" - Private: %s", privPath)
+ log.Printf(" - Public: %s", pubPath)
+ }
+}
+
+func generateXWingKeyPair() (string, string, error) {
+ kp, err := ocrypto.NewXWingKeyPair()
+ 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 generateP256MLKEM768KeyPair() (string, string, error) {
+ kp, err := ocrypto.NewP256MLKEM768KeyPair()
+ 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 generateP384MLKEM1024KeyPair() (string, string, error) {
+ kp, err := ocrypto.NewP384MLKEM1024KeyPair()
+ 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
+}