diff --git a/docs/grpc/index.html b/docs/grpc/index.html index c598fdd7a2..7c9c3285ba 100644 --- a/docs/grpc/index.html +++ b/docs/grpc/index.html @@ -4043,6 +4043,24 @@

Algorithm

+ + ALGORITHM_MLKEM_768 + 20 +

+ + + + ALGORITHM_MLKEM_1024 + 21 +

+ + + + ALGORITHM_HYBRID_XWING + 30 +

+ + @@ -4154,6 +4172,24 @@

KasPublicKeyAlgEnum

+ + KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768 + 20 +

+ + + + KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 + 21 +

+ + + + KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING + 30 +

+ + @@ -6292,7 +6328,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), 'mlkem-wrapped' (ML-KEM-wrapped), 'hybrid' (Hybrid X-Wing-wrapped)

@@ -6347,10 +6383,10 @@

KeyAccess

ephemeral_public_key string -

Ephemeral public key for ECDH key derivation (ec-wrapped type only) -Required: When key_type="ec-wrapped" (experimental ECDH-based ZTDF) +

Ephemeral public key for ECDH/ML-KEM/Hybrid key derivation +Required: When key_type="ec-wrapped", "mlkem-wrapped", or "hybrid" Omitted: When key_type="wrapped" (RSA-based ZTDF) -Should be a PEM-encoded PKCS#8 (ASN.1) formatted public key +Should be a PEM-encoded or Base64-encoded (for ML-KEM/Hybrid) public key material Used to derive the symmetric key for unwrapping the DEK

@@ -6676,8 +6712,8 @@

RewrapResponse

