From 8ba515ce6be920e35a8b9b86913b06318ddf693b Mon Sep 17 00:00:00 2001 From: Jose Corella Date: Wed, 27 Sep 2023 16:20:30 -0700 Subject: [PATCH 1/8] chore(decrypt): specify behavior on decrypt with encryption context --- .../background.md | 540 ++++++++++++++++++ .../change.md | 52 ++ client-apis/decrypt.md | 17 +- 3 files changed, 608 insertions(+), 1 deletion(-) create mode 100644 changes/2023-09-26_encryption-context-decrypt/background.md create mode 100644 changes/2023-09-26_encryption-context-decrypt/change.md diff --git a/changes/2023-09-26_encryption-context-decrypt/background.md b/changes/2023-09-26_encryption-context-decrypt/background.md new file mode 100644 index 00000000..3df9beb8 --- /dev/null +++ b/changes/2023-09-26_encryption-context-decrypt/background.md @@ -0,0 +1,540 @@ +[//]: # "Copyright Amazon.com Inc. or its affiliates. All Rights Reserved." +[//]: # "SPDX-License-Identifier: CC-BY-SA-4.0" + +# Which Encryption Context should be used in Decrypt Operations + +## Definitions + +### Conventions used in this document + +The key words +"MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", +"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" +in this document are to be interpreted as described in +[RFC 2119](https://tools.ietf.org/html/rfc2119). + +## Issues and Alternatives + +### What kind of Encryption Context should Decrypt return? + +Decrypt returns Encryption Context. +This requirement may be satisfied by returning the parsed header that contains this value. + +With the addition of the [required encryption context cmm](../../framework/required-encryption-context-cmm.md), +the encrypt API is able to filter out encryption context key-value pairs that +are not stored but instead authenticated. + +Currently, on decrypt takes in optional encryption context. +This optional encryption context is used as encryption context for authentication only. + +The Required Encryption Context CMM can modify the encryption context on decrypt. +This results in values that are not authenticated against the message or the plaintext data key. + +It MUST be required that the decryption materials obtained from the underlying CMM's MUST +contain all configured encryption context keys in its encryption context and the values MUST remain +unchanged. + +The Decrypt API MUST return the encryption context stored in the header and the encryption +context used for authentication only. + +### What changes to the existing Required Encryption Context CMM are required? + +None + +### API changes + +If required encryption context keys match any keys stored in the message header, +their values MUST match. Otherwise old messages are not compatible with the required encryption context CMM. + +``` +forall k <- decryptionMaterials.requiredEncryptionContextKeys + | k in headerEncryptionContext + :: decryptionMaterials[k] == headerEncryptionContext[k] +``` + +## Testing + +In order to test that decrypt behaves as expected according to the specification, testing should include the following +scenarios to accurately reason about the behavior of using the Required Encryption Context CMM. + +### Test Decrypt with Identical Encryption Context + +Without using a Required Encryption Context CMM, Decrypt MUST succeed if provided with the identical encryption context +that was used on Encrypt. + +``` +// The string "asdf" as bytes +var asdf := [ 97, 115, 100, 102 ]; +var aesKeyring := GetAesKeyring(); + +// Test supply same encryption context on encrypt and decrypt NO filtering +var encryptionContext := map[ keyA := valA, keyB := valB ]; + +var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := None, + keyring := Some(aesKeyring), + algorithmSuiteId := None, + frameLength := None +)); + +expect encryptOutput.Success?; +var esdkCiphertext := encryptOutput.value.ciphertext; + +var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(aesKeyring), + encryptionContext := Some(encryptionContext) +)); + +expect decryptOutput.Success?; +var cycledPlaintext := decryptOutput.value.plaintext; +expect cycledPlaintext == asdf; +``` + +### Test Filter out Encryption Context on Encrypt AND supply on Decrypt + +On Encrypt will not write one key-value pair to the message header and instead will include it in the header signature. +On Decrypt will supply the Encryption Context pair that was not written but will +NOT use the Required Encryption Context CMM. This operation MUST succeed. + +``` +// The string "asdf" as bytes +var asdf := [ 97, 115, 100, 102 ]; +var aesKeyring := GetAesKeyring(); + +// Test supply same encryption context on encrypt and decrypt NO filtering +var encryptionContext := map[ keyA := valA, keyB := valB ]; +var reproducedEncryptionContext := map[keyA := valA]; +var requiredEncryptionContextKeys := [keyA]; + +var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := aesKeyring + ) +); + +// Create Required EC CMM with the required EC Keys we want +var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) +); + +var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := Some(reqCMM), + keyring := None, + algorithmSuiteId := None, + frameLength := None +)); + +expect encryptOutput.Success?; +var esdkCiphertext := encryptOutput.value.ciphertext; + +var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(rawAesKeyring), + encryptionContext := Some(reproducedEncryptionContext) +)); + +expect decryptOutput.Success?; +var cycledPlaintext := decryptOutput.value.plaintext; +expect cycledPlaintext == asdf; +``` + +### Test Filter out on Encrypt and Supply on Decrypt with Required Encryption Context CMM + +On Encrypt will not write one key-value pair to the message header and instead will include it in the header signature. +On Decrypt will supply the Encryption Context pair that was not written but will +use the Required Encryption Context CMM requiring that the filtered out key on Encrypt is supplied. +This operation MUST succeed. + +``` +// The string "asdf" as bytes +var asdf := [ 97, 115, 100, 102 ]; +var aesKeyring := GetAesKeyring(); + +// Test supply same encryption context on encrypt and decrypt NO filtering +var encryptionContext := map[ keyA := valA, keyB := valB ]; +var reproducedEncryptionContext := map[keyA := valA]; +var requiredEncryptionContextKeys := [keyA]; + +var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := aesKeyring + ) +); + +// Create Required EC CMM with the required EC Keys we want +var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) +); + +var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := Some(reqCMM), + keyring := None, + algorithmSuiteId := None, + frameLength := None +)); + +expect encryptOutput.Success?; +var esdkCiphertext := encryptOutput.value.ciphertext; + +defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := aesKeyring + ) +); + +// Create Required EC CMM with the required EC Keys we want +reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) +); + +var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := Some(reqCMM), + keyring := None, + encryptionContext := Some(reproducedEncryptionContext) +)); + +expect decryptOutput.Success?; +var cycledPlaintext := decryptOutput.value.plaintext; +expect cycledPlaintext == asdf; +``` + +### Test Removing Encryption Context on Encrypt is Backwards Compatible + +On Encrypt will write all encryption context supplied to the message. +On Decrypt will have a Required Encryption Context CMM that requires all encryption context +on Decrypt. + +``` +// The string "asdf" as bytes +var asdf := [ 97, 115, 100, 102 ]; +var aesKeyring := GetAesKeyring(); + +// Test supply same encryption context on encrypt and decrypt NO filtering +var encryptionContext := map[ keyA := valA, keyB := valB ]; +var requiredEncryptionContextKeys := [keyA, keyB]; +var reproducedEncryptionContext := map[ keyA := valA, keyB := valB]; + +var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := aesKeyring + ) +); + +var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := Some(defaultCMM), + keyring := None, + algorithmSuiteId := None, + frameLength := None +)); + +expect encryptOutput.Success?; +var esdkCiphertext := encryptOutput.value.ciphertext; + +// Create Required EC CMM with the required EC Keys we want +var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) +); + +var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := Some(reqCMM), + keyring := None, + encryptionContext := Some(reproducedEncryptionContext) +)); + +expect decryptOutput.Success?; +var cycledPlaintext := decryptOutput.value.plaintext; +expect cycledPlaintext == asdf; +``` + +### Test Different Encryption Context on Decrypt Failure + +Encrypt with and store all encryption context in the message header. +On Decrypt will supply additional encryption context not stored in the header. +This operation MUST fail. + +``` +// The string "asdf" as bytes +var asdf := [ 97, 115, 100, 102 ]; +var aesKeyring := GetAesKeyring(); + +// Test supply same encryption context on encrypt and decrypt NO filtering +var encryptionContext := map[ keyA := valA, keyB := valB ]; +var reproducedAdditionalEncryptionContext := map[ keyC := valC ]; +var requiredEncryptionContextKeys := [keyA, keyB]; + +var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := aesKeyring + ) +); + +var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := Some(defaultCMM), + keyring := None, + algorithmSuiteId := None, + frameLength := None +)); + +expect encryptOutput.Success?; +var esdkCiphertext := encryptOutput.value.ciphertext; + +// Create Required EC CMM with the required EC Keys we want +var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) +); + +var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := Some(reqCMM), + keyring := None, + encryptionContext := Some(reproducedAdditionalEncryptionContext) +)); + +expect decryptOutput.Failure?; +``` + +### Test MisMatched Encryption Context on Decrypt Failure + +Encrypt with and store all encryption context in the message header. +On Decrypt will supply mismatched encryption context that is stored in the header. +This operation MUST fail. + +``` +// The string "asdf" as bytes +var asdf := [ 97, 115, 100, 102 ]; +var aesKeyring := GetAesKeyring(); + +// Test supply same encryption context on encrypt and decrypt NO filtering +var encryptionContext := map[ keyA := valA, keyB := valB ]; +var reproducedAdditionalEncryptionContext := map[ keyA := valB, keyB := valA ]; +var requiredEncryptionContextKeys := [keyA, keyB]; + +var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := aesKeyring + ) +); + +var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := Some(defaultCMM), + keyring := None, + algorithmSuiteId := None, + frameLength := None +)); + +expect encryptOutput.Success?; +var esdkCiphertext := encryptOutput.value.ciphertext; + +// Create Required EC CMM with the required EC Keys we want +var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) +); + +var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := Some(reqCMM), + keyring := None, + encryptionContext := Some(reproducedAdditionalEncryptionContext) +)); + +expect decryptOutput.Failure?; +``` + +### Test filter out Encryption Context and DO NOT supply on Decrypt + +Encrypt will NOT store all encryption context. +Decrypt will NOT supply reproduced encryption context. +This operation MUST fail. + +``` +// The string "asdf" as bytes +var asdf := [ 97, 115, 100, 102 ]; +var aesKeyring := GetAesKeyring(); + +// Test supply same encryption context on encrypt and decrypt NO filtering +var encryptionContext := map[ keyA := valA, keyB := valB ]; +var requiredEncryptionContextKeys := [keyA, keyB]; + +var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := aesKeyring + ) +); + +// Create Required EC CMM with the required EC Keys we want +var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) +); + +var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := Some(reqCMM), + keyring := None, + algorithmSuiteId := None, + frameLength := None +)); + +expect encryptOutput.Success?; +var esdkCiphertext := encryptOutput.value.ciphertext; + +var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := Some(defaultCMM), + keyring := None, + encryptionContext := None +)); + +expect decryptOutput.Failure?; +``` + +### Test filter out Encryption Context and supply mis-matched Encryption Context on Decrypt + +Encrypt will not store all encryption context. +Decrypt will supply the correct key but a different value. +This operation MUST fail. + +``` +// The string "asdf" as bytes +var asdf := [ 97, 115, 100, 102 ]; +var aesKeyring := GetAesKeyring(); + +// Test supply same encryption context on encrypt and decrypt NO filtering +var encryptionContext := map[ keyA := valA, keyB := valB ]; +var requiredEncryptionContextKeys := [keyA, keyB]; +var mismatchedReproducedEncryptionContext := map[keyA := valB, keyB := valA]; + +var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := aesKeyring + ) +); + +// Create Required EC CMM with the required EC Keys we want +var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) +); + +var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := Some(reqCMM), + keyring := None, + algorithmSuiteId := None, + frameLength := None +)); + +expect encryptOutput.Success?; +var esdkCiphertext := encryptOutput.value.ciphertext; + +var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(aesKeyring) + encryptionContext := Some(mismatchedReproducedEncryptionContext) +)); + +expect decryptOutput.Failure?; +``` + +### Test filter out Encryption Context and supply with missing required value on Decrypt + +Encrypt will not store all encryption context. +Decrypt will supply the key-value that is stored but not the one that was dropped. +This operation MUST fail. + +``` +// The string "asdf" as bytes +var asdf := [ 97, 115, 100, 102 ]; +var aesKeyring := GetAesKeyring(); + +// Test supply same encryption context on encrypt and decrypt NO filtering +var encryptionContext := map[ keyA := valA, keyB := valB ]; +var requiredEncryptionContextKeys := [keyA]; +var droppedRequiredKeyEncryptionContext := map[ keyB := valB ]; + +var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := aesKeyring + ) +); + +// Create Required EC CMM with the required EC Keys we want +var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) +); + +var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := Some(reqCMM), + keyring := None, + algorithmSuiteId := None, + frameLength := None +)); + +expect encryptOutput.Success?; +var esdkCiphertext := encryptOutput.value.ciphertext; + +var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(aesKeyring) + encryptionContext := Some(droppedRequiredKeyEncryptionContext) +)); + +expect decryptOutput.Failure?; +``` diff --git a/changes/2023-09-26_encryption-context-decrypt/change.md b/changes/2023-09-26_encryption-context-decrypt/change.md new file mode 100644 index 00000000..0e410aa4 --- /dev/null +++ b/changes/2023-09-26_encryption-context-decrypt/change.md @@ -0,0 +1,52 @@ +[//]: # "Copyright Amazon.com Inc. or its affiliates. All Rights Reserved." +[//]: # "SPDX-License-Identifier: CC-BY-SA-4.0" + +# Check Required Encryption Context Keys exist in Encryption Context in Decrypt and the values match in the stored Encryption Context in the message header + +## Affected Implementations + +This serves as a reference for all implementations that this change affects. + +| Language | Repository | +| ---------- | -------------------------------------------------------------------------------------------------------------- | +| Java | [aws-encryption-sdk-java](https://github.com/aws/aws-encryption-sdk-java) | +| .NET | [aws-encryption-sdk-net](https://github.com/aws/aws-encryption-sdk-dafny/tree/mainline/aws-encryption-sdk-net) | +| Python | [aws-encryption-sdk-python](https://github.com/aws/aws-encryption-sdk-python) | +| CLI | [aws-encryption-sdk-cli](https://github.com/aws/aws-encryption-sdk-cli) | +| C | [aws-encryption-sdk-c](https://github.com/aws/aws-encryption-sdk-c) | +| Javascript | [aws-encryption-sdk-javascript](https://github.com/aws/aws-encryption-sdk-javascript) | + +## Definitions + +### Conventions used in this document + +The key words +"MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", +"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" +in this document are to be interpreted as described in +[RFC 2119](https://tools.ietf.org/html/rfc2119). + +## Summary + +The [Decrypt](../../client-apis/decrypt.md) API does not specify +how it should deal with required encryption context keys it receives from the call to the +Cryptographic Materials Manager, the encryption context it optionally takes in, and the stored +encryption context on the message header. + +Decrypt MUST verify that if the keys in the required encryption context keys exist in the reproduced encryption context +AND they are stored in the message header, they MUST have the same value as the reproduced encryption context supplied. + +### `decrypt` API required encryption context keys and stored encryption context verification + +Before verifying the message header, Decrypt MUST verify +that if a [required encryption context key](../../framework/structures.md#required-encryption-context-keys) +exists in the message [header's AAD](../../data-format/message-header.md#aad) +the value in the [decryption materials' encryption context](../../framework/structures.md#decryption-materials) +MUST match what is store in the message header. + +This verifies that the reproduced encryption context is used to decrypt the message and +NOT some key-value pair that the underlying CMM MAY have modified. + +If required keys exist, match stored encryption context, AND decryption succeeds +Decrypt MUST return both the Encryption Context stored in the header AND the +encryption context to only authenticate. diff --git a/client-apis/decrypt.md b/client-apis/decrypt.md index 40c1096e..15cd1b58 100644 --- a/client-apis/decrypt.md +++ b/client-apis/decrypt.md @@ -9,6 +9,8 @@ ### Changelog +- 0.6.0 [Required Encryption Context Keys exist in message header, their values MUST match](../changes/2023-09-26_encryption-context-decrypt/change.md) + - 0.5.0 - [Encryption context values that are authenticated but not stored with the encrypted message](../changes/2022-11-14_encryption_context_on_decrypt/proposal.md) @@ -161,7 +163,8 @@ that implementation SHOULD NOT provide an API that allows the caller to stream t ### Encryption Context The [encryption context](../framework/structures.md#encryption-context) that is used as -additional authenticated data during the decryption of the input [encrypted message](#encrypted-message). +additional authenticated data during the decryption of the input [encrypted message](#encrypted-message) and +the [encryption context for authentication only](../client-apis/encrypt.md#encryption-context-not-stored-in-the-message) if available. This output MAY be satisfied by outputting a [parsed header](#parsed-header) containing this value. @@ -184,6 +187,7 @@ The Decrypt operation is divided into several distinct steps: - [Parse the header](#parse-the-header) - [Get the decryption materials](#get-the-decryption-materials) +- [Check required keys in header](#check-required-keys-in-header) - [Verify the header](#verify-the-header) - [Decrypt the message body](#decrypt-the-message-body) - [Verify the signature](#verify-the-signature) @@ -281,6 +285,17 @@ This document refers to the output of the key derivation algorithm as the derive Note that if the key derivation algorithm is the [identity KDF](../framework/algorithm-suites.md#identity-kdf), then the derived data key is the same as the plaintext data key. +### Check required keys in header + +Once the decryption materials request to a CMM succeeds +Decrypt MUST verify the following: + +- If a [required encryption context key](../framework/structures.md#required-encryption-context-keys) in + the decryption materials' response exists in the [message header body](../data-format/message-header.md#header-body) + the value in the decryption materials' encryption context MUST equal the value stored in the message header body. + +If this encryption context verification fails, this operation MUST immediately halt and fail. + ### Verify the header Once a valid message header is deserialized and decryption materials are available, From f164be5640ece3aaaec52f731f3a119d2de67e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Corella?= <39066999+josecorella@users.noreply.github.com> Date: Mon, 2 Oct 2023 14:05:25 -0700 Subject: [PATCH 2/8] Apply suggestions from code review Co-authored-by: lavaleri <49660121+lavaleri@users.noreply.github.com> --- .../background.md | 10 +++++----- client-apis/decrypt.md | 5 +++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/changes/2023-09-26_encryption-context-decrypt/background.md b/changes/2023-09-26_encryption-context-decrypt/background.md index 3df9beb8..9e2595ff 100644 --- a/changes/2023-09-26_encryption-context-decrypt/background.md +++ b/changes/2023-09-26_encryption-context-decrypt/background.md @@ -22,13 +22,13 @@ This requirement may be satisfied by returning the parsed header that contains t With the addition of the [required encryption context cmm](../../framework/required-encryption-context-cmm.md), the encrypt API is able to filter out encryption context key-value pairs that -are not stored but instead authenticated. +are not stored on the message. -Currently, on decrypt takes in optional encryption context. -This optional encryption context is used as encryption context for authentication only. +Currently, Decrypt takes in optional encryption context. +This optional encryption context is not stored in the message header, but is still authenticated. -The Required Encryption Context CMM can modify the encryption context on decrypt. -This results in values that are not authenticated against the message or the plaintext data key. +However, the CMM's DecryptMaterials is allowed to modify the encryption context on decrypt. +A poorly designed CMM could theoretically return materials with an "incorrect" encryption context that contradicts the encryption context in the header of the message. It MUST be required that the decryption materials obtained from the underlying CMM's MUST contain all configured encryption context keys in its encryption context and the values MUST remain diff --git a/client-apis/decrypt.md b/client-apis/decrypt.md index 15cd1b58..7d3e10cb 100644 --- a/client-apis/decrypt.md +++ b/client-apis/decrypt.md @@ -163,8 +163,9 @@ that implementation SHOULD NOT provide an API that allows the caller to stream t ### Encryption Context The [encryption context](../framework/structures.md#encryption-context) that is used as -additional authenticated data during the decryption of the input [encrypted message](#encrypted-message) and -the [encryption context for authentication only](../client-apis/encrypt.md#encryption-context-not-stored-in-the-message) if available. +additional authenticated data during the decryption of the input [encrypted message](#encrypted-message). +Specifically, the union of the encryption context serialized into the message header and +the encryption context for authentication only, if available. This output MAY be satisfied by outputting a [parsed header](#parsed-header) containing this value. From 9b8233adea7d8b38b2e280abfbc759d488c74524 Mon Sep 17 00:00:00 2001 From: Jose Corella Date: Mon, 2 Oct 2023 15:49:04 -0700 Subject: [PATCH 3/8] update --- .../background.md | 76 +++++++++++++++---- .../change.md | 7 +- client-apis/decrypt.md | 2 +- 3 files changed, 67 insertions(+), 18 deletions(-) diff --git a/changes/2023-09-26_encryption-context-decrypt/background.md b/changes/2023-09-26_encryption-context-decrypt/background.md index 9e2595ff..3fe91083 100644 --- a/changes/2023-09-26_encryption-context-decrypt/background.md +++ b/changes/2023-09-26_encryption-context-decrypt/background.md @@ -34,7 +34,7 @@ It MUST be required that the decryption materials obtained from the underlying C contain all configured encryption context keys in its encryption context and the values MUST remain unchanged. -The Decrypt API MUST return the encryption context stored in the header and the encryption +The Decrypt API MUST return the set of the union of the encryption context stored in the header and the encryption context used for authentication only. ### What changes to the existing Required Encryption Context CMM are required? @@ -43,8 +43,8 @@ None ### API changes -If required encryption context keys match any keys stored in the message header, -their values MUST match. Otherwise old messages are not compatible with the required encryption context CMM. +If any required encryption context keys from the CMM's `DecryptionMaterials` response +match any keys stored in the message header, their values MUST match. ``` forall k <- decryptionMaterials.requiredEncryptionContextKeys @@ -341,8 +341,7 @@ var aesKeyring := GetAesKeyring(); // Test supply same encryption context on encrypt and decrypt NO filtering var encryptionContext := map[ keyA := valA, keyB := valB ]; -var reproducedAdditionalEncryptionContext := map[ keyA := valB, keyB := valA ]; -var requiredEncryptionContextKeys := [keyA, keyB]; +var reproducedAdditionalEncryptionContext := map[ keyA := valA, keyB := valB, keyC := valC ]; var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( mplTypes.CreateDefaultCryptographicMaterialsManagerInput( @@ -362,19 +361,10 @@ var encryptOutput := esdk.Encrypt(Types.EncryptInput( expect encryptOutput.Success?; var esdkCiphertext := encryptOutput.value.ciphertext; -// Create Required EC CMM with the required EC Keys we want -var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) -); - var decryptOutput := esdk.Decrypt(Types.DecryptInput( ciphertext := esdkCiphertext, - materialsManager := Some(reqCMM), - keyring := None, + materialsManager := None, + keyring := Some(aesKeyring), encryptionContext := Some(reproducedAdditionalEncryptionContext) )); @@ -538,3 +528,57 @@ var decryptOutput := esdk.Decrypt(Types.DecryptInput( expect decryptOutput.Failure?; ``` + +### Test Encryption Context has an extra pair on Decrypt Failure + +Encrypt will not store all encryption context. +Decrypt will supply the key-value that was dropped but will also include a new key-value that +was not used. +This operation MUST fail. + +``` +// The string "asdf" as bytes +var asdf := [ 97, 115, 100, 102 ]; +var aesKeyring := GetAesKeyring(); + +// Test supply same encryption context on encrypt and decrypt NO filtering +var encryptionContext := map[ keyA := valA, keyB := valB ]; +var requiredEncryptionContextKeys := [keyA]; +var reproducedEncryptionContext := map[ keyA := valA, keyC := valC ]; + +var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := aesKeyring + ) +); + +// Create Required EC CMM with the required EC Keys we want +var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) +); + +var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := Some(reqCMM), + keyring := None, + algorithmSuiteId := None, + frameLength := None +)); + +expect encryptOutput.Success?; +var esdkCiphertext := encryptOutput.value.ciphertext; + +var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(aesKeyring) + encryptionContext := Some(reproducedEncryptionContext) +)); + +expect decryptOutput.Failure?; +``` diff --git a/changes/2023-09-26_encryption-context-decrypt/change.md b/changes/2023-09-26_encryption-context-decrypt/change.md index 0e410aa4..79076bf4 100644 --- a/changes/2023-09-26_encryption-context-decrypt/change.md +++ b/changes/2023-09-26_encryption-context-decrypt/change.md @@ -48,5 +48,10 @@ This verifies that the reproduced encryption context is used to decrypt the mess NOT some key-value pair that the underlying CMM MAY have modified. If required keys exist, match stored encryption context, AND decryption succeeds -Decrypt MUST return both the Encryption Context stored in the header AND the +Decrypt MUST return the Encryption Context stored in the header AND the encryption context to only authenticate. +The encryption context to only authenticate MUST be the [encryption context](../framework/structures.md#encryption-context) +in the [decryption materials](../framework/structures.md#decryption-materials) +filtered to only contain key value pairs listed in +the [decryption material's](../framework/structures.md#decryption-materials) +[required encryption context keys](../framework/structures.md#required-encryption-context-keys-1). diff --git a/client-apis/decrypt.md b/client-apis/decrypt.md index 7d3e10cb..96feba21 100644 --- a/client-apis/decrypt.md +++ b/client-apis/decrypt.md @@ -164,7 +164,7 @@ that implementation SHOULD NOT provide an API that allows the caller to stream t The [encryption context](../framework/structures.md#encryption-context) that is used as additional authenticated data during the decryption of the input [encrypted message](#encrypted-message). -Specifically, the union of the encryption context serialized into the message header and +Specifically, it MUST be the union of the encryption context serialized into the message header and the encryption context for authentication only, if available. This output MAY be satisfied by outputting a [parsed header](#parsed-header) containing this value. From 7dd4dc8b1ff3542bc9fbe270c4ff48a7abff9e55 Mon Sep 17 00:00:00 2001 From: Jose Corella Date: Wed, 4 Oct 2023 11:07:50 -0700 Subject: [PATCH 4/8] update --- .../background.md | 15 +++++++---- .../change.md | 4 +-- client-apis/decrypt.md | 25 ++++++++----------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/changes/2023-09-26_encryption-context-decrypt/background.md b/changes/2023-09-26_encryption-context-decrypt/background.md index 3fe91083..4afd4f9a 100644 --- a/changes/2023-09-26_encryption-context-decrypt/background.md +++ b/changes/2023-09-26_encryption-context-decrypt/background.md @@ -17,17 +17,19 @@ in this document are to be interpreted as described in ### What kind of Encryption Context should Decrypt return? -Decrypt returns Encryption Context. -This requirement may be satisfied by returning the parsed header that contains this value. - With the addition of the [required encryption context cmm](../../framework/required-encryption-context-cmm.md), the encrypt API is able to filter out encryption context key-value pairs that are not stored on the message. +Decrypt returns Encryption Context. +We were able to satisfy this requirement by returning the parsed message header. +This is no longer adequate as the header may not contain all Encryption Context values used to +authenticate the message. + Currently, Decrypt takes in optional encryption context. -This optional encryption context is not stored in the message header, but is still authenticated. +This optional encryption context MAY not be stored in the message header, but is still authenticated. -However, the CMM's DecryptMaterials is allowed to modify the encryption context on decrypt. +However, the CMMs DecryptMaterials is allowed to modify the encryption context on decrypt. A poorly designed CMM could theoretically return materials with an "incorrect" encryption context that contradicts the encryption context in the header of the message. It MUST be required that the decryption materials obtained from the underlying CMM's MUST @@ -41,6 +43,9 @@ context used for authentication only. None +### What changes to the existing Cryptographic Materials Manager Interface are required? + + ### API changes If any required encryption context keys from the CMM's `DecryptionMaterials` response diff --git a/changes/2023-09-26_encryption-context-decrypt/change.md b/changes/2023-09-26_encryption-context-decrypt/change.md index 79076bf4..14a77598 100644 --- a/changes/2023-09-26_encryption-context-decrypt/change.md +++ b/changes/2023-09-26_encryption-context-decrypt/change.md @@ -33,8 +33,8 @@ how it should deal with required encryption context keys it receives from the ca Cryptographic Materials Manager, the encryption context it optionally takes in, and the stored encryption context on the message header. -Decrypt MUST verify that if the keys in the required encryption context keys exist in the reproduced encryption context -AND they are stored in the message header, they MUST have the same value as the reproduced encryption context supplied. +For required encryption context keys the value in stored in the message header +MUST equal the value in decryption materials encryption context. ### `decrypt` API required encryption context keys and stored encryption context verification diff --git a/client-apis/decrypt.md b/client-apis/decrypt.md index 96feba21..da2cb9d6 100644 --- a/client-apis/decrypt.md +++ b/client-apis/decrypt.md @@ -9,8 +9,6 @@ ### Changelog -- 0.6.0 [Required Encryption Context Keys exist in message header, their values MUST match](../changes/2023-09-26_encryption-context-decrypt/change.md) - - 0.5.0 - [Encryption context values that are authenticated but not stored with the encrypted message](../changes/2022-11-14_encryption_context_on_decrypt/proposal.md) @@ -165,7 +163,7 @@ that implementation SHOULD NOT provide an API that allows the caller to stream t The [encryption context](../framework/structures.md#encryption-context) that is used as additional authenticated data during the decryption of the input [encrypted message](#encrypted-message). Specifically, it MUST be the union of the encryption context serialized into the message header and -the encryption context for authentication only, if available. +the [encryption context for authentication only](#encryption-context-to-only-authenticate), if available. This output MAY be satisfied by outputting a [parsed header](#parsed-header) containing this value. @@ -188,7 +186,6 @@ The Decrypt operation is divided into several distinct steps: - [Parse the header](#parse-the-header) - [Get the decryption materials](#get-the-decryption-materials) -- [Check required keys in header](#check-required-keys-in-header) - [Verify the header](#verify-the-header) - [Decrypt the message body](#decrypt-the-message-body) - [Verify the signature](#verify-the-signature) @@ -286,17 +283,6 @@ This document refers to the output of the key derivation algorithm as the derive Note that if the key derivation algorithm is the [identity KDF](../framework/algorithm-suites.md#identity-kdf), then the derived data key is the same as the plaintext data key. -### Check required keys in header - -Once the decryption materials request to a CMM succeeds -Decrypt MUST verify the following: - -- If a [required encryption context key](../framework/structures.md#required-encryption-context-keys) in - the decryption materials' response exists in the [message header body](../data-format/message-header.md#header-body) - the value in the decryption materials' encryption context MUST equal the value stored in the message header body. - -If this encryption context verification fails, this operation MUST immediately halt and fail. - ### Verify the header Once a valid message header is deserialized and decryption materials are available, @@ -443,6 +429,15 @@ Note that the message header and message body MAY have already been input during If this verification is not successful, this operation MUST immediately halt and fail. +##### Encryption Context to Only Authenticate + +The encryption context to only authenticate MUST be the [encryption context](../framework/structures.md#encryption-context) +in the [decryption materials](../framework/structures.md#decryption-materials) +filtered to only contain key value pairs listed in +the [decryption material's](../framework/structures.md#decryption-materials) +[required encryption context keys](../framework/structures.md#required-encryption-context-keys-1) +serialized according to the [encryption context serialization specification](../framework/structures.md#serialization). + ## Security Considerations If this operation is [streaming](streaming.md) output to the caller From 2d83dfcf8efeff3ed06b5a0a98e5bbcc51168076 Mon Sep 17 00:00:00 2001 From: Jose Corella Date: Wed, 4 Oct 2023 12:35:56 -0700 Subject: [PATCH 5/8] format --- changes/2023-09-26_encryption-context-decrypt/background.md | 1 - 1 file changed, 1 deletion(-) diff --git a/changes/2023-09-26_encryption-context-decrypt/background.md b/changes/2023-09-26_encryption-context-decrypt/background.md index 4afd4f9a..4ebba6c9 100644 --- a/changes/2023-09-26_encryption-context-decrypt/background.md +++ b/changes/2023-09-26_encryption-context-decrypt/background.md @@ -45,7 +45,6 @@ None ### What changes to the existing Cryptographic Materials Manager Interface are required? - ### API changes If any required encryption context keys from the CMM's `DecryptionMaterials` response From d257aeeefd7b86c7fb632ee78fd9f785dd70097c Mon Sep 17 00:00:00 2001 From: Jose Corella Date: Thu, 5 Oct 2023 11:39:22 -0700 Subject: [PATCH 6/8] update spec --- .../background.md | 656 +++--------------- .../change.md | 38 +- 2 files changed, 130 insertions(+), 564 deletions(-) diff --git a/changes/2023-09-26_encryption-context-decrypt/background.md b/changes/2023-09-26_encryption-context-decrypt/background.md index 4ebba6c9..64b4d546 100644 --- a/changes/2023-09-26_encryption-context-decrypt/background.md +++ b/changes/2023-09-26_encryption-context-decrypt/background.md @@ -18,26 +18,37 @@ in this document are to be interpreted as described in ### What kind of Encryption Context should Decrypt return? With the addition of the [required encryption context cmm](../../framework/required-encryption-context-cmm.md), -the encrypt API is able to filter out encryption context key-value pairs that +the `encrypt` API is able to filter out encryption context key-value pairs that are not stored on the message. -Decrypt returns Encryption Context. +`decrypt` returns Encryption Context. We were able to satisfy this requirement by returning the parsed message header. This is no longer adequate as the header may not contain all Encryption Context values used to authenticate the message. -Currently, Decrypt takes in optional encryption context. +Currently, `decrypt` takes in optional encryption context. This optional encryption context MAY not be stored in the message header, but is still authenticated. -However, the CMMs DecryptMaterials is allowed to modify the encryption context on decrypt. -A poorly designed CMM could theoretically return materials with an "incorrect" encryption context that contradicts the encryption context in the header of the message. +If `decrypt` uses [encryption context to only authenticate](../../client-apis/decrypt.md#encryption-context-to-only-authenticate) +to successfully decrypt a message, then the encryption context output +MUST be the union of the encryption context serialized into the message header and +the [encryption context for authentication only](#encryption-context-to-only-authenticate), if available. + + +### Can you construct message that stores different encryption context than the encryption context returned by a CMM? + +None of the built-in implementations of the [CMM interface](../../framework/cmm-interface.md) +modify the encryption context on DecryptMaterials. -It MUST be required that the decryption materials obtained from the underlying CMM's MUST -contain all configured encryption context keys in its encryption context and the values MUST remain -unchanged. +However, the CMMs DecryptMaterials is allowed to modify the encryption context on decrypt. +A poorly designed CMM could theoretically return materials with an "incorrect" encryption context +that contradicts the encryption context in the header of the message. -The Decrypt API MUST return the set of the union of the encryption context stored in the header and the encryption -context used for authentication only. +The `decrypt` API SHOULD not check if the encryption context that was stored on the message matches +what it receives from the CMMs DecryptMaterials because the current implementation +of the `encrypt` API used with the built-in CMMs is not able to write a message +that on `decrypt` the CMM returns "incorrect" encryption context that contradicts +the encryption context stored in the header of the message. ### What changes to the existing Required Encryption Context CMM are required? @@ -45,544 +56,99 @@ None ### What changes to the existing Cryptographic Materials Manager Interface are required? -### API changes - -If any required encryption context keys from the CMM's `DecryptionMaterials` response -match any keys stored in the message header, their values MUST match. - -``` -forall k <- decryptionMaterials.requiredEncryptionContextKeys - | k in headerEncryptionContext - :: decryptionMaterials[k] == headerEncryptionContext[k] -``` +None ## Testing In order to test that decrypt behaves as expected according to the specification, testing should include the following scenarios to accurately reason about the behavior of using the Required Encryption Context CMM. -### Test Decrypt with Identical Encryption Context - -Without using a Required Encryption Context CMM, Decrypt MUST succeed if provided with the identical encryption context -that was used on Encrypt. - -``` -// The string "asdf" as bytes -var asdf := [ 97, 115, 100, 102 ]; -var aesKeyring := GetAesKeyring(); - -// Test supply same encryption context on encrypt and decrypt NO filtering -var encryptionContext := map[ keyA := valA, keyB := valB ]; - -var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := None, - keyring := Some(aesKeyring), - algorithmSuiteId := None, - frameLength := None -)); - -expect encryptOutput.Success?; -var esdkCiphertext := encryptOutput.value.ciphertext; - -var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(aesKeyring), - encryptionContext := Some(encryptionContext) -)); - -expect decryptOutput.Success?; -var cycledPlaintext := decryptOutput.value.plaintext; -expect cycledPlaintext == asdf; -``` - -### Test Filter out Encryption Context on Encrypt AND supply on Decrypt - -On Encrypt will not write one key-value pair to the message header and instead will include it in the header signature. -On Decrypt will supply the Encryption Context pair that was not written but will -NOT use the Required Encryption Context CMM. This operation MUST succeed. - -``` -// The string "asdf" as bytes -var asdf := [ 97, 115, 100, 102 ]; -var aesKeyring := GetAesKeyring(); - -// Test supply same encryption context on encrypt and decrypt NO filtering -var encryptionContext := map[ keyA := valA, keyB := valB ]; -var reproducedEncryptionContext := map[keyA := valA]; -var requiredEncryptionContextKeys := [keyA]; - -var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := aesKeyring - ) -); - -// Create Required EC CMM with the required EC Keys we want -var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) -); - -var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := Some(reqCMM), - keyring := None, - algorithmSuiteId := None, - frameLength := None -)); - -expect encryptOutput.Success?; -var esdkCiphertext := encryptOutput.value.ciphertext; - -var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(rawAesKeyring), - encryptionContext := Some(reproducedEncryptionContext) -)); - -expect decryptOutput.Success?; -var cycledPlaintext := decryptOutput.value.plaintext; -expect cycledPlaintext == asdf; -``` - -### Test Filter out on Encrypt and Supply on Decrypt with Required Encryption Context CMM - -On Encrypt will not write one key-value pair to the message header and instead will include it in the header signature. -On Decrypt will supply the Encryption Context pair that was not written but will -use the Required Encryption Context CMM requiring that the filtered out key on Encrypt is supplied. -This operation MUST succeed. - -``` -// The string "asdf" as bytes -var asdf := [ 97, 115, 100, 102 ]; -var aesKeyring := GetAesKeyring(); - -// Test supply same encryption context on encrypt and decrypt NO filtering -var encryptionContext := map[ keyA := valA, keyB := valB ]; -var reproducedEncryptionContext := map[keyA := valA]; -var requiredEncryptionContextKeys := [keyA]; - -var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := aesKeyring - ) -); - -// Create Required EC CMM with the required EC Keys we want -var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) -); - -var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := Some(reqCMM), - keyring := None, - algorithmSuiteId := None, - frameLength := None -)); - -expect encryptOutput.Success?; -var esdkCiphertext := encryptOutput.value.ciphertext; - -defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := aesKeyring - ) -); - -// Create Required EC CMM with the required EC Keys we want -reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) -); - -var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := Some(reqCMM), - keyring := None, - encryptionContext := Some(reproducedEncryptionContext) -)); - -expect decryptOutput.Success?; -var cycledPlaintext := decryptOutput.value.plaintext; -expect cycledPlaintext == asdf; -``` - -### Test Removing Encryption Context on Encrypt is Backwards Compatible - -On Encrypt will write all encryption context supplied to the message. -On Decrypt will have a Required Encryption Context CMM that requires all encryption context -on Decrypt. - -``` -// The string "asdf" as bytes -var asdf := [ 97, 115, 100, 102 ]; -var aesKeyring := GetAesKeyring(); - -// Test supply same encryption context on encrypt and decrypt NO filtering -var encryptionContext := map[ keyA := valA, keyB := valB ]; -var requiredEncryptionContextKeys := [keyA, keyB]; -var reproducedEncryptionContext := map[ keyA := valA, keyB := valB]; - -var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := aesKeyring - ) -); - -var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := Some(defaultCMM), - keyring := None, - algorithmSuiteId := None, - frameLength := None -)); - -expect encryptOutput.Success?; -var esdkCiphertext := encryptOutput.value.ciphertext; - -// Create Required EC CMM with the required EC Keys we want -var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) -); - -var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := Some(reqCMM), - keyring := None, - encryptionContext := Some(reproducedEncryptionContext) -)); - -expect decryptOutput.Success?; -var cycledPlaintext := decryptOutput.value.plaintext; -expect cycledPlaintext == asdf; -``` - -### Test Different Encryption Context on Decrypt Failure - -Encrypt with and store all encryption context in the message header. -On Decrypt will supply additional encryption context not stored in the header. -This operation MUST fail. - -``` -// The string "asdf" as bytes -var asdf := [ 97, 115, 100, 102 ]; -var aesKeyring := GetAesKeyring(); - -// Test supply same encryption context on encrypt and decrypt NO filtering -var encryptionContext := map[ keyA := valA, keyB := valB ]; -var reproducedAdditionalEncryptionContext := map[ keyC := valC ]; -var requiredEncryptionContextKeys := [keyA, keyB]; - -var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := aesKeyring - ) -); - -var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := Some(defaultCMM), - keyring := None, - algorithmSuiteId := None, - frameLength := None -)); - -expect encryptOutput.Success?; -var esdkCiphertext := encryptOutput.value.ciphertext; - -// Create Required EC CMM with the required EC Keys we want -var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) -); - -var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := Some(reqCMM), - keyring := None, - encryptionContext := Some(reproducedAdditionalEncryptionContext) -)); - -expect decryptOutput.Failure?; -``` - -### Test MisMatched Encryption Context on Decrypt Failure - -Encrypt with and store all encryption context in the message header. -On Decrypt will supply mismatched encryption context that is stored in the header. -This operation MUST fail. - -``` -// The string "asdf" as bytes -var asdf := [ 97, 115, 100, 102 ]; -var aesKeyring := GetAesKeyring(); - -// Test supply same encryption context on encrypt and decrypt NO filtering -var encryptionContext := map[ keyA := valA, keyB := valB ]; -var reproducedAdditionalEncryptionContext := map[ keyA := valA, keyB := valB, keyC := valC ]; - -var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := aesKeyring - ) -); - -var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := Some(defaultCMM), - keyring := None, - algorithmSuiteId := None, - frameLength := None -)); - -expect encryptOutput.Success?; -var esdkCiphertext := encryptOutput.value.ciphertext; - -var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(aesKeyring), - encryptionContext := Some(reproducedAdditionalEncryptionContext) -)); - -expect decryptOutput.Failure?; -``` - -### Test filter out Encryption Context and DO NOT supply on Decrypt - -Encrypt will NOT store all encryption context. -Decrypt will NOT supply reproduced encryption context. -This operation MUST fail. - -``` -// The string "asdf" as bytes -var asdf := [ 97, 115, 100, 102 ]; -var aesKeyring := GetAesKeyring(); - -// Test supply same encryption context on encrypt and decrypt NO filtering -var encryptionContext := map[ keyA := valA, keyB := valB ]; -var requiredEncryptionContextKeys := [keyA, keyB]; - -var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := aesKeyring - ) -); - -// Create Required EC CMM with the required EC Keys we want -var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) -); - -var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := Some(reqCMM), - keyring := None, - algorithmSuiteId := None, - frameLength := None -)); - -expect encryptOutput.Success?; -var esdkCiphertext := encryptOutput.value.ciphertext; - -var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := Some(defaultCMM), - keyring := None, - encryptionContext := None -)); - -expect decryptOutput.Failure?; -``` - -### Test filter out Encryption Context and supply mis-matched Encryption Context on Decrypt - -Encrypt will not store all encryption context. -Decrypt will supply the correct key but a different value. -This operation MUST fail. - -``` -// The string "asdf" as bytes -var asdf := [ 97, 115, 100, 102 ]; -var aesKeyring := GetAesKeyring(); - -// Test supply same encryption context on encrypt and decrypt NO filtering -var encryptionContext := map[ keyA := valA, keyB := valB ]; -var requiredEncryptionContextKeys := [keyA, keyB]; -var mismatchedReproducedEncryptionContext := map[keyA := valB, keyB := valA]; - -var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := aesKeyring - ) -); - -// Create Required EC CMM with the required EC Keys we want -var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) -); - -var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := Some(reqCMM), - keyring := None, - algorithmSuiteId := None, - frameLength := None -)); - -expect encryptOutput.Success?; -var esdkCiphertext := encryptOutput.value.ciphertext; - -var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(aesKeyring) - encryptionContext := Some(mismatchedReproducedEncryptionContext) -)); - -expect decryptOutput.Failure?; -``` - -### Test filter out Encryption Context and supply with missing required value on Decrypt - -Encrypt will not store all encryption context. -Decrypt will supply the key-value that is stored but not the one that was dropped. -This operation MUST fail. - -``` -// The string "asdf" as bytes -var asdf := [ 97, 115, 100, 102 ]; -var aesKeyring := GetAesKeyring(); - -// Test supply same encryption context on encrypt and decrypt NO filtering -var encryptionContext := map[ keyA := valA, keyB := valB ]; -var requiredEncryptionContextKeys := [keyA]; -var droppedRequiredKeyEncryptionContext := map[ keyB := valB ]; - -var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := aesKeyring - ) -); - -// Create Required EC CMM with the required EC Keys we want -var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) -); - -var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := Some(reqCMM), - keyring := None, - algorithmSuiteId := None, - frameLength := None -)); - -expect encryptOutput.Success?; -var esdkCiphertext := encryptOutput.value.ciphertext; - -var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(aesKeyring) - encryptionContext := Some(droppedRequiredKeyEncryptionContext) -)); - -expect decryptOutput.Failure?; -``` - -### Test Encryption Context has an extra pair on Decrypt Failure - -Encrypt will not store all encryption context. -Decrypt will supply the key-value that was dropped but will also include a new key-value that -was not used. -This operation MUST fail. - -``` -// The string "asdf" as bytes -var asdf := [ 97, 115, 100, 102 ]; -var aesKeyring := GetAesKeyring(); - -// Test supply same encryption context on encrypt and decrypt NO filtering -var encryptionContext := map[ keyA := valA, keyB := valB ]; -var requiredEncryptionContextKeys := [keyA]; -var reproducedEncryptionContext := map[ keyA := valA, keyC := valC ]; - -var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := aesKeyring - ) -); - -// Create Required EC CMM with the required EC Keys we want -var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) -); - -var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := Some(reqCMM), - keyring := None, - algorithmSuiteId := None, - frameLength := None -)); - -expect encryptOutput.Success?; -var esdkCiphertext := encryptOutput.value.ciphertext; - -var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(aesKeyring) - encryptionContext := Some(reproducedEncryptionContext) -)); - -expect decryptOutput.Failure?; -``` +To test the new encryption context (EC) features +the following dimensions exists: + +* Stored EC -- EC stored in the header +* Not stored EC -- EC authenticated to the header but not stored +* CMM Material EC -- EC on the decryption material +* Required keys -- Keys for the EC that MAY be only authenticated +* Reproduced EC -- EC passed on decrypt + +Given the EC `{ a: a, b: b }` +we break this into the following interesting options: + +Stored EC/Not Stored EC +* `{a: a, b: b}` / `{}` +* `{a: a}` / `{b: b}` +* `{}` / `{a: a, b: b}` + +CMM Material/Required Keys +* `{a: a, b: b}` / `{}` +* `{a: a, b: b}` / `{a}` +* `{a: a, b: b}` / `{a,b}` +* `{a: a, b: c}` / `{a}` +* `{a: a, b: b}` / `{c}` + +Reproduced EC +* `{}` +* `{ a: a }` +* `{ b: b }` +* `{ a: a, b: b }` +* `{ a: c }` +* `{ b: c }` +* `{ a: c, b: b }` +* `{ a: c, b: c }` +* `{ c: c }` +* `{ a: a, c: c }` +* `{ b: b, c: c}` +* `{ a: a, b: b, c: c }` + + +### Message: `{a: a, b: b}` / `{}` + +CMM Material/Required Keys →
Reproduced EC ↓ | `{a: a, b: b}` / `{}` | `{a: a, b: b}` / `{a}`| `{a: a, b: b}` / `{a,b}`| `{a: a, b: c}` / `{a}` | `{a: a, b: b}` / `{c}` | +------------------------------------------------------------|-----------------------|------------------------|--------------------------|------------------------|------------------------| +`{}` | pass | | | | | +`{ a: a }` | | | | | | +`{ b: b }` | | | | | | +`{ a: a, b: b }` | | | | | | +`{ a: c }` | | | | | | +`{ b: c }` | | | | | | +`{ a: c, b: b }` | | | | | | +`{ a: c, b: c }` | | | | | | +`{ c: c }` | | | | | | +`{ a: a, c: c }` | | | | | | +`{ b: b, c: c}` | | | | | | +`{ a: a, b: b, c: c }` | | | | | | + +### Message: `{a: a}` / `{b: b}` + +CMM Material/Required Keys →
Reproduced EC ↓ | `{a: a, b: b}` / `{}` | `{a: a, b: b}` / `{a}`| `{a: a, b: b}` / `{a,b}`| `{a: a, b: c}` / `{a}` | `{a: a, b: b}` / `{c}` | +------------------------------------------------------------|-----------------------|------------------------|--------------------------|------------------------|------------------------| +`{}` | | | | | | +`{ a: a }` | | | | | | +`{ b: b }` | | | | | | +`{ a: a, b: b }` | | | | | | +`{ a: c }` | | | | | | +`{ b: c }` | | | | | | +`{ a: c, b: b }` | | | | | | +`{ a: c, b: c }` | | | | | | +`{ c: c }` | | | | | | +`{ a: a, c: c }` | | | | | | +`{ b: b, c: c}` | | | | | | +`{ a: a, b: b, c: c }` | | | | | | + +### Message:`{}` / `{a: a, b: b}` + +CMM Material/Required Keys →
Reproduced EC ↓ | `{a: a, b: b}` / `{}` | `{a: a, b: b}` / `{a}`| `{a: a, b: b}` / `{a,b}`| `{a: a, b: c}` / `{a}` | `{a: a, b: b}` / `{c}` | +------------------------------------------------------------|-----------------------|------------------------|--------------------------|------------------------|------------------------| +`{}` | | | | | | +`{ a: a }` | | | | | | +`{ b: b }` | | | | | | +`{ a: a, b: b }` | | | | | | +`{ a: c }` | | | | | | +`{ b: c }` | | | | | | +`{ a: c, b: b }` | | | | | | +`{ a: c, b: c }` | | | | | | +`{ c: c }` | | | | | | +`{ a: a, c: c }` | | | | | | +`{ b: b, c: c}` | | | | | | +`{ a: a, b: b, c: c }` | | | | | | \ No newline at end of file diff --git a/changes/2023-09-26_encryption-context-decrypt/change.md b/changes/2023-09-26_encryption-context-decrypt/change.md index 14a77598..252ccc10 100644 --- a/changes/2023-09-26_encryption-context-decrypt/change.md +++ b/changes/2023-09-26_encryption-context-decrypt/change.md @@ -28,30 +28,30 @@ in this document are to be interpreted as described in ## Summary -The [Decrypt](../../client-apis/decrypt.md) API does not specify -how it should deal with required encryption context keys it receives from the call to the -Cryptographic Materials Manager, the encryption context it optionally takes in, and the stored -encryption context on the message header. +The [Decrypt](../../client-apis/decrypt.md) only requires +that the [encryption context](../../framework/structures.md#encryption-context) that is used as +additional authenticated data during the decryption of the input [encrypted message](#encrypted-message) +is returned. -For required encryption context keys the value in stored in the message header -MUST equal the value in decryption materials encryption context. +Additionally it should also return the +[encryption context used for authentication only](../../client-apis/decrypt.md#encryption-context-to-only-authenticate) +if it used any during the operation. -### `decrypt` API required encryption context keys and stored encryption context verification +### `decrypt` API returns encryption context used as AAD and encryption context used for authentication only +On encrypt the [required encryption context cmm](../../framework/required-encryption-context-cmm.md), +is able to filter out encryption context key-value pairs that are not stored on the message. -Before verifying the message header, Decrypt MUST verify -that if a [required encryption context key](../../framework/structures.md#required-encryption-context-keys) -exists in the message [header's AAD](../../data-format/message-header.md#aad) -the value in the [decryption materials' encryption context](../../framework/structures.md#decryption-materials) -MUST match what is store in the message header. +If the required encryption context CMM filters out encryption context keys from the Additional Authenticated +Data stored on the header, Decrypt MUST use the +[encryption context to only authenticate](../../client-apis/decrypt.md#encryption-context-to-only-authenticate) +to verify the header auth tag. -This verifies that the reproduced encryption context is used to decrypt the message and -NOT some key-value pair that the underlying CMM MAY have modified. - -If required keys exist, match stored encryption context, AND decryption succeeds -Decrypt MUST return the Encryption Context stored in the header AND the -encryption context to only authenticate. The encryption context to only authenticate MUST be the [encryption context](../framework/structures.md#encryption-context) in the [decryption materials](../framework/structures.md#decryption-materials) filtered to only contain key value pairs listed in the [decryption material's](../framework/structures.md#decryption-materials) -[required encryption context keys](../framework/structures.md#required-encryption-context-keys-1). +[required encryption context keys](../framework/structures.md#required-encryption-context-keys-1) +serialized according to the [encryption context serialization specification](../framework/structures.md#serialization). + +`decrypt` MUST return the union of the encryption context serialized into the message header and +the [encryption context for authentication only](#encryption-context-to-only-authenticate), if available. From 656459af3dcae9f97e7c86050a6b2bd452ed48d0 Mon Sep 17 00:00:00 2001 From: Jose Corella Date: Thu, 5 Oct 2023 14:14:58 -0700 Subject: [PATCH 7/8] update matrix --- .../background.md | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/changes/2023-09-26_encryption-context-decrypt/background.md b/changes/2023-09-26_encryption-context-decrypt/background.md index 64b4d546..376ae7a9 100644 --- a/changes/2023-09-26_encryption-context-decrypt/background.md +++ b/changes/2023-09-26_encryption-context-decrypt/background.md @@ -106,49 +106,49 @@ Reproduced EC CMM Material/Required Keys →
Reproduced EC ↓ | `{a: a, b: b}` / `{}` | `{a: a, b: b}` / `{a}`| `{a: a, b: b}` / `{a,b}`| `{a: a, b: c}` / `{a}` | `{a: a, b: b}` / `{c}` | ------------------------------------------------------------|-----------------------|------------------------|--------------------------|------------------------|------------------------| -`{}` | pass | | | | | -`{ a: a }` | | | | | | -`{ b: b }` | | | | | | -`{ a: a, b: b }` | | | | | | -`{ a: c }` | | | | | | -`{ b: c }` | | | | | | -`{ a: c, b: b }` | | | | | | -`{ a: c, b: c }` | | | | | | -`{ c: c }` | | | | | | -`{ a: a, c: c }` | | | | | | -`{ b: b, c: c}` | | | | | | -`{ a: a, b: b, c: c }` | | | | | | +`{}` | pass | fail | fail | fail | fail | +`{ a: a }` | pass | pass | fail | fail | fail | +`{ b: b }` | pass | pass | fail | fail | fail | +`{ a: a, b: b }` | pass | pass | pass | fail | fail | +`{ a: c }` | fail | fail | fail | fail | fail | +`{ b: c }` | fail | fail | fail | fail | fail | +`{ a: c, b: b }` | fail | fail | fail | fail | fail | +`{ a: c, b: c }` | fail | fail | fail | fail | fail | +`{ c: c }` | fail | fail | fail | fail | fail | +`{ a: a, c: c }` | fail | fail | fail | fail | fail | +`{ b: b, c: c}` | fail | fail | fail | fail | fail | +`{ a: a, b: b, c: c }` | fail | fail | fail | fail | fail | ### Message: `{a: a}` / `{b: b}` CMM Material/Required Keys →
Reproduced EC ↓ | `{a: a, b: b}` / `{}` | `{a: a, b: b}` / `{a}`| `{a: a, b: b}` / `{a,b}`| `{a: a, b: c}` / `{a}` | `{a: a, b: b}` / `{c}` | ------------------------------------------------------------|-----------------------|------------------------|--------------------------|------------------------|------------------------| -`{}` | | | | | | -`{ a: a }` | | | | | | -`{ b: b }` | | | | | | -`{ a: a, b: b }` | | | | | | -`{ a: c }` | | | | | | -`{ b: c }` | | | | | | -`{ a: c, b: b }` | | | | | | -`{ a: c, b: c }` | | | | | | -`{ c: c }` | | | | | | -`{ a: a, c: c }` | | | | | | -`{ b: b, c: c}` | | | | | | -`{ a: a, b: b, c: c }` | | | | | | +`{}` | fail | fail | fail | fail | fail | +`{ a: a }` | fail | fail | fail | fail | fail | +`{ b: b }` | pass | fail | fail | fail | fail | +`{ a: a, b: b }` | pass | pass | pass | pass | fail | +`{ a: c }` | fail | fail | fail | fail | fail | +`{ b: c }` | fail | fail | fail | fail | fail | +`{ a: c, b: b }` | fail | fail | fail | fail | fail | +`{ a: c, b: c }` | fail | fail | fail | fail | fail | +`{ c: c }` | fail | fail | fail | fail | fail | +`{ a: a, c: c }` | fail | fail | fail | fail | fail | +`{ b: b, c: c}` | fail | fail | fail | fail | fail | +`{ a: a, b: b, c: c }` | fail | fail | fail | fail | fail | ### Message:`{}` / `{a: a, b: b}` CMM Material/Required Keys →
Reproduced EC ↓ | `{a: a, b: b}` / `{}` | `{a: a, b: b}` / `{a}`| `{a: a, b: b}` / `{a,b}`| `{a: a, b: c}` / `{a}` | `{a: a, b: b}` / `{c}` | ------------------------------------------------------------|-----------------------|------------------------|--------------------------|------------------------|------------------------| -`{}` | | | | | | -`{ a: a }` | | | | | | -`{ b: b }` | | | | | | -`{ a: a, b: b }` | | | | | | -`{ a: c }` | | | | | | -`{ b: c }` | | | | | | -`{ a: c, b: b }` | | | | | | -`{ a: c, b: c }` | | | | | | -`{ c: c }` | | | | | | -`{ a: a, c: c }` | | | | | | -`{ b: b, c: c}` | | | | | | -`{ a: a, b: b, c: c }` | | | | | | \ No newline at end of file +`{}` | fail | fail | fail | fail | fail | +`{ a: a }` | fail | pass | fail | fail | fail | +`{ b: b }` | fail | fail | fail | fail | fail | +`{ a: a, b: b }` | pass | fail | pass | fail | fail | +`{ a: c }` | fail | fail | fail | fail | fail | +`{ b: c }` | fail | fail | fail | fail | fail | +`{ a: c, b: b }` | fail | fail | fail | fail | fail | +`{ a: c, b: c }` | fail | fail | fail | fail | fail | +`{ c: c }` | fail | fail | fail | fail | fail | +`{ a: a, c: c }` | fail | fail | fail | fail | fail | +`{ b: b, c: c}` | fail | fail | fail | fail | fail | +`{ a: a, b: b, c: c }` | fail | fail | fail | fail | fail | \ No newline at end of file From c9eae97dc368d3ad0780c2f21dd26a75721dca65 Mon Sep 17 00:00:00 2001 From: Jose Corella Date: Thu, 5 Oct 2023 14:16:00 -0700 Subject: [PATCH 8/8] format --- .../background.md | 143 +++++++++--------- .../change.md | 5 +- 2 files changed, 75 insertions(+), 73 deletions(-) diff --git a/changes/2023-09-26_encryption-context-decrypt/background.md b/changes/2023-09-26_encryption-context-decrypt/background.md index 376ae7a9..00567eb4 100644 --- a/changes/2023-09-26_encryption-context-decrypt/background.md +++ b/changes/2023-09-26_encryption-context-decrypt/background.md @@ -32,8 +32,7 @@ This optional encryption context MAY not be stored in the message header, but is If `decrypt` uses [encryption context to only authenticate](../../client-apis/decrypt.md#encryption-context-to-only-authenticate) to successfully decrypt a message, then the encryption context output MUST be the union of the encryption context serialized into the message header and -the [encryption context for authentication only](#encryption-context-to-only-authenticate), if available. - +the [encryption context for authentication only](#encryption-context-to-only-authenticate), if available. ### Can you construct message that stores different encryption context than the encryption context returned by a CMM? @@ -46,8 +45,8 @@ that contradicts the encryption context in the header of the message. The `decrypt` API SHOULD not check if the encryption context that was stored on the message matches what it receives from the CMMs DecryptMaterials because the current implementation -of the `encrypt` API used with the built-in CMMs is not able to write a message -that on `decrypt` the CMM returns "incorrect" encryption context that contradicts +of the `encrypt` API used with the built-in CMMs is not able to write a message +that on `decrypt` the CMM returns "incorrect" encryption context that contradicts the encryption context stored in the header of the message. ### What changes to the existing Required Encryption Context CMM are required? @@ -66,89 +65,91 @@ scenarios to accurately reason about the behavior of using the Required Encrypti To test the new encryption context (EC) features the following dimensions exists: -* Stored EC -- EC stored in the header -* Not stored EC -- EC authenticated to the header but not stored -* CMM Material EC -- EC on the decryption material -* Required keys -- Keys for the EC that MAY be only authenticated -* Reproduced EC -- EC passed on decrypt +- Stored EC -- EC stored in the header +- Not stored EC -- EC authenticated to the header but not stored +- CMM Material EC -- EC on the decryption material +- Required keys -- Keys for the EC that MAY be only authenticated +- Reproduced EC -- EC passed on decrypt Given the EC `{ a: a, b: b }` we break this into the following interesting options: Stored EC/Not Stored EC -* `{a: a, b: b}` / `{}` -* `{a: a}` / `{b: b}` -* `{}` / `{a: a, b: b}` + +- `{a: a, b: b}` / `{}` +- `{a: a}` / `{b: b}` +- `{}` / `{a: a, b: b}` CMM Material/Required Keys -* `{a: a, b: b}` / `{}` -* `{a: a, b: b}` / `{a}` -* `{a: a, b: b}` / `{a,b}` -* `{a: a, b: c}` / `{a}` -* `{a: a, b: b}` / `{c}` + +- `{a: a, b: b}` / `{}` +- `{a: a, b: b}` / `{a}` +- `{a: a, b: b}` / `{a,b}` +- `{a: a, b: c}` / `{a}` +- `{a: a, b: b}` / `{c}` Reproduced EC -* `{}` -* `{ a: a }` -* `{ b: b }` -* `{ a: a, b: b }` -* `{ a: c }` -* `{ b: c }` -* `{ a: c, b: b }` -* `{ a: c, b: c }` -* `{ c: c }` -* `{ a: a, c: c }` -* `{ b: b, c: c}` -* `{ a: a, b: b, c: c }` +- `{}` +- `{ a: a }` +- `{ b: b }` +- `{ a: a, b: b }` +- `{ a: c }` +- `{ b: c }` +- `{ a: c, b: b }` +- `{ a: c, b: c }` +- `{ c: c }` +- `{ a: a, c: c }` +- `{ b: b, c: c}` +- `{ a: a, b: b, c: c }` ### Message: `{a: a, b: b}` / `{}` -CMM Material/Required Keys →
Reproduced EC ↓ | `{a: a, b: b}` / `{}` | `{a: a, b: b}` / `{a}`| `{a: a, b: b}` / `{a,b}`| `{a: a, b: c}` / `{a}` | `{a: a, b: b}` / `{c}` | -------------------------------------------------------------|-----------------------|------------------------|--------------------------|------------------------|------------------------| -`{}` | pass | fail | fail | fail | fail | -`{ a: a }` | pass | pass | fail | fail | fail | -`{ b: b }` | pass | pass | fail | fail | fail | -`{ a: a, b: b }` | pass | pass | pass | fail | fail | -`{ a: c }` | fail | fail | fail | fail | fail | -`{ b: c }` | fail | fail | fail | fail | fail | -`{ a: c, b: b }` | fail | fail | fail | fail | fail | -`{ a: c, b: c }` | fail | fail | fail | fail | fail | -`{ c: c }` | fail | fail | fail | fail | fail | -`{ a: a, c: c }` | fail | fail | fail | fail | fail | -`{ b: b, c: c}` | fail | fail | fail | fail | fail | -`{ a: a, b: b, c: c }` | fail | fail | fail | fail | fail | +| CMM Material/Required Keys →
Reproduced EC ↓ | `{a: a, b: b}` / `{}` | `{a: a, b: b}` / `{a}` | `{a: a, b: b}` / `{a,b}` | `{a: a, b: c}` / `{a}` | `{a: a, b: b}` / `{c}` | +| ----------------------------------------------------------- | --------------------- | ---------------------- | ------------------------ | ---------------------- | ---------------------- | +| `{}` | pass | fail | fail | fail | fail | +| `{ a: a }` | pass | pass | fail | fail | fail | +| `{ b: b }` | pass | pass | fail | fail | fail | +| `{ a: a, b: b }` | pass | pass | pass | fail | fail | +| `{ a: c }` | fail | fail | fail | fail | fail | +| `{ b: c }` | fail | fail | fail | fail | fail | +| `{ a: c, b: b }` | fail | fail | fail | fail | fail | +| `{ a: c, b: c }` | fail | fail | fail | fail | fail | +| `{ c: c }` | fail | fail | fail | fail | fail | +| `{ a: a, c: c }` | fail | fail | fail | fail | fail | +| `{ b: b, c: c}` | fail | fail | fail | fail | fail | +| `{ a: a, b: b, c: c }` | fail | fail | fail | fail | fail | ### Message: `{a: a}` / `{b: b}` -CMM Material/Required Keys →
Reproduced EC ↓ | `{a: a, b: b}` / `{}` | `{a: a, b: b}` / `{a}`| `{a: a, b: b}` / `{a,b}`| `{a: a, b: c}` / `{a}` | `{a: a, b: b}` / `{c}` | -------------------------------------------------------------|-----------------------|------------------------|--------------------------|------------------------|------------------------| -`{}` | fail | fail | fail | fail | fail | -`{ a: a }` | fail | fail | fail | fail | fail | -`{ b: b }` | pass | fail | fail | fail | fail | -`{ a: a, b: b }` | pass | pass | pass | pass | fail | -`{ a: c }` | fail | fail | fail | fail | fail | -`{ b: c }` | fail | fail | fail | fail | fail | -`{ a: c, b: b }` | fail | fail | fail | fail | fail | -`{ a: c, b: c }` | fail | fail | fail | fail | fail | -`{ c: c }` | fail | fail | fail | fail | fail | -`{ a: a, c: c }` | fail | fail | fail | fail | fail | -`{ b: b, c: c}` | fail | fail | fail | fail | fail | -`{ a: a, b: b, c: c }` | fail | fail | fail | fail | fail | +| CMM Material/Required Keys →
Reproduced EC ↓ | `{a: a, b: b}` / `{}` | `{a: a, b: b}` / `{a}` | `{a: a, b: b}` / `{a,b}` | `{a: a, b: c}` / `{a}` | `{a: a, b: b}` / `{c}` | +| ----------------------------------------------------------- | --------------------- | ---------------------- | ------------------------ | ---------------------- | ---------------------- | +| `{}` | fail | fail | fail | fail | fail | +| `{ a: a }` | fail | fail | fail | fail | fail | +| `{ b: b }` | pass | fail | fail | fail | fail | +| `{ a: a, b: b }` | pass | pass | pass | pass | fail | +| `{ a: c }` | fail | fail | fail | fail | fail | +| `{ b: c }` | fail | fail | fail | fail | fail | +| `{ a: c, b: b }` | fail | fail | fail | fail | fail | +| `{ a: c, b: c }` | fail | fail | fail | fail | fail | +| `{ c: c }` | fail | fail | fail | fail | fail | +| `{ a: a, c: c }` | fail | fail | fail | fail | fail | +| `{ b: b, c: c}` | fail | fail | fail | fail | fail | +| `{ a: a, b: b, c: c }` | fail | fail | fail | fail | fail | ### Message:`{}` / `{a: a, b: b}` -CMM Material/Required Keys →
Reproduced EC ↓ | `{a: a, b: b}` / `{}` | `{a: a, b: b}` / `{a}`| `{a: a, b: b}` / `{a,b}`| `{a: a, b: c}` / `{a}` | `{a: a, b: b}` / `{c}` | -------------------------------------------------------------|-----------------------|------------------------|--------------------------|------------------------|------------------------| -`{}` | fail | fail | fail | fail | fail | -`{ a: a }` | fail | pass | fail | fail | fail | -`{ b: b }` | fail | fail | fail | fail | fail | -`{ a: a, b: b }` | pass | fail | pass | fail | fail | -`{ a: c }` | fail | fail | fail | fail | fail | -`{ b: c }` | fail | fail | fail | fail | fail | -`{ a: c, b: b }` | fail | fail | fail | fail | fail | -`{ a: c, b: c }` | fail | fail | fail | fail | fail | -`{ c: c }` | fail | fail | fail | fail | fail | -`{ a: a, c: c }` | fail | fail | fail | fail | fail | -`{ b: b, c: c}` | fail | fail | fail | fail | fail | -`{ a: a, b: b, c: c }` | fail | fail | fail | fail | fail | \ No newline at end of file +| CMM Material/Required Keys →
Reproduced EC ↓ | `{a: a, b: b}` / `{}` | `{a: a, b: b}` / `{a}` | `{a: a, b: b}` / `{a,b}` | `{a: a, b: c}` / `{a}` | `{a: a, b: b}` / `{c}` | +| ----------------------------------------------------------- | --------------------- | ---------------------- | ------------------------ | ---------------------- | ---------------------- | +| `{}` | fail | fail | fail | fail | fail | +| `{ a: a }` | fail | pass | fail | fail | fail | +| `{ b: b }` | fail | fail | fail | fail | fail | +| `{ a: a, b: b }` | pass | fail | pass | fail | fail | +| `{ a: c }` | fail | fail | fail | fail | fail | +| `{ b: c }` | fail | fail | fail | fail | fail | +| `{ a: c, b: b }` | fail | fail | fail | fail | fail | +| `{ a: c, b: c }` | fail | fail | fail | fail | fail | +| `{ c: c }` | fail | fail | fail | fail | fail | +| `{ a: a, c: c }` | fail | fail | fail | fail | fail | +| `{ b: b, c: c}` | fail | fail | fail | fail | fail | +| `{ a: a, b: b, c: c }` | fail | fail | fail | fail | fail | diff --git a/changes/2023-09-26_encryption-context-decrypt/change.md b/changes/2023-09-26_encryption-context-decrypt/change.md index 252ccc10..6c68312d 100644 --- a/changes/2023-09-26_encryption-context-decrypt/change.md +++ b/changes/2023-09-26_encryption-context-decrypt/change.md @@ -33,16 +33,17 @@ that the [encryption context](../../framework/structures.md#encryption-context) additional authenticated data during the decryption of the input [encrypted message](#encrypted-message) is returned. -Additionally it should also return the +Additionally it should also return the [encryption context used for authentication only](../../client-apis/decrypt.md#encryption-context-to-only-authenticate) if it used any during the operation. ### `decrypt` API returns encryption context used as AAD and encryption context used for authentication only + On encrypt the [required encryption context cmm](../../framework/required-encryption-context-cmm.md), is able to filter out encryption context key-value pairs that are not stored on the message. If the required encryption context CMM filters out encryption context keys from the Additional Authenticated -Data stored on the header, Decrypt MUST use the +Data stored on the header, Decrypt MUST use the [encryption context to only authenticate](../../client-apis/decrypt.md#encryption-context-to-only-authenticate) to verify the header auth tag.