string

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") +Required: For EC-based operations (key_type="ec-wrapped") or Hybrid +Optional: Empty for RSA-based ZTDF (key_type="wrapped") or ML-KEM 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 b17083ebd1..414620572e 100644 --- a/docs/openapi/authorization/authorization.openapi.yaml +++ b/docs/openapi/authorization/authorization.openapi.yaml @@ -343,6 +343,9 @@ components: - ALGORITHM_EC_P256 - ALGORITHM_EC_P384 - ALGORITHM_EC_P521 + - ALGORITHM_MLKEM_768 + - ALGORITHM_MLKEM_1024 + - ALGORITHM_HYBRID_XWING description: Supported key algorithms. policy.KasPublicKeyAlgEnum: type: string @@ -354,6 +357,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_MLKEM_768 + - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 + - KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING 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..dfc69dbf78 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_MLKEM_768 + - ALGORITHM_MLKEM_1024 + - ALGORITHM_HYBRID_XWING 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_MLKEM_768 + - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 + - KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING policy.SourceType: type: string title: SourceType diff --git a/docs/openapi/kas/kas.openapi.yaml b/docs/openapi/kas/kas.openapi.yaml index b9e18aa899..cbb7de1b3b 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), 'mlkem-wrapped' (ML-KEM-wrapped), 'hybrid' (Hybrid X-Wing-wrapped) url: type: string title: kas_url @@ -259,10 +259,10 @@ components: type: string title: ephemeral_public_key description: |- - Ephemeral public key for ECDH key derivation (ec-wrapped type only) - Required: When key_type="ec-wrapped" (experimental ECDH-based ZTDF) + Ephemeral public key for ECDH/ML-KEM/Hybrid key derivation + Required: When key_type="ec-wrapped", "mlkem-wrapped", or "hybrid" Omitted: When key_type="wrapped" (RSA-based ZTDF) - Should be a PEM-encoded PKCS#8 (ASN.1) formatted public key + Should be a PEM-encoded or Base64-encoded (for ML-KEM/Hybrid) public key material Used to derive the symmetric key for unwrapping the DEK title: KeyAccess additionalProperties: false @@ -450,8 +450,8 @@ components: title: session_public_key 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") + Required: For EC-based operations (key_type="ec-wrapped") or Hybrid + Optional: Empty for RSA-based ZTDF (key_type="wrapped") or ML-KEM 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..770efbd744 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_MLKEM_768 + - ALGORITHM_MLKEM_1024 + - ALGORITHM_HYBRID_XWING 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_MLKEM_768 + - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 + - KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING 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 0fcb66f710..67052c49bf 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_MLKEM_768 + - ALGORITHM_MLKEM_1024 + - ALGORITHM_HYBRID_XWING 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_MLKEM_768 + - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 + - KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING policy.SortDirection: type: string title: SortDirection diff --git a/docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml b/docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml index 9cdc346918..12ce447a18 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_MLKEM_768 + - ALGORITHM_MLKEM_1024 + - ALGORITHM_HYBRID_XWING 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_MLKEM_768 + - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 + - KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING 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, 20, 21] ``` $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, 20, 21] ``` $ref: '#/components/schemas/policy.Algorithm' diff --git a/docs/openapi/policy/namespaces/namespaces.openapi.yaml b/docs/openapi/policy/namespaces/namespaces.openapi.yaml index 4a5b7e35cb..071817abae 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_MLKEM_768 + - ALGORITHM_MLKEM_1024 + - ALGORITHM_HYBRID_XWING 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_MLKEM_768 + - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 + - KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING policy.SortDirection: type: string title: SortDirection diff --git a/docs/openapi/policy/objects.openapi.yaml b/docs/openapi/policy/objects.openapi.yaml index 917017b1a0..a48bfafd1d 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_MLKEM_768 + - ALGORITHM_MLKEM_1024 + - ALGORITHM_HYBRID_XWING 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_MLKEM_768 + - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 + - KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING 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..4cff7da1ff 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_MLKEM_768 + - ALGORITHM_MLKEM_1024 + - ALGORITHM_HYBRID_XWING 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_MLKEM_768 + - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 + - KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING 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..80b5691319 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_MLKEM_768 + - ALGORITHM_MLKEM_1024 + - ALGORITHM_HYBRID_XWING 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_MLKEM_768 + - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 + - KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING 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..696ae62059 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_MLKEM_768 + - ALGORITHM_MLKEM_1024 + - ALGORITHM_HYBRID_XWING 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_MLKEM_768 + - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 + - KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING 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 ce818161fb..530dab4c0f 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_MLKEM_768 + - ALGORITHM_MLKEM_1024 + - ALGORITHM_HYBRID_XWING 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_MLKEM_768 + - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 + - KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING policy.SortDirection: type: string title: SortDirection diff --git a/docs/openapi/policy/unsafe/unsafe.openapi.yaml b/docs/openapi/policy/unsafe/unsafe.openapi.yaml index f52e95b427..e400f9b9e1 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_MLKEM_768 + - ALGORITHM_MLKEM_1024 + - ALGORITHM_HYBRID_XWING 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_MLKEM_768 + - KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 + - KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING policy.KeyMode: type: string title: KeyMode diff --git a/lib/ocrypto/asym_decryption.go b/lib/ocrypto/asym_decryption.go index 426f859723..e917bea75c 100644 --- a/lib/ocrypto/asym_decryption.go +++ b/lib/ocrypto/asym_decryption.go @@ -7,6 +7,7 @@ import ( "crypto/ecdh" "crypto/ecdsa" "crypto/elliptic" + "crypto/mlkem" "crypto/rsa" "crypto/sha256" "crypto/x509" @@ -26,6 +27,21 @@ type AsymDecryption struct { type PrivateKeyDecryptor interface { // Decrypt decrypts ciphertext with private key. Decrypt(data []byte) ([]byte, error) + + // DecryptWithEphemeralKey decrypts ciphertext using additional sender material. + DecryptWithEphemeralKey(data, ephemeral []byte) ([]byte, error) +} + +type MLKEMDecryptor768 struct { + decap *mlkem.DecapsulationKey768 +} + +type MLKEMDecryptor1024 struct { + decap *mlkem.DecapsulationKey1024 +} + +type HybridXWingDecryptorWrapper struct { + decap *HybridXWingDecryptor } // FromPrivatePEM creates and returns a new AsymDecryption. @@ -44,6 +60,26 @@ func FromPrivatePEMWithSalt(privateKeyInPem string, salt, info []byte) (PrivateK return AsymDecryption{}, errors.New("failed to parse PEM formatted private key") } + if block.Type == "MLKEM DECAPSULATION KEY" { + decap768, err := mlkem.NewDecapsulationKey768(block.Bytes) + if err == nil { + return &MLKEMDecryptor768{decap: decap768}, nil + } + decap1024, err1024 := mlkem.NewDecapsulationKey1024(block.Bytes) + if err1024 != nil { + return nil, fmt.Errorf("mlkem.NewDecapsulationKey1024 failed after mlkem.NewDecapsulationKey768 failed: %w / %w", err, err1024) + } + return &MLKEMDecryptor1024{decap: decap1024}, nil + } + + if block.Type == "HYBRID X-WING PRIVATE KEY" { + decap, err := NewHybridXWingDecryptor(block.Bytes) + if err != nil { + return nil, err + } + return &HybridXWingDecryptorWrapper{decap: decap}, nil + } + priv, err := x509.ParsePKCS8PrivateKey(block.Bytes) switch { case err == nil: @@ -109,6 +145,13 @@ func (asymDecryption AsymDecryption) Decrypt(data []byte) ([]byte, error) { return bytes, nil } +func (asymDecryption AsymDecryption) DecryptWithEphemeralKey(data, ephemeral []byte) ([]byte, error) { + if len(ephemeral) > 0 { + return nil, errors.New("ephemeral key is not supported for RSA decryption") + } + return asymDecryption.Decrypt(data) +} + type ECDecryptor struct { sk *ecdh.PrivateKey salt []byte @@ -196,6 +239,129 @@ func (e ECDecryptor) DecryptWithEphemeralKey(data, ephemeral []byte) ([]byte, er return plaintext, nil } +func (d MLKEMDecryptor768) Decrypt(_ []byte) ([]byte, error) { + return nil, errors.New("ciphertext encapsulation is required for ML-KEM decryption") +} + +func (d MLKEMDecryptor1024) Decrypt(_ []byte) ([]byte, error) { + return nil, errors.New("ciphertext encapsulation is required for ML-KEM decryption") +} + +func (d MLKEMDecryptor768) DecryptWithEphemeralKey(data, ephemeral []byte) ([]byte, error) { + if d.decap == nil { + return nil, errors.New("mlkem decapsulation key is nil") + } + if len(ephemeral) == 0 { + return nil, errors.New("ciphertext encapsulation is required for ML-KEM decryption") + } + + sharedSecret, err := d.decap.Decapsulate(ephemeral) + if err != nil { + return nil, fmt.Errorf("mlkem.Decapsulate failed: %w", err) + } + + block, err := aes.NewCipher(sharedSecret) + if err != nil { + return nil, fmt.Errorf("aes.NewCipher failure: %w", err) + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, fmt.Errorf("cipher.NewGCM failure: %w", err) + } + + nonceSize := gcm.NonceSize() + if len(data) < nonceSize { + return nil, errors.New("ciphertext too short") + } + + nonce, ciphertext := data[:nonceSize], data[nonceSize:] + plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) + if err != nil { + return nil, fmt.Errorf("gcm.Open failure: %w", err) + } + + return plaintext, nil +} + +func (d MLKEMDecryptor1024) DecryptWithEphemeralKey(data, ephemeral []byte) ([]byte, error) { + if d.decap == nil { + return nil, errors.New("mlkem decapsulation key is nil") + } + if len(ephemeral) == 0 { + return nil, errors.New("ciphertext encapsulation is required for ML-KEM decryption") + } + + sharedSecret, err := d.decap.Decapsulate(ephemeral) + if err != nil { + return nil, fmt.Errorf("mlkem.Decapsulate failed: %w", err) + } + + block, err := aes.NewCipher(sharedSecret) + if err != nil { + return nil, fmt.Errorf("aes.NewCipher failure: %w", err) + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, fmt.Errorf("cipher.NewGCM failure: %w", err) + } + + nonceSize := gcm.NonceSize() + if len(data) < nonceSize { + return nil, errors.New("ciphertext too short") + } + + nonce, ciphertext := data[:nonceSize], data[nonceSize:] + plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) + if err != nil { + return nil, fmt.Errorf("gcm.Open failure: %w", err) + } + + return plaintext, nil +} + +func (d HybridXWingDecryptorWrapper) Decrypt(_ []byte) ([]byte, error) { + return nil, errors.New("ciphertext encapsulation is required for Hybrid X-Wing decryption") +} + +func (d HybridXWingDecryptorWrapper) DecryptWithEphemeralKey(data, ephemeral []byte) ([]byte, error) { + if d.decap == nil { + return nil, errors.New("hybrid x-wing decapsulation key is nil") + } + if len(ephemeral) == 0 { + return nil, errors.New("ciphertext encapsulation is required for Hybrid X-Wing decryption") + } + + sharedSecret, err := d.decap.Decapsulate(ephemeral) + if err != nil { + return nil, fmt.Errorf("hybrid x-wing Decapsulate failed: %w", err) + } + + block, err := aes.NewCipher(sharedSecret) + if err != nil { + return nil, fmt.Errorf("aes.NewCipher failure: %w", err) + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, fmt.Errorf("cipher.NewGCM failure: %w", err) + } + + nonceSize := gcm.NonceSize() + if len(data) < nonceSize { + return nil, errors.New("ciphertext too short") + } + + nonce, ciphertext := data[:nonceSize], data[nonceSize:] + plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) + if err != nil { + return nil, fmt.Errorf("gcm.Open failure: %w", err) + } + + return plaintext, nil +} + func convCurve(c ecdh.Curve) elliptic.Curve { switch c { case ecdh.P256(): diff --git a/lib/ocrypto/asym_encryption.go b/lib/ocrypto/asym_encryption.go index c44aa64cce..1b054ba5df 100644 --- a/lib/ocrypto/asym_encryption.go +++ b/lib/ocrypto/asym_encryption.go @@ -5,11 +5,13 @@ import ( "crypto/cipher" "crypto/ecdh" "crypto/ecdsa" + "crypto/mlkem" "crypto/rand" "crypto/rsa" "crypto/sha1" //nolint:gosec // used for padding which is safe "crypto/sha256" "crypto/x509" + "encoding/asn1" "encoding/pem" "errors" "fmt" @@ -23,8 +25,10 @@ import ( type SchemeType string const ( - RSA SchemeType = "wrapped" - EC SchemeType = "ec-wrapped" + RSA SchemeType = "wrapped" + EC SchemeType = "ec-wrapped" + MLKEM SchemeType = "mlkem-wrapped" + Hybrid SchemeType = "hybrid" ) type PublicKeyEncryptor interface { @@ -40,7 +44,8 @@ type PublicKeyEncryptor interface { // KeyType returns the key type, e.g. RSA or EC. KeyType() KeyType - // For EC schemes, this method returns the public part of the ephemeral key. + // For EC and ML-KEM schemes, this method returns the public part of the ephemeral key. + // For Hybrid scheme, it returns the ASN.1 marshaled ciphertext. // Otherwise, it returns nil. EphemeralKey() []byte @@ -59,6 +64,24 @@ type ECEncryptor struct { info []byte } +type MLKEMEncryptor768 struct { + pub *mlkem.EncapsulationKey768 + cipherText []byte + sharedSecret []byte +} + +type MLKEMEncryptor1024 struct { + pub *mlkem.EncapsulationKey1024 + cipherText []byte + sharedSecret []byte +} + +type HybridXWingEncryptorWrapper struct { + enc *HybridXWingEncryptor + sharedSecret []byte + ciphertext []byte +} + func FromPublicPEM(publicKeyInPem string) (PublicKeyEncryptor, error) { // TK Move salt and info out of library, into API option functions digest := sha256.New() @@ -85,6 +108,12 @@ func FromPublicPEMWithSalt(publicKeyInPem string, salt, info []byte) (PublicKeyE return newECIES(e, salt, info) case *ecdh.PublicKey: return newECIES(pub, salt, info) + case *mlkem.EncapsulationKey768: + return newMLKEM768(pub), nil + case *mlkem.EncapsulationKey1024: + return newMLKEM1024(pub), nil + case *HybridXWingEncryptor: + return newHybridXWing(pub) default: break } @@ -97,6 +126,24 @@ func newECIES(pub *ecdh.PublicKey, salt, info []byte) (ECEncryptor, error) { return ECEncryptor{pub, ek, salt, info}, err } +func newMLKEM768(pub *mlkem.EncapsulationKey768) *MLKEMEncryptor768 { + sharedSecret, cipherText := pub.Encapsulate() + return &MLKEMEncryptor768{pub: pub, cipherText: cipherText, sharedSecret: sharedSecret} +} + +func newMLKEM1024(pub *mlkem.EncapsulationKey1024) *MLKEMEncryptor1024 { + sharedSecret, cipherText := pub.Encapsulate() + return &MLKEMEncryptor1024{pub: pub, cipherText: cipherText, sharedSecret: sharedSecret} +} + +func newHybridXWing(pub *HybridXWingEncryptor) (*HybridXWingEncryptorWrapper, error) { + sharedSecret, ciphertext, err := pub.Encapsulate() + if err != nil { + return nil, err + } + return &HybridXWingEncryptorWrapper{enc: pub, sharedSecret: sharedSecret, ciphertext: ciphertext}, nil +} + // NewAsymEncryption creates and returns a new AsymEncryption. // // Deprecated: Use FromPublicPEM instead. @@ -123,15 +170,32 @@ func getPublicPart(publicKeyInPem string) (any, error) { } var pub any - if strings.Contains(publicKeyInPem, "BEGIN CERTIFICATE") { + var err error + switch { + case strings.Contains(publicKeyInPem, "BEGIN CERTIFICATE"): cert, err := x509.ParseCertificate(block.Bytes) if err != nil { return nil, fmt.Errorf("x509.ParseCertificate failed: %w", err) } pub = cert.PublicKey - } else { - var err error + case block.Type == "MLKEM ENCAPSULATOR": + encap768, err := mlkem.NewEncapsulationKey768(block.Bytes) + if err == nil { + pub = encap768 + break + } + encap1024, err1024 := mlkem.NewEncapsulationKey1024(block.Bytes) + if err1024 != nil { + return nil, fmt.Errorf("mlkem.NewEncapsulationKey1024 failed after mlkem.NewEncapsulationKey768 failed: %w / %w", err, err1024) + } + pub = encap1024 + case block.Type == "HYBRID X-WING PUBLIC KEY": + pub, err = NewHybridXWingEncryptor(block.Bytes) + if err != nil { + return nil, err + } + default: pub, err = x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return nil, fmt.Errorf("x509.ParsePKIXPublicKey failed: %w", err) @@ -160,6 +224,18 @@ func (e ECEncryptor) Type() SchemeType { return EC } +func (e MLKEMEncryptor768) Type() SchemeType { + return MLKEM +} + +func (e MLKEMEncryptor1024) Type() SchemeType { + return MLKEM +} + +func (e *HybridXWingEncryptorWrapper) Type() SchemeType { + return Hybrid +} + func (e ECEncryptor) KeyType() KeyType { switch e.pub.Curve() { case ecdh.P256(): @@ -176,6 +252,18 @@ func (e ECEncryptor) KeyType() KeyType { } } +func (e MLKEMEncryptor768) KeyType() KeyType { + return MLKEM768Key +} + +func (e MLKEMEncryptor1024) KeyType() KeyType { + return MLKEM1024Key +} + +func (e *HybridXWingEncryptorWrapper) KeyType() KeyType { + return HybridXWingKey +} + func (e AsymEncryption) EphemeralKey() []byte { return nil } @@ -188,6 +276,18 @@ func (e ECEncryptor) EphemeralKey() []byte { return publicKeyBytes } +func (e MLKEMEncryptor768) EphemeralKey() []byte { + return e.cipherText +} + +func (e MLKEMEncryptor1024) EphemeralKey() []byte { + return e.cipherText +} + +func (e *HybridXWingEncryptorWrapper) EphemeralKey() []byte { + return e.ciphertext +} + func (e AsymEncryption) Metadata() (map[string]string, error) { return make(map[string]string), nil } @@ -198,6 +298,24 @@ func (e ECEncryptor) Metadata() (map[string]string, error) { return m, nil } +func (e MLKEMEncryptor768) Metadata() (map[string]string, error) { + m := make(map[string]string) + m["encapsulatedKey"] = string(e.EphemeralKey()) + return m, nil +} + +func (e MLKEMEncryptor1024) Metadata() (map[string]string, error) { + m := make(map[string]string) + m["encapsulatedKey"] = string(e.EphemeralKey()) + return m, nil +} + +func (e *HybridXWingEncryptorWrapper) Metadata() (map[string]string, error) { + m := make(map[string]string) + m["encapsulatedKey"] = string(e.EphemeralKey()) + return m, nil +} + func (e AsymEncryption) Encrypt(data []byte) ([]byte, error) { if e.PublicKey == nil { return nil, errors.New("failed to encrypt, public key is empty") @@ -269,7 +387,95 @@ func (e ECEncryptor) Encrypt(data []byte) ([]byte, error) { return ciphertext, nil } +func (e MLKEMEncryptor768) Encrypt(data []byte) ([]byte, error) { + block, err := aes.NewCipher(e.sharedSecret) + if err != nil { + return nil, fmt.Errorf("aes.NewCipher failed: %w", err) + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, fmt.Errorf("cipher.NewGCM failed: %w", err) + } + + nonce := make([]byte, gcm.NonceSize()) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + return nil, fmt.Errorf("nonce generation failed: %w", err) + } + + return gcm.Seal(nonce, nonce, data, nil), nil +} + +func (e MLKEMEncryptor1024) Encrypt(data []byte) ([]byte, error) { + block, err := aes.NewCipher(e.sharedSecret) + if err != nil { + return nil, fmt.Errorf("aes.NewCipher failed: %w", err) + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, fmt.Errorf("cipher.NewGCM failed: %w", err) + } + + nonce := make([]byte, gcm.NonceSize()) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + return nil, fmt.Errorf("nonce generation failed: %w", err) + } + + return gcm.Seal(nonce, nonce, data, nil), nil +} + +func (e *HybridXWingEncryptorWrapper) Encrypt(data []byte) ([]byte, error) { + block, err := aes.NewCipher(e.sharedSecret) + if err != nil { + return nil, fmt.Errorf("aes.NewCipher failed: %w", err) + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, fmt.Errorf("cipher.NewGCM failed: %w", err) + } + + nonce := make([]byte, gcm.NonceSize()) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + return nil, fmt.Errorf("nonce generation failed: %w", err) + } + + return gcm.Seal(nonce, nonce, data, nil), nil +} + // PublicKeyInPemFormat Returns public key in pem format. func (e ECEncryptor) PublicKeyInPemFormat() (string, error) { return publicKeyInPemFormat(e.ek.Public()) } + +func (e MLKEMEncryptor768) PublicKeyInPemFormat() (string, error) { + return string(pem.EncodeToMemory(&pem.Block{ + Type: "MLKEM ENCAPSULATOR", + Bytes: e.pub.Bytes(), + })), nil +} + +func (e MLKEMEncryptor1024) PublicKeyInPemFormat() (string, error) { + return string(pem.EncodeToMemory(&pem.Block{ + Type: "MLKEM ENCAPSULATOR", + Bytes: e.pub.Bytes(), + })), nil +} + +func (e *HybridXWingEncryptorWrapper) PublicKeyInPemFormat() (string, error) { + pk := hybridXWingPublicKeyASN1{ + X25519: e.enc.pkX, + MLKEM768: e.enc.pkM.Bytes(), + } + + bytes, err := asn1.Marshal(pk) + if err != nil { + return "", fmt.Errorf("failed to marshal hybrid public key: %w", err) + } + + return string(pem.EncodeToMemory(&pem.Block{ + Type: "HYBRID X-WING PUBLIC KEY", + Bytes: bytes, + })), nil +} diff --git a/lib/ocrypto/ec_key_pair.go b/lib/ocrypto/ec_key_pair.go index f9a9554d4f..7be2225cc7 100644 --- a/lib/ocrypto/ec_key_pair.go +++ b/lib/ocrypto/ec_key_pair.go @@ -4,6 +4,7 @@ import ( "crypto/ecdh" "crypto/ecdsa" "crypto/elliptic" + "crypto/mlkem" "crypto/rand" "crypto/sha256" "crypto/x509" @@ -19,16 +20,6 @@ import ( type ECCMode uint8 -type KeyType string - -const ( - RSA2048Key KeyType = "rsa:2048" - RSA4096Key KeyType = "rsa:4096" - EC256Key KeyType = "ec:secp256r1" - EC384Key KeyType = "ec:secp384r1" - EC521Key KeyType = "ec:secp521r1" -) - const ( ECCModeSecp256r1 ECCMode = 0 ECCModeSecp384r1 ECCMode = 1 @@ -36,14 +27,6 @@ const ( ECCModeSecp256k1 ECCMode = 3 ) -const ( - ECCurveP256Size = 256 - ECCurveP384Size = 384 - ECCurveP521Size = 521 - RSA2048Size = 2048 - RSA4096Size = 4096 -) - type KeyPair interface { PublicKeyInPemFormat() (string, error) PrivateKeyInPemFormat() (string, error) @@ -64,6 +47,12 @@ func NewKeyPair(kt KeyType) (KeyPair, error) { return nil, err } return NewECKeyPair(mode) + case MLKEM768Key: + return NewMLKEMKeyPair() + case MLKEM1024Key: + return NewMLKEM1024KeyPair() + case HybridXWingKey: + return NewHybridXWingKeyPair() default: return nil, fmt.Errorf("unsupported key type: %v", kt) } @@ -73,6 +62,14 @@ type ECKeyPair struct { PrivateKey *ecdsa.PrivateKey } +type MLKEMKeyPair struct { + PrivateKey *mlkem.DecapsulationKey768 +} + +type MLKEM1024KeyPair struct { + PrivateKey *mlkem.DecapsulationKey1024 +} + func IsECKeyType(kt KeyType) bool { switch kt { //nolint:exhaustive // only handle ec types case EC256Key, EC384Key, EC521Key: @@ -184,6 +181,24 @@ func NewECKeyPair(mode ECCMode) (ECKeyPair, error) { return ecKeyPair, nil } +func NewMLKEMKeyPair() (MLKEMKeyPair, error) { + privateKey, err := mlkem.GenerateKey768() + if err != nil { + return MLKEMKeyPair{}, fmt.Errorf("mlkem.GenerateKey768 failed: %w", err) + } + + return MLKEMKeyPair{PrivateKey: privateKey}, nil +} + +func NewMLKEM1024KeyPair() (MLKEM1024KeyPair, error) { + privateKey, err := mlkem.GenerateKey1024() + if err != nil { + return MLKEM1024KeyPair{}, fmt.Errorf("mlkem.GenerateKey1024 failed: %w", err) + } + + return MLKEM1024KeyPair{PrivateKey: privateKey}, nil +} + // PrivateKeyInPemFormat Returns private key in pem format. func (keyPair ECKeyPair) PrivateKeyInPemFormat() (string, error) { if keyPair.PrivateKey == nil { @@ -224,6 +239,62 @@ func (keyPair ECKeyPair) PublicKeyInPemFormat() (string, error) { return string(publicKeyPem), nil } +func (keyPair MLKEMKeyPair) PrivateKeyInPemFormat() (string, error) { + if keyPair.PrivateKey == nil { + return "", errors.New("failed to generate PEM formatted private key") + } + + privateKeyPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "MLKEM DECAPSULATION KEY", + Bytes: keyPair.PrivateKey.Bytes(), + }, + ) + return string(privateKeyPEM), nil +} + +func (keyPair MLKEMKeyPair) PublicKeyInPemFormat() (string, error) { + if keyPair.PrivateKey == nil { + return "", errors.New("failed to generate PEM formatted public key") + } + + publicKeyPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "MLKEM ENCAPSULATOR", + Bytes: keyPair.PrivateKey.EncapsulationKey().Bytes(), + }, + ) + return string(publicKeyPEM), nil +} + +func (keyPair MLKEM1024KeyPair) PrivateKeyInPemFormat() (string, error) { + if keyPair.PrivateKey == nil { + return "", errors.New("failed to generate PEM formatted private key") + } + + privateKeyPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "MLKEM DECAPSULATION KEY", + Bytes: keyPair.PrivateKey.Bytes(), + }, + ) + return string(privateKeyPEM), nil +} + +func (keyPair MLKEM1024KeyPair) PublicKeyInPemFormat() (string, error) { + if keyPair.PrivateKey == nil { + return "", errors.New("failed to generate PEM formatted public key") + } + + publicKeyPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "MLKEM ENCAPSULATOR", + Bytes: keyPair.PrivateKey.EncapsulationKey().Bytes(), + }, + ) + return string(publicKeyPEM), nil +} + // KeySize Return the size of this ec key pair. func (keyPair ECKeyPair) KeySize() (int, error) { if keyPair.PrivateKey == nil { @@ -494,3 +565,11 @@ func GetECKeySize(pemData []byte) (int, error) { func (keyPair ECKeyPair) GetKeyType() KeyType { return EC256Key } + +func (keyPair MLKEMKeyPair) GetKeyType() KeyType { + return MLKEM768Key +} + +func (keyPair MLKEM1024KeyPair) GetKeyType() KeyType { + return MLKEM1024Key +} diff --git a/lib/ocrypto/hybrid.go b/lib/ocrypto/hybrid.go new file mode 100644 index 0000000000..cd8f42d8ee --- /dev/null +++ b/lib/ocrypto/hybrid.go @@ -0,0 +1,234 @@ +package ocrypto + +import ( + "crypto/ecdh" + "crypto/mlkem" + "crypto/rand" + "encoding/asn1" + "encoding/pem" + "errors" + "fmt" + + "golang.org/x/crypto/sha3" +) + +// HybridXWingKeyPair combines X25519 and ML-KEM-768 +type HybridXWingKeyPair struct { + X25519 *ecdh.PrivateKey + MLKEM768 *mlkem.DecapsulationKey768 +} + +type hybridXWingPublicKeyASN1 struct { + X25519 []byte + MLKEM768 []byte +} + +type hybridXWingPrivateKeyASN1 struct { + X25519 []byte + MLKEM768 []byte +} + +type hybridXWingCiphertextASN1 struct { + X25519 []byte + MLKEM768 []byte +} + +func NewHybridXWingKeyPair() (*HybridXWingKeyPair, error) { + x25519, err := ecdh.X25519().GenerateKey(rand.Reader) + if err != nil { + return nil, fmt.Errorf("ecdh.X25519.GenerateKey failed: %w", err) + } + + mlkem768, err := mlkem.GenerateKey768() + if err != nil { + return nil, fmt.Errorf("mlkem.GenerateKey768 failed: %w", err) + } + + return &HybridXWingKeyPair{ + X25519: x25519, + MLKEM768: mlkem768, + }, nil +} + +func (kp *HybridXWingKeyPair) GetKeyType() KeyType { + return HybridXWingKey +} + +func (kp *HybridXWingKeyPair) PublicKeyInPemFormat() (string, error) { + pk := hybridXWingPublicKeyASN1{ + X25519: kp.X25519.PublicKey().Bytes(), + MLKEM768: kp.MLKEM768.EncapsulationKey().Bytes(), + } + + bytes, err := asn1.Marshal(pk) + if err != nil { + return "", fmt.Errorf("failed to marshal hybrid public key: %w", err) + } + + return string(pem.EncodeToMemory(&pem.Block{ + Type: "HYBRID X-WING PUBLIC KEY", + Bytes: bytes, + })), nil +} + +func (kp *HybridXWingKeyPair) PrivateKeyInPemFormat() (string, error) { + sk := hybridXWingPrivateKeyASN1{ + X25519: kp.X25519.Bytes(), + MLKEM768: kp.MLKEM768.Bytes(), + } + + bytes, err := asn1.Marshal(sk) + if err != nil { + return "", fmt.Errorf("failed to marshal hybrid private key: %w", err) + } + + return string(pem.EncodeToMemory(&pem.Block{ + Type: "HYBRID X-WING PRIVATE KEY", + Bytes: bytes, + })), nil +} + +// X-Wing KEM Shared Secret computation as per draft-connolly-cfrg-xwing-kem-10 +// Shared Secret: SHA3-256("\X-Wing" || ss_X || ss_M || X25519_pk || ML-KEM-768_pk || X25519_ct || ML-KEM-768_ct) +func computeXWingSharedSecret(ssX, ssM, pkX, pkM, ctX, ctM []byte) []byte { + h := sha3.New256() + h.Write([]byte("\\X-Wing")) + h.Write(ssX) + h.Write(ssM) + h.Write(pkX) + h.Write(pkM) + h.Write(ctX) + h.Write(ctM) + return h.Sum(nil) +} + +type HybridXWingEncryptor struct { + pkX []byte + pkM *mlkem.EncapsulationKey768 +} + +func NewHybridXWingEncryptor(pk []byte) (*HybridXWingEncryptor, error) { + var pkASN hybridXWingPublicKeyASN1 + if _, err := asn1.Unmarshal(pk, &pkASN); err != nil { + return nil, fmt.Errorf("failed to unmarshal hybrid public key: %w", err) + } + + pkM, err := mlkem.NewEncapsulationKey768(pkASN.MLKEM768) + if err != nil { + return nil, fmt.Errorf("failed to create MLKEM encapsulation key: %w", err) + } + + return &HybridXWingEncryptor{ + pkX: pkASN.X25519, + pkM: pkM, + }, nil +} + +func (e *HybridXWingEncryptor) Encapsulate() ([]byte, []byte, error) { + // X25519 encapsulation + ekX, err := ecdh.X25519().GenerateKey(rand.Reader) + if err != nil { + return nil, nil, err + } + pkX, err := ecdh.X25519().NewPublicKey(e.pkX) + if err != nil { + return nil, nil, err + } + ssX, err := ekX.ECDH(pkX) + if err != nil { + return nil, nil, err + } + ctX := ekX.PublicKey().Bytes() + + // ML-KEM-768 encapsulation + ssM, ctM := e.pkM.Encapsulate() + + // Compute combined shared secret + sharedSecret := computeXWingSharedSecret(ssX, ssM, e.pkX, e.pkM.Bytes(), ctX, ctM) + + // Marshal ciphertext into ASN.1 + ctASN := hybridXWingCiphertextASN1{ + X25519: ctX, + MLKEM768: ctM, + } + ciphertext, err := asn1.Marshal(ctASN) + if err != nil { + return nil, nil, err + } + + return sharedSecret, ciphertext, nil +} + +type HybridXWingDecryptor struct { + skX *ecdh.PrivateKey + skM *mlkem.DecapsulationKey768 +} + +func NewHybridXWingDecryptor(sk []byte) (*HybridXWingDecryptor, error) { + var skASN hybridXWingPrivateKeyASN1 + if _, err := asn1.Unmarshal(sk, &skASN); err != nil { + return nil, fmt.Errorf("failed to unmarshal hybrid private key: %w", err) + } + + skX, err := ecdh.X25519().NewPrivateKey(skASN.X25519) + if err != nil { + return nil, fmt.Errorf("failed to create X25519 private key: %w", err) + } + + skM, err := mlkem.NewDecapsulationKey768(skASN.MLKEM768) + if err != nil { + return nil, fmt.Errorf("failed to create MLKEM decapsulation key: %w", err) + } + + return &HybridXWingDecryptor{ + skX: skX, + skM: skM, + }, nil +} + +func (d *HybridXWingDecryptor) Decapsulate(ciphertext []byte) ([]byte, error) { + var ctASN hybridXWingCiphertextASN1 + if _, err := asn1.Unmarshal(ciphertext, &ctASN); err != nil { + return nil, fmt.Errorf("failed to unmarshal hybrid ciphertext: %w", err) + } + + // X25519 decapsulation + pkX, err := ecdh.X25519().NewPublicKey(ctASN.X25519) + if err != nil { + return nil, err + } + ssX, err := d.skX.ECDH(pkX) + if err != nil { + return nil, err + } + + // ML-KEM-768 decapsulation + ssM, err := d.skM.Decapsulate(ctASN.MLKEM768) + if err != nil { + return nil, err + } + + // Compute combined shared secret + sharedSecret := computeXWingSharedSecret(ssX, ssM, d.skX.PublicKey().Bytes(), d.skM.EncapsulationKey().Bytes(), ctASN.X25519, ctASN.MLKEM768) + + return sharedSecret, nil +} + +// Convert from PEM format to internal encryptor/decryptor +func HybridEncryptorFromPEM(publicKeyInPem string) (*HybridXWingEncryptor, error) { + block, _ := pem.Decode([]byte(publicKeyInPem)) + if block == nil || block.Type != "HYBRID X-WING PUBLIC KEY" { + return nil, errors.New("failed to parse HYBRID X-WING PUBLIC KEY") + } + + return NewHybridXWingEncryptor(block.Bytes) +} + +func HybridDecryptorFromPEM(privateKeyInPem string) (*HybridXWingDecryptor, error) { + block, _ := pem.Decode([]byte(privateKeyInPem)) + if block == nil || block.Type != "HYBRID X-WING PRIVATE KEY" { + return nil, errors.New("failed to parse HYBRID X-WING PRIVATE KEY") + } + + return NewHybridXWingDecryptor(block.Bytes) +} diff --git a/lib/ocrypto/hybrid_test.go b/lib/ocrypto/hybrid_test.go new file mode 100644 index 0000000000..f10738f410 --- /dev/null +++ b/lib/ocrypto/hybrid_test.go @@ -0,0 +1,81 @@ +package ocrypto + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestHybridXWingRoundtrip(t *testing.T) { + // Generate key pair + kp, err := NewHybridXWingKeyPair() + require.NoError(t, err) + require.NotNil(t, kp) + + publicKeyPEM, err := kp.PublicKeyInPemFormat() + require.NoError(t, err) + require.NotEmpty(t, publicKeyPEM) + + privateKeyPEM, err := kp.PrivateKeyInPemFormat() + require.NoError(t, err) + require.NotEmpty(t, privateKeyPEM) + + // Create encryptor and decryptor + encryptor, err := HybridEncryptorFromPEM(publicKeyPEM) + require.NoError(t, err) + require.NotNil(t, encryptor) + + decryptor, err := HybridDecryptorFromPEM(privateKeyPEM) + require.NoError(t, err) + require.NotNil(t, decryptor) + + // Encapsulate + ssEnc, ct, err := encryptor.Encapsulate() + require.NoError(t, err) + require.NotEmpty(t, ssEnc) + require.NotEmpty(t, ct) + + // Decapsulate + ssDec, err := decryptor.Decapsulate(ct) + require.NoError(t, err) + require.Equal(t, ssEnc, ssDec) +} + +func TestHybridXWingAsymEncryptionRoundtrip(t *testing.T) { + // Generate key pair + kp, err := NewHybridXWingKeyPair() + require.NoError(t, err) + + publicKeyPEM, err := kp.PublicKeyInPemFormat() + require.NoError(t, err) + + privateKeyPEM, err := kp.PrivateKeyInPemFormat() + require.NoError(t, err) + + // Create encryptor and decryptor via common interfaces + encryptor, err := FromPublicPEM(publicKeyPEM) + require.NoError(t, err) + assert.Equal(t, Hybrid, encryptor.Type()) + assert.Equal(t, HybridXWingKey, encryptor.KeyType()) + + decryptor, err := FromPrivatePEM(privateKeyPEM) + require.NoError(t, err) + + // Data to encrypt + data := []byte("hello world, hybrid style") + + // Encrypt + ciphertext, err := encryptor.Encrypt(data) + require.NoError(t, err) + require.NotEmpty(t, ciphertext) + + // Get ephemeral key (ciphertext from KEM) + ephemeral := encryptor.EphemeralKey() + require.NotEmpty(t, ephemeral) + + // Decrypt + plaintext, err := decryptor.DecryptWithEphemeralKey(ciphertext, ephemeral) + require.NoError(t, err) + assert.Equal(t, data, plaintext) +} diff --git a/lib/ocrypto/key_types.go b/lib/ocrypto/key_types.go new file mode 100644 index 0000000000..cdfb56584d --- /dev/null +++ b/lib/ocrypto/key_types.go @@ -0,0 +1,25 @@ +package ocrypto + +type KeyType string + +const ( + RSA2048Key KeyType = "rsa:2048" + RSA4096Key KeyType = "rsa:4096" + EC256Key KeyType = "ec:secp256r1" + EC384Key KeyType = "ec:secp384r1" + EC521Key KeyType = "ec:secp521r1" + MLKEM768Key KeyType = "mlkem:768" + MLKEM1024Key KeyType = "mlkem:1024" + HybridXWingKey KeyType = "hpqt:xwing" +) + +const ( + RSA2048Size = 2048 + RSA4096Size = 4096 +) + +const ( + ECCurveP256Size = 256 + ECCurveP384Size = 384 + ECCurveP521Size = 521 +) diff --git a/protocol/go/kas/kas.pb.go b/protocol/go/kas/kas.pb.go index 6d6fb574e3..ea24285f83 100644 --- a/protocol/go/kas/kas.pb.go +++ b/protocol/go/kas/kas.pb.go @@ -244,7 +244,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), 'mlkem-wrapped' (ML-KEM-wrapped), 'hybrid' (Hybrid 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 @@ -269,10 +269,10 @@ type KeyAccess struct { // Optional: Not used by ZTDF (policy and metadata are separate) // Contains magic bytes, version, algorithm, policy, and ephemeral key information 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) + // Ephemeral public key for ECDH/ML-KEM/Hybrid key derivation + // Required: When key_type="ec-wrapped", "mlkem-wrapped", or "hybrid" // Omitted: When key_type="wrapped" (RSA-based ZTDF) - // Should be a PEM-encoded PKCS#8 (ASN.1) formatted public key + // Should be a PEM-encoded or Base64-encoded (for ML-KEM/Hybrid) public key material // 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"` } @@ -855,8 +855,8 @@ type RewrapResponse struct { // Deprecated: Marked as deprecated in kas/kas.proto. 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") + // Required: For EC-based operations (key_type="ec-wrapped") or Hybrid + // Optional: Empty for RSA-based ZTDF (key_type="wrapped") or ML-KEM // 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 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..5d0d36b958 100644 --- a/protocol/go/policy/kasregistry/key_access_server_registry.pb.go +++ b/protocol/go/policy/kasregistry/key_access_server_registry.pb.go @@ -4012,218 +4012,219 @@ 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, 0xd4, 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, 0xac, 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, 0x74, 0xba, 0x48, 0x71, + 0xba, 0x01, 0x6e, 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, - 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, + 0x1a, 0x1f, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x5b, 0x31, 0x2c, 0x20, 0x32, 0x2c, + 0x20, 0x33, 0x2c, 0x20, 0x34, 0x2c, 0x20, 0x35, 0x2c, 0x20, 0x32, 0x30, 0x2c, 0x20, 0x32, 0x31, + 0x5d, 0x52, 0x0c, 0x6b, 0x65, 0x79, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, + 0x93, 0x01, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x4d, + 0x6f, 0x64, 0x65, 0x42, 0x67, 0xba, 0x48, 0x64, 0xba, 0x01, 0x61, 0x0a, 0x10, 0x6b, 0x65, 0x79, + 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x12, 0x35, 0x54, + 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x6d, 0x75, 0x73, 0x74, + 0x20, 0x62, 0x65, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, + 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x28, 0x31, + 0x2d, 0x34, 0x29, 0x2e, 0x1a, 0x16, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3e, 0x3d, 0x20, 0x31, 0x20, + 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3c, 0x3d, 0x20, 0x34, 0x52, 0x07, 0x6b, 0x65, + 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x42, 0x0a, 0x0e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, + 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x43, 0x74, 0x78, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x0c, 0x70, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x12, 0x3d, 0x0a, 0x0f, 0x70, 0x72, 0x69, + 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x72, 0x69, 0x76, + 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x52, 0x0d, 0x70, 0x72, 0x69, 0x76, 0x61, + 0x74, 0x65, 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x12, 0x33, + 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x3a, 0xbb, 0x07, 0xba, 0x48, 0xb7, 0x07, 0x1a, 0x97, 0x03, 0x0a, 0x23, 0x70, + 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x5f, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, + 0x65, 0x64, 0x12, 0xbc, 0x01, 0x54, 0x68, 0x65, 0x20, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, + 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x69, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, + 0x20, 0x69, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, + 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, + 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x20, 0x6f, 0x72, 0x20, 0x4b, 0x45, 0x59, 0x5f, + 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x44, 0x45, 0x52, 0x5f, 0x52, 0x4f, + 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x77, 0x72, 0x61, 0x70, + 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, + 0x65, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x69, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, + 0x65, 0x20, 0x69, 0x73, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x52, 0x45, + 0x4d, 0x4f, 0x54, 0x45, 0x20, 0x6f, 0x72, 0x20, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, + 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, + 0x2e, 0x1a, 0xb0, 0x01, 0x28, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, + 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x32, 0x29, 0x20, + 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, + 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x2e, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, + 0x6b, 0x65, 0x79, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x27, 0x29, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x28, + 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, + 0x20, 0x33, 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x6d, + 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x34, 0x29, 0x20, 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, + 0x78, 0x2e, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x3d, 0x3d, + 0x20, 0x27, 0x27, 0x29, 0x1a, 0xf4, 0x02, 0x0a, 0x26, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 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, 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, + 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, 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, + 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, 0xed, 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, 0xd7, 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, 0xa5, + 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, 0x74, 0xba, 0x48, 0x71, 0xba, 0x01, 0x6e, 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, 0x1f, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x69, 0x6e, 0x20, 0x5b, 0x31, 0x2c, 0x20, 0x32, 0x2c, 0x20, 0x33, 0x2c, 0x20, 0x34, 0x2c, + 0x20, 0x35, 0x2c, 0x20, 0x32, 0x30, 0x2c, 0x20, 0x32, 0x31, 0x5d, 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x9e, 0x01, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x42, 0x72, 0xba, 0x48, 0x6f, 0xba, diff --git a/protocol/go/policy/objects.pb.go b/protocol/go/policy/objects.pb.go index d2c0921c8b..6efbf9b0f1 100644 --- a/protocol/go/policy/objects.pb.go +++ b/protocol/go/policy/objects.pb.go @@ -243,17 +243,23 @@ 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_MLKEM_768 KasPublicKeyAlgEnum = 20 + KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 KasPublicKeyAlgEnum = 21 + KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING KasPublicKeyAlgEnum = 30 ) // 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", + 20: "KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768", + 21: "KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024", + 30: "KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING", } KasPublicKeyAlgEnum_value = map[string]int32{ "KAS_PUBLIC_KEY_ALG_ENUM_UNSPECIFIED": 0, @@ -262,6 +268,9 @@ var ( "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_MLKEM_768": 20, + "KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024": 21, + "KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING": 30, } ) @@ -296,31 +305,40 @@ func (KasPublicKeyAlgEnum) EnumDescriptor() ([]byte, []int) { type Algorithm int32 const ( - Algorithm_ALGORITHM_UNSPECIFIED Algorithm = 0 - Algorithm_ALGORITHM_RSA_2048 Algorithm = 1 - Algorithm_ALGORITHM_RSA_4096 Algorithm = 2 - Algorithm_ALGORITHM_EC_P256 Algorithm = 3 - Algorithm_ALGORITHM_EC_P384 Algorithm = 4 - Algorithm_ALGORITHM_EC_P521 Algorithm = 5 + Algorithm_ALGORITHM_UNSPECIFIED Algorithm = 0 + Algorithm_ALGORITHM_RSA_2048 Algorithm = 1 + Algorithm_ALGORITHM_RSA_4096 Algorithm = 2 + Algorithm_ALGORITHM_EC_P256 Algorithm = 3 + Algorithm_ALGORITHM_EC_P384 Algorithm = 4 + Algorithm_ALGORITHM_EC_P521 Algorithm = 5 + Algorithm_ALGORITHM_MLKEM_768 Algorithm = 20 + Algorithm_ALGORITHM_MLKEM_1024 Algorithm = 21 + Algorithm_ALGORITHM_HYBRID_XWING Algorithm = 30 ) // Enum value maps for Algorithm. var ( Algorithm_name = map[int32]string{ - 0: "ALGORITHM_UNSPECIFIED", - 1: "ALGORITHM_RSA_2048", - 2: "ALGORITHM_RSA_4096", - 3: "ALGORITHM_EC_P256", - 4: "ALGORITHM_EC_P384", - 5: "ALGORITHM_EC_P521", + 0: "ALGORITHM_UNSPECIFIED", + 1: "ALGORITHM_RSA_2048", + 2: "ALGORITHM_RSA_4096", + 3: "ALGORITHM_EC_P256", + 4: "ALGORITHM_EC_P384", + 5: "ALGORITHM_EC_P521", + 20: "ALGORITHM_MLKEM_768", + 21: "ALGORITHM_MLKEM_1024", + 30: "ALGORITHM_HYBRID_XWING", } 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_MLKEM_768": 20, + "ALGORITHM_MLKEM_1024": 21, + "ALGORITHM_HYBRID_XWING": 30, } ) @@ -3697,7 +3715,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, 0x81, 0x03, 0x0a, 0x13, 0x4b, 0x61, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x41, 0x6c, 0x67, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x27, 0x0a, 0x23, 0x4b, 0x41, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, @@ -3713,41 +3731,53 @@ 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, 0x25, 0x0a, 0x21, 0x4b, + 0x41, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, + 0x47, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x4d, 0x4c, 0x4b, 0x45, 0x4d, 0x5f, 0x37, 0x36, 0x38, + 0x10, 0x14, 0x12, 0x26, 0x0a, 0x22, 0x4b, 0x41, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, + 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x4d, 0x4c, + 0x4b, 0x45, 0x4d, 0x5f, 0x31, 0x30, 0x32, 0x34, 0x10, 0x15, 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, 0x48, 0x59, 0x42, 0x52, 0x49, 0x44, 0x5f, 0x58, 0x57, 0x49, + 0x4e, 0x47, 0x10, 0x1e, 0x2a, 0xea, 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, 0x17, 0x0a, 0x13, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, + 0x4d, 0x4c, 0x4b, 0x45, 0x4d, 0x5f, 0x37, 0x36, 0x38, 0x10, 0x14, 0x12, 0x18, 0x0a, 0x14, 0x41, + 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x4d, 0x4c, 0x4b, 0x45, 0x4d, 0x5f, 0x31, + 0x30, 0x32, 0x34, 0x10, 0x15, 0x12, 0x1a, 0x0a, 0x16, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, + 0x48, 0x4d, 0x5f, 0x48, 0x59, 0x42, 0x52, 0x49, 0x44, 0x5f, 0x58, 0x57, 0x49, 0x4e, 0x47, 0x10, + 0x1e, 0x2a, 0x56, 0x0a, 0x09, 0x4b, 0x65, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, + 0x0a, 0x16, 0x4b, 0x45, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x4b, 0x45, + 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, + 0x01, 0x12, 0x16, 0x0a, 0x12, 0x4b, 0x45, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, + 0x52, 0x4f, 0x54, 0x41, 0x54, 0x45, 0x44, 0x10, 0x02, 0x2a, 0x94, 0x01, 0x0a, 0x07, 0x4b, 0x65, + 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, + 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x1c, 0x0a, 0x18, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, + 0x49, 0x47, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x01, 0x12, 0x1e, 0x0a, + 0x1a, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x44, + 0x45, 0x52, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x02, 0x12, 0x13, 0x0a, + 0x0f, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, + 0x10, 0x03, 0x12, 0x1c, 0x0a, 0x18, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, + 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x04, + 0x42, 0x82, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x42, + 0x0c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, + 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, + 0x74, 0x64, 0x66, 0x2f, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0xa2, + 0x02, 0x03, 0x50, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0xca, 0x02, + 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0xe2, 0x02, 0x12, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x06, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/sdk/basekey.go b/sdk/basekey.go index 5f3cc12004..ea091914d9 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.MLKEM768Key): + return policy.Algorithm_ALGORITHM_MLKEM_768 + case string(ocrypto.MLKEM1024Key): + return policy.Algorithm_ALGORITHM_MLKEM_1024 + case string(ocrypto.HybridXWingKey): + return policy.Algorithm_ALGORITHM_HYBRID_XWING 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_MLKEM_768: + return string(ocrypto.MLKEM768Key), nil + case policy.Algorithm_ALGORITHM_MLKEM_1024: + return string(ocrypto.MLKEM1024Key), nil + case policy.Algorithm_ALGORITHM_HYBRID_XWING: + return string(ocrypto.HybridXWingKey), nil case policy.Algorithm_ALGORITHM_UNSPECIFIED: fallthrough default: diff --git a/sdk/codegen/runner/generate.go b/sdk/codegen/runner/generate.go index 211cedfdc4..0a8a88e197 100644 --- a/sdk/codegen/runner/generate.go +++ b/sdk/codegen/runner/generate.go @@ -177,12 +177,11 @@ func New%s%s%sConnectWrapper(httpClient connect.HTTPClient, baseURL string, opts func generateInterfaceType(interfaceName string, methods []string, packageName, prefix, suffix string) string { // Generate the interface type definition var builder strings.Builder - builder.WriteString(fmt.Sprintf(` + fmt.Fprintf(&builder, ` type %s%s%s interface { -`, prefix, interfaceName, suffix)) +`, prefix, interfaceName, suffix) for _, method := range methods { - builder.WriteString(fmt.Sprintf(` %s(ctx context.Context, req *%s.%sRequest) (*%s.%sResponse, error) -`, method, packageName, method, packageName, method)) + fmt.Fprintf(&builder, " %s(ctx context.Context, req *%s.%sRequest) (*%s.%sResponse, error)\n", method, packageName, method, packageName, method) } builder.WriteString("}\n") return builder.String() diff --git a/sdk/experimental/tdf/keysplit/attributes.go b/sdk/experimental/tdf/keysplit/attributes.go index e12d838e97..31ec8b2f4a 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_MLKEM_768: + return "mlkem:768" + case policy.Algorithm_ALGORITHM_MLKEM_1024: + return "mlkem:1024" + case policy.Algorithm_ALGORITHM_HYBRID_XWING: + return "hpqt:xwing" 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_MLKEM_768: + return policy.Algorithm_ALGORITHM_MLKEM_768 + case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024: + return policy.Algorithm_ALGORITHM_MLKEM_1024 + case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING: + return policy.Algorithm_ALGORITHM_HYBRID_XWING case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_UNSPECIFIED: return policy.Algorithm_ALGORITHM_UNSPECIFIED default: diff --git a/sdk/granter.go b/sdk/granter.go index 8275a04f42..e309f648bd 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_MLKEM_768: + return policy.Algorithm_ALGORITHM_MLKEM_768 + case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024: + return policy.Algorithm_ALGORITHM_MLKEM_1024 + case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING: + return policy.Algorithm_ALGORITHM_HYBRID_XWING 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.MLKEM768Key: + return policy.Algorithm_ALGORITHM_MLKEM_768 + case ocrypto.MLKEM1024Key: + return policy.Algorithm_ALGORITHM_MLKEM_1024 + case ocrypto.HybridXWingKey: + return policy.Algorithm_ALGORITHM_HYBRID_XWING 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_MLKEM_768: + return string(ocrypto.MLKEM768Key) + case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024: + return string(ocrypto.MLKEM1024Key) + case policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING: + return string(ocrypto.HybridXWingKey) 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_MLKEM_768: + return ocrypto.MLKEM768Key + case policy.Algorithm_ALGORITHM_MLKEM_1024: + return ocrypto.MLKEM1024Key + case policy.Algorithm_ALGORITHM_HYBRID_XWING: + return ocrypto.HybridXWingKey case policy.Algorithm_ALGORITHM_UNSPECIFIED: return ocrypto.KeyType("") default: diff --git a/sdk/schema/manifest.schema.json b/sdk/schema/manifest.schema.json index 6488623fa2..983747a394 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", "remote", "wrapped", "mlkem-wrapped", "hybrid"] }, "url": { "description": "A fully qualified URL pointing to a key access service responsible for managing access to the encryption keys.", diff --git a/sdk/tdf.go b/sdk/tdf.go index db22208b5f..82b82e2f58 100644 --- a/sdk/tdf.go +++ b/sdk/tdf.go @@ -43,6 +43,8 @@ const ( kKeySize = 32 kWrapped = "wrapped" kECWrapped = "ec-wrapped" + kMLKEMWrapped = "mlkem-wrapped" + kHybridWrapped = "hybrid" kKasProtocol = "kas" kSplitKeyType = "split" kGCMCipherAlgorithm = "AES-256-GCM" @@ -674,7 +676,8 @@ func createKeyAccess(kasInfo KASInfo, symKey []byte, policyBinding PolicyBinding } ktype := ocrypto.KeyType(kasInfo.Algorithm) - if ocrypto.IsECKeyType(ktype) { + switch { + case ocrypto.IsECKeyType(ktype): mode, err := ocrypto.ECKeyTypeToMode(ktype) if err != nil { return KeyAccess{}, err @@ -686,7 +689,23 @@ func createKeyAccess(kasInfo KASInfo, symKey []byte, policyBinding PolicyBinding keyAccess.KeyType = kECWrapped keyAccess.WrappedKey = wrappedKeyInfo.wrappedKey keyAccess.EphemeralPublicKey = wrappedKeyInfo.publicKey - } else { + case ktype == ocrypto.MLKEM768Key, ktype == ocrypto.MLKEM1024Key: + wrappedKey, encapsulatedKey, err := generateWrapKeyWithMLKEM(kasInfo.PublicKey, symKey) + if err != nil { + return KeyAccess{}, err + } + keyAccess.KeyType = kMLKEMWrapped + keyAccess.WrappedKey = wrappedKey + keyAccess.EphemeralPublicKey = encapsulatedKey + case ktype == ocrypto.HybridXWingKey: + wrappedKey, encapsulatedKey, err := generateWrapKeyWithHybrid(kasInfo.PublicKey, symKey) + if err != nil { + return KeyAccess{}, err + } + keyAccess.KeyType = kHybridWrapped + keyAccess.WrappedKey = wrappedKey + keyAccess.EphemeralPublicKey = encapsulatedKey + default: wrappedKey, err := generateWrapKeyWithRSA(kasInfo.PublicKey, symKey) if err != nil { return KeyAccess{}, err @@ -761,6 +780,44 @@ func generateWrapKeyWithRSA(publicKey string, symKey []byte) (string, error) { return string(ocrypto.Base64Encode(wrappedKey)), nil } +func generateWrapKeyWithMLKEM(publicKey string, symKey []byte) (string, string, error) { + publicKeyEncryptor, err := ocrypto.FromPublicPEM(publicKey) + if err != nil { + return "", "", fmt.Errorf("generateWrapKeyWithMLKEM: ocrypto.FromPublicPEM failed:%w", err) + } + + wrappedKey, err := publicKeyEncryptor.Encrypt(symKey) + if err != nil { + return "", "", fmt.Errorf("generateWrapKeyWithMLKEM: encrypt failed:%w", err) + } + + encapsulatedKey := publicKeyEncryptor.EphemeralKey() + if len(encapsulatedKey) == 0 { + return "", "", errors.New("generateWrapKeyWithMLKEM: encapsulated key missing") + } + + return string(ocrypto.Base64Encode(wrappedKey)), string(ocrypto.Base64Encode(encapsulatedKey)), nil +} + +func generateWrapKeyWithHybrid(publicKey string, symKey []byte) (string, string, error) { + publicKeyEncryptor, err := ocrypto.FromPublicPEM(publicKey) + if err != nil { + return "", "", fmt.Errorf("generateWrapKeyWithHybrid: ocrypto.FromPublicPEM failed:%w", err) + } + + wrappedKey, err := publicKeyEncryptor.Encrypt(symKey) + if err != nil { + return "", "", fmt.Errorf("generateWrapKeyWithHybrid: encrypt failed:%w", err) + } + + encapsulatedKey := publicKeyEncryptor.EphemeralKey() + if len(encapsulatedKey) == 0 { + return "", "", errors.New("generateWrapKeyWithHybrid: encapsulated key missing") + } + + return string(ocrypto.Base64Encode(wrappedKey)), string(ocrypto.Base64Encode(encapsulatedKey)), nil +} + // create policy object func createPolicyObject(attributes []AttributeValueFQN) (PolicyObject, error) { uuidObj, err := uuid.NewUUID() diff --git a/service/internal/security/basic_manager.go b/service/internal/security/basic_manager.go index 6197e50eb3..2080b8ccda 100644 --- a/service/internal/security/basic_manager.go +++ b/service/internal/security/basic_manager.go @@ -97,6 +97,26 @@ 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.MLKEM768Key, ocrypto.MLKEM1024Key: + plaintext, err := decrypter.DecryptWithEphemeralKey(ciphertext, ephemeralPublicKey) + if err != nil { + return nil, fmt.Errorf("failed to decrypt with ML-KEM: %w", err) + } + protectedKey, err := ocrypto.NewAESProtectedKey(plaintext) + if err != nil { + return nil, fmt.Errorf("failed to create protected key: %w", err) + } + return protectedKey, nil + case ocrypto.HybridXWingKey: + plaintext, err := decrypter.DecryptWithEphemeralKey(ciphertext, ephemeralPublicKey) + if err != nil { + return nil, fmt.Errorf("failed to decrypt with Hybrid 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 } 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..5c32948667 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 encryption with ML-KEM of the KAO + AlgorithmMLKEM768 = "mlkem:768" + AlgorithmMLKEM1024 = "mlkem:1024" + + // Used for encryption with Hybrid X-Wing of the KAO + AlgorithmHybridXWing = "hpqt:xwing" ) diff --git a/service/internal/security/in_process_provider.go b/service/internal/security/in_process_provider.go index 67c86487aa..0ac95ad5f0 100644 --- a/service/internal/security/in_process_provider.go +++ b/service/internal/security/in_process_provider.go @@ -2,7 +2,6 @@ package security import ( "context" - "crypto" "crypto/elliptic" "crypto/x509" "encoding/pem" @@ -80,11 +79,7 @@ func (k *KeyDetailsAdapter) ExportPublicKey(_ context.Context, format trust.KeyT return jwkKey, nil case trust.KeyTypePKCS8: - // Try to get the key as an RSA key first - if rsaKey, err := k.cryptoProvider.RSAPublicKey(kid); err == nil { - return rsaKey, nil - } - return k.cryptoProvider.ECPublicKey(kid) + return k.cryptoProvider.PublicKey(kid) default: return "", ErrCertNotFound } @@ -92,8 +87,11 @@ func (k *KeyDetailsAdapter) ExportPublicKey(_ context.Context, format trust.KeyT func (k *KeyDetailsAdapter) ExportCertificate(_ context.Context) (string, error) { kid := string(k.id) - if k.algorithm == AlgorithmECP256R1 { + switch k.algorithm { + case AlgorithmECP256R1, AlgorithmECP384R1, AlgorithmECP521R1: return k.cryptoProvider.ECCertificate(kid) + case ocrypto.RSA2048Key, ocrypto.RSA4096Key, ocrypto.MLKEM768Key, ocrypto.MLKEM1024Key, ocrypto.HybridXWingKey: + return "", errors.New("certificates only available for EC keys") } return "", errors.New("certificates only available for EC keys") } @@ -170,31 +168,29 @@ 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 - } - } + key, ok := a.cryptoProvider.keysByID[string(id)] + if !ok { + return nil, ErrCertNotFound + } + + switch key := key.(type) { + case StandardECCrypto: + return &KeyDetailsAdapter{ + id: id, + algorithm: ocrypto.KeyType(key.Algorithm), + legacy: a.legacyKeys[string(id)], + cryptoProvider: a.cryptoProvider, + }, nil + case PrivateKeyCrypto: + return &KeyDetailsAdapter{ + id: id, + algorithm: ocrypto.KeyType(key.Algorithm), + legacy: a.legacyKeys[string(id)], + cryptoProvider: a.cryptoProvider, + }, nil + default: + return nil, ErrCertNotFound } - return nil, ErrCertNotFound } // ListKeys lists all available keys @@ -203,32 +199,36 @@ func (a *InProcessProvider) ListKeys(ctx context.Context) ([]trust.KeyDetails, e } func (a *InProcessProvider) ListKeysWith(ctx context.Context, opts trust.ListKeyOptions) ([]trust.KeyDetails, error) { - // This is a limited implementation as CryptoProvider doesn't expose a list of all keys var keys []trust.KeyDetails - // Try to find keys for known algorithms - for _, alg := range []string{AlgorithmRSA2048, AlgorithmECP256R1} { - if kids, err := a.cryptoProvider.ListKIDsByAlgorithm(alg); err == nil && len(kids) > 0 { - for _, kid := range kids { - if opts.LegacyOnly && !a.legacyKeys[kid] { - continue // Skip non-legacy keys if LegacyOnly is true - } - keys = append(keys, &KeyDetailsAdapter{ - id: trust.KeyIdentifier(kid), - algorithm: ocrypto.KeyType(alg), - cryptoProvider: a.cryptoProvider, - legacy: a.legacyKeys[kid], - }) - } - } else if err != nil { + for kid, key := range a.cryptoProvider.keysByID { + if opts.LegacyOnly && !a.legacyKeys[kid] { + continue + } + + var algorithm ocrypto.KeyType + switch key := key.(type) { + case StandardECCrypto: + algorithm = ocrypto.KeyType(key.Algorithm) + case PrivateKeyCrypto: + algorithm = ocrypto.KeyType(key.Algorithm) + default: if a.logger != nil { a.logger.WarnContext(ctx, - "failed to list keys by algorithm", - slog.String("algorithm", alg), - slog.Any("error", err), + "failed to list key with unsupported type", + slog.String("kid", kid), + slog.Any("type", fmt.Sprintf("%T", key)), ) } + continue } + + keys = append(keys, &KeyDetailsAdapter{ + id: trust.KeyIdentifier(kid), + algorithm: algorithm, + cryptoProvider: a.cryptoProvider, + legacy: a.legacyKeys[kid], + }) } return keys, nil @@ -237,30 +237,25 @@ func (a *InProcessProvider) ListKeysWith(ctx context.Context, opts trust.ListKey // Decrypt implements the unified decryption method for both RSA and EC func (a *InProcessProvider) Decrypt(ctx context.Context, keyDetails trust.KeyDetails, ciphertext []byte, ephemeralPublicKey []byte) (ocrypto.ProtectedKey, error) { kid := string(keyDetails.ID()) - - var protectedKey ocrypto.ProtectedKey - var err error - - // Try to determine the key type - keyType, err := a.determineKeyType(ctx, kid) - if err != nil { - return nil, err + key, ok := a.cryptoProvider.keysByID[kid] + if !ok { + return nil, ErrCertNotFound } var rawKey []byte - switch keyType { - case AlgorithmRSA2048: - if len(ephemeralPublicKey) > 0 { - return nil, errors.New("ephemeral public key should not be provided for RSA decryption") - } - rawKey, err = a.cryptoProvider.RSADecrypt(crypto.SHA1, kid, "", ciphertext) - - case AlgorithmECP256R1: + var err error + switch key := key.(type) { + case StandardECCrypto: if len(ephemeralPublicKey) == 0 { return nil, errors.New("ephemeral public key is required for EC decryption") } - protectedKey, err = a.cryptoProvider.ECDecrypt(ctx, kid, ephemeralPublicKey, ciphertext) - + protectedKey, err := a.cryptoProvider.ECDecrypt(ctx, kid, ephemeralPublicKey, ciphertext) + if err != nil { + return nil, err + } + return protectedKey, nil + case PrivateKeyCrypto: + rawKey, err = key.dec.DecryptWithEphemeralKey(ciphertext, ephemeralPublicKey) default: return nil, errors.New("unsupported key algorithm") } @@ -268,15 +263,7 @@ func (a *InProcessProvider) Decrypt(ctx context.Context, keyDetails trust.KeyDet if err != nil { return nil, err } - - if protectedKey == nil { - protectedKey, err = ocrypto.NewAESProtectedKey(rawKey) - if err != nil { - return nil, fmt.Errorf("failed to create protected key: %w", err) - } - } - - return protectedKey, nil + return ocrypto.NewAESProtectedKey(rawKey) } // DeriveKey computes an ECDH shared secret and derives an AES key via HKDF. @@ -334,19 +321,3 @@ func (a *InProcessProvider) GenerateECSessionKey(_ context.Context, ephemeralPub 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 - } - - // Then try EC - if _, err := a.cryptoProvider.ECPublicKey(kid); err == nil { - return AlgorithmECP256R1, 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..2c3805fbe3 100644 --- a/service/internal/security/standard_crypto.go +++ b/service/internal/security/standard_crypto.go @@ -52,10 +52,10 @@ type StandardKeyInfo struct { PublicKeyPath string `mapstructure:"public_key_path" json:"public_key_path"` } -type StandardRSACrypto struct { +type PrivateKeyCrypto struct { KeyPairInfo - asymDecryption ocrypto.AsymDecryption - asymEncryption ocrypto.AsymEncryption + dec ocrypto.PrivateKeyDecryptor + enc ocrypto.PublicKeyEncryptor } type StandardECCrypto struct { @@ -150,23 +150,19 @@ func loadKey(k KeyPairInfo) (any, error) { ecPrivateKeyPem: string(privatePEM), ecCertificatePEM: string(certPEM), }, nil - case AlgorithmRSA2048, AlgorithmRSA4096: - asymDecryption, err := ocrypto.NewAsymDecryption(string(privatePEM)) + case AlgorithmRSA2048, AlgorithmRSA4096, AlgorithmMLKEM768, AlgorithmMLKEM1024, AlgorithmHybridXWing: + decrypter, err := ocrypto.FromPrivatePEM(string(privatePEM)) if err != nil { - return nil, fmt.Errorf("ocrypto.NewAsymDecryption failed: %w", err) + return nil, fmt.Errorf("ocrypto.FromPrivatePEM failed: %w", err) } publicKeyEncryptor, err := ocrypto.FromPublicPEM(string(certPEM)) if err != nil { return nil, fmt.Errorf("ocrypto.FromPublicPEM failed: %w", err) } - asymEncryption, ok := publicKeyEncryptor.(*ocrypto.AsymEncryption) - if !ok { - return nil, fmt.Errorf("unexpected public key encryptor type: %T", publicKeyEncryptor) - } - return StandardRSACrypto{ - KeyPairInfo: k, - asymDecryption: asymDecryption, - asymEncryption: *asymEncryption, + return PrivateKeyCrypto{ + KeyPairInfo: k, + dec: decrypter, + enc: publicKeyEncryptor, }, nil default: return nil, errors.New("unsupported algorithm [" + k.Algorithm + "]") @@ -199,25 +195,20 @@ func loadDeprecatedKeys(rsaKeys map[string]StandardKeyInfo, ecKeys map[string]St if err != nil { return nil, fmt.Errorf("failed to rsa public key file: %w", err) } - publicKeyEncryptor, err := ocrypto.FromPublicPEM(string(publicPemData)) if err != nil { return nil, fmt.Errorf("ocrypto.FromPublicPEM failed: %w", err) } - asymEncryption, ok := publicKeyEncryptor.(*ocrypto.AsymEncryption) - if !ok { - return nil, fmt.Errorf("unexpected public key encryptor type: %T", publicKeyEncryptor) - } - k := StandardRSACrypto{ + k := PrivateKeyCrypto{ KeyPairInfo: KeyPairInfo{ Algorithm: AlgorithmRSA2048, KID: id, Private: kasInfo.PrivateKeyPath, Certificate: kasInfo.PublicKeyPath, }, - asymDecryption: asymDecryption, - asymEncryption: *asymEncryption, + dec: asymDecryption, + enc: publicKeyEncryptor, } keysByAlg[AlgorithmRSA2048][id] = k keysByID[id] = k @@ -266,22 +257,26 @@ func (s StandardCrypto) FindKID(alg string) string { return "" } -func (s StandardCrypto) RSAPublicKey(kid string) (string, error) { +func (s StandardCrypto) PublicKey(kid string) (string, error) { k, ok := s.keysByID[kid] if !ok { - return "", fmt.Errorf("no rsa key with id [%s]: %w", kid, ErrCertNotFound) - } - rsa, ok := k.(StandardRSACrypto) - if !ok { - return "", fmt.Errorf("key with id [%s] is not an RSA key: %w", kid, ErrCertNotFound) + return "", fmt.Errorf("no public key with id [%s]: %w", kid, ErrCertNotFound) } - - pem, err := rsa.asymEncryption.PublicKeyInPemFormat() - if err != nil { - return "", fmt.Errorf("failed to retrieve rsa public key file: %w", err) + switch key := k.(type) { + case PrivateKeyCrypto: + publicKeyPEM, err := key.enc.PublicKeyInPemFormat() + if err != nil { + return "", fmt.Errorf("failed to retrieve public key file: %w", err) + } + return publicKeyPEM, nil + case StandardECCrypto: + if key.ecCertificatePEM != "" { + return key.ecCertificatePEM, nil + } + return s.ECPublicKey(kid) + default: + return "", fmt.Errorf("key with id [%s] does not expose a public key: %w", kid, ErrCertNotFound) } - - return pem, nil } func (s StandardCrypto) ECCertificate(kid string) (string, error) { @@ -334,12 +329,12 @@ func (s StandardCrypto) RSADecrypt(_ crypto.Hash, kid string, _ string, cipherte if !ok { return nil, ErrCertNotFound } - rsa, ok := k.(StandardRSACrypto) + rsa, ok := k.(PrivateKeyCrypto) if !ok { return nil, ErrCertNotFound } - data, err := rsa.asymDecryption.Decrypt(ciphertext) + data, err := rsa.dec.Decrypt(ciphertext) if err != nil { return nil, fmt.Errorf("error decrypting data: %w", err) } @@ -355,12 +350,17 @@ func (s StandardCrypto) RSAPublicKeyAsJSON(kid string) (string, error) { if !ok { return "", ErrCertNotFound } - rsa, ok := k.(StandardRSACrypto) + rsa, ok := k.(PrivateKeyCrypto) if !ok { return "", ErrCertNotFound } - rsaPublicKeyJwk, err := jwk.FromRaw(rsa.asymEncryption.PublicKey) + asymEncryption, ok := rsa.enc.(*ocrypto.AsymEncryption) + if !ok { + return "", fmt.Errorf("key with id [%s] does not support JWK export: %w", kid, ErrCertNotFound) + } + + rsaPublicKeyJwk, err := jwk.FromRaw(asymEncryption.PublicKey) if err != nil { return "", fmt.Errorf("jwk.FromRaw: %w", err) } @@ -429,12 +429,8 @@ func (s *StandardCrypto) Decrypt(_ context.Context, keyID trust.KeyIdentifier, c return nil, fmt.Errorf("failed to decrypt with ephemeral key: %w", err) } - case StandardRSACrypto: - if len(ephemeralPublicKey) > 0 { - return nil, errors.New("ephemeral public key should not be provided for RSA decryption") - } - - rawKey, err = key.asymDecryption.Decrypt(ciphertext) + case PrivateKeyCrypto: + rawKey, err = key.dec.DecryptWithEphemeralKey(ciphertext, ephemeralPublicKey) if err != nil { return nil, fmt.Errorf("error decrypting data: %w", err) } diff --git a/service/kas/access/publicKey.go b/service/kas/access/publicKey.go index eb5b1fe780..98c5721e8a 100644 --- a/service/kas/access/publicKey.go +++ b/service/kas/access/publicKey.go @@ -149,11 +149,11 @@ func (p *Provider) PublicKey(ctx context.Context, req *connect.Request[kaspb.Pub } switch algorithm { - case security.AlgorithmECP256R1: + case security.AlgorithmECP256R1, security.AlgorithmECP384R1, security.AlgorithmECP521R1: // For EC keys, export the public key ecPublicKeyPem, err := keyDetails.ExportPublicKey(ctx, trust.KeyTypePKCS8) return r(ecPublicKeyPem, kid, err) - case security.AlgorithmRSA2048: + case security.AlgorithmMLKEM768, security.AlgorithmMLKEM1024, security.AlgorithmRSA2048, security.AlgorithmRSA4096, security.AlgorithmHybridXWing: fallthrough case "": switch fmt { diff --git a/service/kas/access/rewrap.go b/service/kas/access/rewrap.go index d62975a480..f771b5e9bf 100644 --- a/service/kas/access/rewrap.go +++ b/service/kas/access/rewrap.go @@ -667,6 +667,50 @@ func (p *Provider) verifyRewrapRequests(ctx context.Context, req *kaspb.Unsigned var dek ocrypto.ProtectedKey var err error switch kao.GetKeyAccessObject().GetKeyType() { + case string(ocrypto.MLKEM): + ephemeralCiphertext := kao.GetKeyAccessObject().GetEphemeralPublicKey() + if ephemeralCiphertext == "" { + p.Logger.WarnContext(ctx, "missing encapsulated key for ml-kem rewrap") + failedKAORewrap(results, kao, err400("bad request")) + continue + } + + encapsulatedKey, err := ocrypto.Base64Decode([]byte(ephemeralCiphertext)) + if err != nil { + p.Logger.WarnContext(ctx, "failed to decode encapsulated key for ml-kem rewrap", slog.Any("error", err)) + failedKAORewrap(results, kao, err400("bad request")) + continue + } + + kid := trust.KeyIdentifier(kao.GetKeyAccessObject().GetKid()) + dek, err = p.KeyDelegator.Decrypt(ctx, kid, kao.GetKeyAccessObject().GetWrappedKey(), encapsulatedKey) + if err != nil { + p.Logger.WarnContext(ctx, "failed to decrypt ML-KEM key", slog.Any("error", err)) + failedKAORewrap(results, kao, err400("bad request")) + continue + } + case string(ocrypto.Hybrid): + ephemeralCiphertext := kao.GetKeyAccessObject().GetEphemeralPublicKey() + if ephemeralCiphertext == "" { + p.Logger.WarnContext(ctx, "missing encapsulated key for hybrid rewrap") + failedKAORewrap(results, kao, err400("bad request")) + continue + } + + encapsulatedKey, err := ocrypto.Base64Decode([]byte(ephemeralCiphertext)) + if err != nil { + p.Logger.WarnContext(ctx, "failed to decode encapsulated key for hybrid rewrap", slog.Any("error", err)) + failedKAORewrap(results, kao, err400("bad request")) + continue + } + + kid := trust.KeyIdentifier(kao.GetKeyAccessObject().GetKid()) + dek, err = p.KeyDelegator.Decrypt(ctx, kid, kao.GetKeyAccessObject().GetWrappedKey(), encapsulatedKey) + if err != nil { + p.Logger.WarnContext(ctx, "failed to decrypt hybrid key", slog.Any("error", err)) + failedKAORewrap(results, kao, err400("bad request")) + continue + } case "ec-wrapped": if !p.ECTDFEnabled && !p.Preview.ECTDFEnabled { @@ -920,11 +964,11 @@ func (p *Provider) tdf3Rewrap(ctx context.Context, requests []*kaspb.UnsignedRew encap := security.OCEncapsulator{PublicKeyEncryptor: asymEncrypt} var sessionKey string - if e, ok := asymEncrypt.(ocrypto.ECEncryptor); ok { + switch e := asymEncrypt.(type) { + case ocrypto.ECEncryptor: sessionKey, err = e.PublicKeyInPemFormat() if err != nil { p.Logger.ErrorContext(ctx, "unable to serialize ephemeral key", slog.Any("error", err)) - // This may be a 500, but could also be caused by a bad clientPublicKey failAllKaos(requests, results, err400("invalid request")) return "", results, nil } @@ -933,6 +977,13 @@ func (p *Provider) tdf3Rewrap(ctx context.Context, requests []*kaspb.UnsignedRew failAllKaos(requests, results, err400("invalid request")) return "", results, nil } + case *ocrypto.HybridXWingEncryptorWrapper: + sessionKey, err = e.PublicKeyInPemFormat() + if err != nil { + p.Logger.ErrorContext(ctx, "unable to serialize hybrid session key", slog.Any("error", err)) + failAllKaos(requests, results, err400("invalid request")) + return "", results, nil + } } for _, pdpAccess := range pdpAccessResults { diff --git a/service/kas/kas.proto b/service/kas/kas.proto index 7563a25e49..d9ddc6de09 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), 'mlkem-wrapped' (ML-KEM-wrapped), 'hybrid' (Hybrid X-Wing-wrapped) string key_type = 4 [json_name = "type"]; // URL of the Key Access Server that can unwrap this key @@ -99,10 +99,10 @@ message KeyAccess { // Contains magic bytes, version, algorithm, policy, and ephemeral key information bytes header = 9; - // Ephemeral public key for ECDH key derivation (ec-wrapped type only) - // Required: When key_type="ec-wrapped" (experimental ECDH-based ZTDF) + // Ephemeral public key for ECDH/ML-KEM/Hybrid key derivation + // Required: When key_type="ec-wrapped", "mlkem-wrapped", or "hybrid" // Omitted: When key_type="wrapped" (RSA-based ZTDF) - // Should be a PEM-encoded PKCS#8 (ASN.1) formatted public key + // Should be a PEM-encoded or Base64-encoded (for ML-KEM/Hybrid) public key material // Used to derive the symmetric key for unwrapping the DEK string ephemeral_public_key = 10; } @@ -257,8 +257,8 @@ message RewrapResponse { bytes entity_wrapped_key = 2 [deprecated = true]; // 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") + // Required: For EC-based operations (key_type="ec-wrapped") or Hybrid + // Optional: Empty for RSA-based ZTDF (key_type="wrapped") or ML-KEM // 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..99e785e311 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_MLKEM_768: + return ocrypto.MLKEM768Key + case policy.Algorithm_ALGORITHM_MLKEM_1024: + return ocrypto.MLKEM1024Key + case policy.Algorithm_ALGORITHM_HYBRID_XWING: + return ocrypto.HybridXWingKey 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.MLKEM768Key): + return policy.Algorithm_ALGORITHM_MLKEM_768, nil + case string(ocrypto.MLKEM1024Key): + return policy.Algorithm_ALGORITHM_MLKEM_1024, nil + case string(ocrypto.HybridXWingKey): + return policy.Algorithm_ALGORITHM_HYBRID_XWING, nil default: return policy.Algorithm_ALGORITHM_UNSPECIFIED, fmt.Errorf("unsupported algorithm: %s", alg) } diff --git a/service/pkg/db/marshalHelpers.go b/service/pkg/db/marshalHelpers.go index 667ab27e21..1b10c1d4f5 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_MLKEM_768: + return "mlkem:768", nil + case policy.Algorithm_ALGORITHM_MLKEM_1024: + return "mlkem:1024", nil + case policy.Algorithm_ALGORITHM_HYBRID_XWING: + return "hpqt:xwing", nil case policy.Algorithm_ALGORITHM_UNSPECIFIED: fallthrough default: diff --git a/service/policy/db/grant_mappings.go b/service/policy/db/grant_mappings.go index 7c3688af58..e498c63b6c 100644 --- a/service/policy/db/grant_mappings.go +++ b/service/policy/db/grant_mappings.go @@ -22,6 +22,12 @@ 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_MLKEM_768: + return policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_768 + case policy.Algorithm_ALGORITHM_MLKEM_1024: + return policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 + case policy.Algorithm_ALGORITHM_HYBRID_XWING: + return policy.KasPublicKeyAlgEnum_KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_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..ae65fa19f9 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, 20, 21]" // Allow RSA, EC, and ML-KEM algorithms }]; // The algorithm to be used for the key // Required KeyMode key_mode = 4 [(buf.validate.field).cel = { @@ -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, 20, 21]" // Allow RSA, EC, and ML-KEM algorithms }]; // Required KeyMode key_mode = 3 [ diff --git a/service/policy/objects.proto b/service/policy/objects.proto index a54bc2517a..5d45585f84 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_MLKEM_768 = 20; + KAS_PUBLIC_KEY_ALG_ENUM_MLKEM_1024 = 21; + KAS_PUBLIC_KEY_ALG_ENUM_HYBRID_XWING = 30; } // Deprecated @@ -553,6 +556,9 @@ enum Algorithm { ALGORITHM_EC_P256 = 3; ALGORITHM_EC_P384 = 4; ALGORITHM_EC_P521 = 5; + ALGORITHM_MLKEM_768 = 20; + ALGORITHM_MLKEM_1024 = 21; + ALGORITHM_HYBRID_XWING = 30; } // The status of the key