

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# Mise en cache des clés de données
<a name="data-key-caching"></a>

La *mise en cache des clés de données* stocke les [clés de données](concepts.md#DEK) et les [matériaux de chiffrement connexes](data-caching-details.md#cache-entries) dans un cache. Lorsque vous chiffrez ou déchiffrez des données, la AWS Encryption SDK clé de données correspondante est recherchée dans le cache. Si une correspondance est trouvée, il utilise la clé de données mise en cache au lieu d'en générer une nouvelle. La mise en cache des clés de données peut améliorer les performances, réduire les coûts et vous aider à respecter les limites de service lorsque votre application grandit. 

Votre application peut tirer parti de la mise en cache des clés de données si :
+ elle peut réutiliser les clés de données ;
+ elle génère de nombreuses clés de données ; 
+ vos opérations de chiffrement sont trop lentes, trop coûteuses, trop limitées ou utilisent trop de ressources.

La mise en cache peut réduire votre utilisation de services cryptographiques tels que AWS Key Management Service ()AWS KMS. Si vous atteignez votre [AWS KMS requests-per-secondlimite, la](https://docs.aws.amazon.com/kms/latest/developerguide/limits.html#requests-per-second) mise en cache peut vous aider. Votre application peut utiliser des clés mises en cache pour répondre à certaines de vos demandes de clés de données au lieu d'appeler AWS KMS. (Vous pouvez également créer un dossier dans le [AWS Support Center](https://console.aws.amazon.com/support/home#/) pour augmenter la limite de votre compte.)

Il vous AWS Encryption SDK aide à créer et à gérer votre cache de clés de données. [Il fournit un [cache local](data-caching-details.md#simplecache) et un [gestionnaire de matériel cryptographique de mise](data-caching-details.md#caching-cmm) en cache (CMM de mise en cache) qui interagit avec le cache et applique les seuils de sécurité que vous définissez.](thresholds.md) Associés, ces composants vous permettent de bénéficier de l'efficacité que génère la réutilisation des clés de données, tout en préservant la sécurité de votre système.

La mise en cache des clés de données est une fonctionnalité facultative AWS Encryption SDK que vous devez utiliser avec prudence. Par défaut, une nouvelle clé de données est générée pour chaque opération de chiffrement. AWS Encryption SDK Cette technique prend en charge les bonnes pratiques de chiffrement, ce qui dissuade de réutiliser excessivement les clés de données. En général, utilisez la mise en cache des clés de données uniquement lorsqu'elle est nécessaire pour atteindre vos objectifs de performance. Ensuite, utilisez les [seuils de sécurité](thresholds.md) de la mise en cache des clés de données afin vous assurer que vous utilisez la quantité minimale de mise en cache requise pour atteindre vos objectifs de coûts et de performance. 

Version 3. *x* of the supporte Kit SDK de chiffrement AWS pour Java uniquement le CMM de mise en cache avec l'ancienne interface des fournisseurs de clés principales, et non avec l'interface keyring. Cependant, version 4. *x* et versions ultérieures du AWS Encryption SDK pour .NET, version 3. *x* du Kit SDK de chiffrement AWS pour Java, version 4. *x* du Kit SDK de chiffrement AWS pour Python, version 1. *x* du AWS Encryption SDK pour Rust et la version 0.1. *x* ou une version ultérieure de AWS Encryption SDK for Go prend en charge le trousseau de [clés AWS KMS hiérarchique](use-hierarchical-keyring.md), une solution alternative de mise en cache de matériaux cryptographiques. Le contenu chiffré avec le trousseau AWS KMS hiérarchique ne peut être déchiffré qu'avec le trousseau hiérarchique. AWS KMS 

Pour une discussion détaillée de ces compromis en matière de sécurité, voir [AWS Encryption SDK: Comment déterminer si la mise en cache des clés de données convient à votre application](https://aws.amazon.com/blogs/security/aws-encryption-sdk-how-to-decide-if-data-key-caching-is-right-for-your-application/) dans le blog sur la AWS sécurité.

**Topics**
+ [Utilisation de la mise en cache des clés de données](implement-caching.md)
+ [Définition des seuils de sécurité du cache](thresholds.md)
+ [Détails de la mise en cache des clés de données](data-caching-details.md)
+ [Exemple de mise en cache des clés de données](sample-cache-example.md)

# Utilisation de la mise en cache des clés de données
<a name="implement-caching"></a>

Cette rubrique vous montre comment utiliser la mise en cache des clés de données dans votre application. Elle vous guide à travers le processus étape par étape. Elle associe ensuite les étapes dans un exemple simple qui utilise la mise en cache des clés de données dans une opération visant à chiffrer une chaîne.

Les exemples présentés dans cette section montrent comment utiliser [la version 2.0. ](about-versions.md)*x* et versions ultérieures du AWS Encryption SDK. Pour les exemples utilisant des versions antérieures, recherchez votre version dans la liste des [versions](https://github.com/aws/aws-encryption-sdk-c/releases) du GitHub référentiel de votre [langage de programmation](programming-languages.md).

Pour des exemples complets et testés d'utilisation de la mise en cache des clés de données dans le AWS Encryption SDK, voir :
+ C/C\$1\$1 : [caching\$1cmm.cpp](https://github.com/aws/aws-encryption-sdk-c/blob/master/examples/caching_cmm.cpp)
+ Java : [SimpleDataKeyCachingExample.java](https://github.com/aws/aws-encryption-sdk-java/blob/master/src/examples/java/com/amazonaws/crypto/examples/v2/SimpleDataKeyCachingExample.java)
+ JavaScript Navigateur : [caching\$1cmm.ts](https://github.com/aws/aws-encryption-sdk-javascript/blob/master/modules/example-browser/src/caching_cmm.ts)
+ JavaScript Node.js : [caching\$1cmm.ts](https://github.com/aws/aws-encryption-sdk-javascript/blob/master/modules/example-node/src/caching_cmm.ts)
+ Python : [data\$1key\$1caching\$1basic.py](https://github.com/aws/aws-encryption-sdk-python/blob/master/examples/src/legacy/data_key_caching_basic.py)

[AWS Encryption SDK for .NET](dot-net.md) ne prend pas en charge la mise en cache des clés de données.

**Topics**
+ [Utilisation de la mise en cache des clés de données : Step-by-step](#implement-caching-steps)
+ [Exemple de mise en cache des clés de données : chiffrement d'une chaîne](#caching-example-encrypt-string)

## Utilisation de la mise en cache des clés de données : Step-by-step
<a name="implement-caching-steps"></a>

Ces step-by-step instructions vous montrent comment créer les composants dont vous avez besoin pour implémenter la mise en cache des clés de données.
+ [Création d'un cache de clé de données](data-caching-details.md#simplecache) Dans ces exemples, nous utilisons le cache local AWS Encryption SDK fourni par le. Nous limitons le cache à 10 clés de données.

   

------
#### [ C ]

  ```
  // Cache capacity (maximum number of entries) is required
  size_t cache_capacity = 10; 
  struct aws_allocator *allocator = aws_default_allocator();
  
  struct aws_cryptosdk_materials_cache *cache = aws_cryptosdk_materials_cache_local_new(allocator, cache_capacity);
  ```

------
#### [ Java ]

  L'exemple suivant utilise la version 2. *x* du Kit SDK de chiffrement AWS pour Java. Version 3. *x* du rend Kit SDK de chiffrement AWS pour Java obsolète le CMM de mise en cache des clés de données. Avec la version 3. *x*, vous pouvez également utiliser le trousseau de [clés AWS KMS hiérarchique](use-hierarchical-keyring.md), une solution alternative de mise en cache des matériaux cryptographiques.

  ```
  // Cache capacity (maximum number of entries) is required
  int MAX_CACHE_SIZE = 10; 
  
  CryptoMaterialsCache cache = new LocalCryptoMaterialsCache(MAX_CACHE_SIZE);
  ```

------
#### [ JavaScript Browser ]

  ```
  const capacity = 10
  
  const cache = getLocalCryptographicMaterialsCache(capacity)
  ```

------
#### [ JavaScript Node.js ]

  ```
  const capacity = 10
  
  const cache = getLocalCryptographicMaterialsCache(capacity)
  ```

------
#### [ Python ]

  ```
  # Cache capacity (maximum number of entries) is required
  MAX_CACHE_SIZE = 10
  
  cache = aws_encryption_sdk.LocalCryptoMaterialsCache(MAX_CACHE_SIZE)
  ```

------

   
+ Créez un [fournisseur de clés principales](concepts.md#master-key-provider) (Java et Python) ou un [trousseau de clés](concepts.md#keyring) (C et JavaScript). Ces exemples utilisent un fournisseur de clés principales AWS Key Management Service (AWS KMS) ou un trousseau de [AWS KMS clés](use-kms-keyring.md) compatible.

   

------
#### [ C ]

  ```
  // Create an AWS KMS keyring
  //   The input is the Amazon Resource Name (ARN) 
  //   of an AWS KMS key
  struct aws_cryptosdk_keyring *kms_keyring = Aws::Cryptosdk::KmsKeyring::Builder().Build(kms_key_arn);
  ```

------
#### [ Java ]

  L'exemple suivant utilise la version 2. *x* du Kit SDK de chiffrement AWS pour Java. Version 3. *x* du rend Kit SDK de chiffrement AWS pour Java obsolète le CMM de mise en cache des clés de données. Avec la version 3. *x*, vous pouvez également utiliser le trousseau de [clés AWS KMS hiérarchique](use-hierarchical-keyring.md), une solution alternative de mise en cache des matériaux cryptographiques.

  ```
  // Create an AWS KMS master key provider
  //   The input is the Amazon Resource Name (ARN) 
  //   of an AWS KMS key
  MasterKeyProvider<KmsMasterKey> keyProvider = KmsMasterKeyProvider.builder().buildStrict(kmsKeyArn);
  ```

------
#### [ JavaScript Browser ]

  Dans le navigateur, vous devez injecter vos informations d'identification en toute sécurité. Cet exemple définit les informations d'identification dans un webpack (kms.webpack.config) qui résout les informations d'identification lors de l'exécution. Il crée une instance de fournisseur de AWS KMS clients à partir d'un AWS KMS client et des informations d'identification. Ensuite, lorsqu'il crée le trousseau de clés, il transmet le fournisseur client au constructeur avec le AWS KMS key (. `generatorKeyId)`

  ```
  const { accessKeyId, secretAccessKey, sessionToken } = credentials
  
  const clientProvider = getClient(KMS, {
      credentials: {
        accessKeyId,
        secretAccessKey,
        sessionToken
      }
    })
  
  /*  Create an AWS KMS keyring
   *  You must configure the AWS KMS keyring with at least one AWS KMS key
  *  The input is the Amazon Resource Name (ARN) 
   */ of an AWS KMS key
  const keyring = new KmsKeyringBrowser({
      clientProvider,
      generatorKeyId,
      keyIds,
    })
  ```

------
#### [ JavaScript Node.js ]

  ```
  /* Create an AWS KMS keyring
   *   The input is the Amazon Resource Name (ARN) 
  */   of an AWS KMS key
  const keyring = new KmsKeyringNode({ generatorKeyId })
  ```

------
#### [ Python ]

  ```
  # Create an AWS KMS master key provider
  #  The input is the Amazon Resource Name (ARN) 
  #  of an AWS KMS key
  key_provider = aws_encryption_sdk.StrictAwsKmsMasterKeyProvider(key_ids=[kms_key_arn])
  ```

------

   
+ [Créez un gestionnaire de matériel cryptographique de mise en cache](data-caching-details.md#caching-cmm) (CMM de mise en cache). 

   

  Associez votre CMM de mise en cache à votre cache et à votre fournisseur de clé principale ou à votre trousseau de clés. [Définissez ensuite les seuils de sécurité du cache](thresholds.md) sur le CMM de mise en cache. 

   

------
#### [ C ]

  Dans le Kit SDK de chiffrement AWS pour C, vous pouvez créer un CMM de mise en cache à partir d'un CMM sous-jacent, tel que le CMM par défaut, ou à partir d'un trousseau de clés. Cet exemple crée le CMM de mise en cache à partir d'un porte-clés.

  Après avoir créé le CMM de mise en cache, vous pouvez libérer vos références au trousseau de clés et au cache. Pour en savoir plus, consultez [Comptage des références](c-language-using.md#c-language-using-release).

  ```
  // Create the caching CMM
  //   Set the partition ID to NULL.
  //   Set the required maximum age value to 60 seconds.
  struct aws_cryptosdk_cmm *caching_cmm = aws_cryptosdk_caching_cmm_new_from_keyring(allocator, cache, kms_keyring, NULL, 60, AWS_TIMESTAMP_SECS);
  
  // Add an optional message threshold
  //   The cached data key will not be used for more than 10 messages.
  aws_status = aws_cryptosdk_caching_cmm_set_limit_messages(caching_cmm, 10);
  
  // Release your references to the cache and the keyring.
  aws_cryptosdk_materials_cache_release(cache);
  aws_cryptosdk_keyring_release(kms_keyring);
  ```

------
#### [ Java ]

  L'exemple suivant utilise la version 2. *x* du Kit SDK de chiffrement AWS pour Java. Version 3. *x* of the Kit SDK de chiffrement AWS pour Java ne prend pas en charge la mise en cache des clés de données, mais prend en charge le [keyring AWS KMS hiérarchique](use-hierarchical-keyring.md), une solution alternative de mise en cache des matériaux cryptographiques.

  ```
  /*
   * Security thresholds
   *   Max entry age is required. 
   *   Max messages (and max bytes) per entry are optional
   */
  int MAX_ENTRY_AGE_SECONDS = 60;
  int MAX_ENTRY_MSGS = 10;
         
  //Create a caching CMM
  CryptoMaterialsManager cachingCmm =
      CachingCryptoMaterialsManager.newBuilder().withMasterKeyProvider(keyProvider)
                                   .withCache(cache)
                                   .withMaxAge(MAX_ENTRY_AGE_SECONDS, TimeUnit.SECONDS)
                                   .withMessageUseLimit(MAX_ENTRY_MSGS)
                                   .build();
  ```

------
#### [ JavaScript Browser ]

  ```
  /*
   * Security thresholds
   *   Max age (in milliseconds) is required.
   *   Max messages (and max bytes) per entry are optional.
   */
  const maxAge = 1000 * 60
  const maxMessagesEncrypted = 10
  
  /* Create a caching CMM from a keyring  */
  const cachingCmm = new WebCryptoCachingMaterialsManager({
    backingMaterials: keyring,
    cache,
    maxAge,
    maxMessagesEncrypted
  })
  ```

------
#### [ JavaScript Node.js ]

  ```
  /*
   * Security thresholds
   *   Max age (in milliseconds) is required.
   *   Max messages (and max bytes) per entry are optional.
   */
  const maxAge = 1000 * 60
  const maxMessagesEncrypted = 10
  
  /* Create a caching CMM from a keyring  */
  const cachingCmm = new NodeCachingMaterialsManager({
    backingMaterials: keyring,
    cache,
    maxAge,
    maxMessagesEncrypted
  })
  ```

------
#### [ Python ]

  ```
  # Security thresholds
  #   Max entry age is required. 
  #   Max messages (and max bytes) per entry are optional
  #
  MAX_ENTRY_AGE_SECONDS = 60.0
  MAX_ENTRY_MESSAGES = 10
         
  # Create a caching CMM
  caching_cmm = CachingCryptoMaterialsManager(
      master_key_provider=key_provider,
      cache=cache,
      max_age=MAX_ENTRY_AGE_SECONDS,
      max_messages_encrypted=MAX_ENTRY_MESSAGES
  )
  ```

------

C'est tout ce que vous avez besoin de faire. Ensuite, laissez-les AWS Encryption SDK gérer le cache pour vous ou ajoutez votre propre logique de gestion du cache.

Lorsque vous souhaitez utiliser la mise en cache des clés de données dans un appel pour chiffrer ou déchiffrer des données, spécifiez votre CMM de mise en cache plutôt qu'un fournisseur de clé principale ou un autre CMM.

**Note**  
Si vous chiffrez des flux de données, ou des données de taille inconnue, assurez-vous de spécifier la taille des données dans la demande. N'utilise AWS Encryption SDK pas la mise en cache des clés de données lors du chiffrement de données de taille inconnue.

------
#### [ C ]

Dans le Kit SDK de chiffrement AWS pour C, vous créez une session avec le CMM de mise en cache, puis vous traitez la session. 

Par défaut, lorsque la taille du message est inconnue et illimitée, les clés de données AWS Encryption SDK ne sont pas mises en cache. Pour autoriser la mise en cache lorsque vous ne connaissez pas la taille exacte des données, utilisez la méthode `aws_cryptosdk_session_set_message_bound` pour définir une taille maximale pour le message. Définissez une limite supérieure à la taille estimée du message. Si la taille réelle du message dépasse la limite, l'opération échoue.

```
/* Create a session with the caching CMM. Set the session mode to encrypt. */
struct aws_cryptosdk_session *session = aws_cryptosdk_session_new_from_cmm_2(allocator, AWS_CRYPTOSDK_ENCRYPT, caching_cmm);

/* Set a message bound of 1000 bytes */
aws_status = aws_cryptosdk_session_set_message_bound(session, 1000);

/* Encrypt the message using the session with the caching CMM */
aws_status = aws_cryptosdk_session_process(
             session, output_buffer, output_capacity, &output_produced, input_buffer, input_len, &input_consumed);

/* Release your references to the caching CMM and the session. */
aws_cryptosdk_cmm_release(caching_cmm);
aws_cryptosdk_session_destroy(session);
```

------
#### [ Java ]

L'exemple suivant utilise la version 2. *x* du Kit SDK de chiffrement AWS pour Java. Version 3. *x* du rend Kit SDK de chiffrement AWS pour Java obsolète le CMM de mise en cache des clés de données. Avec la version 3. *x*, vous pouvez également utiliser le trousseau de [clés AWS KMS hiérarchique](use-hierarchical-keyring.md), une solution alternative de mise en cache des matériaux cryptographiques.

```
// When the call to encryptData specifies a caching CMM,
// the encryption operation uses the data key cache
final AwsCrypto encryptionSdk = AwsCrypto.standard();
return encryptionSdk.encryptData(cachingCmm, plaintext_source).getResult();
```

------
#### [ JavaScript Browser ]

```
const { result } = await encrypt(cachingCmm, plaintext)
```

------
#### [ JavaScript Node.js ]

Lorsque vous utilisez le CMM de mise en cache dans Kit SDK de chiffrement AWS pour JavaScript for Node.js, la `encrypt` méthode nécessite la longueur du texte en clair. Si vous ne le fournissez pas, la clé de données n'est pas mise en cache. Si vous fournissez une longueur, mais que les données en texte brut que vous fournissez dépassent cette longueur, l'opération de chiffrement échoue. Si vous ne connaissez pas la longueur exacte du texte brut, par exemple lorsque vous diffusez des données, indiquez la plus grande valeur attendue.

```
const { result } = await encrypt(cachingCmm, plaintext, { plaintextLength: plaintext.length })
```

------
#### [ Python ]

```
# Set up an encryption client
client = aws_encryption_sdk.EncryptionSDKClient()

# When the call to encrypt specifies a caching CMM,
# the encryption operation uses the data key cache
#
encrypted_message, header = client.encrypt(
    source=plaintext_source,
    materials_manager=caching_cmm
)
```

------

## Exemple de mise en cache des clés de données : chiffrement d'une chaîne
<a name="caching-example-encrypt-string"></a>

Cet exemple de code simple utilise la mise en cache des clés de données lors du chiffrement d'une chaîne. Il combine le code de la [step-by-step procédure](#implement-caching-steps) dans un code de test que vous pouvez exécuter.

L'exemple crée un [cache local](data-caching-details.md#simplecache) et un [fournisseur de clés principales](concepts.md#master-key-provider) ou un trousseau de [clés](concepts.md#keyring) pour un AWS KMS key. [Il utilise ensuite le cache local et le fournisseur de clés principales ou le trousseau de clés pour créer un CMM de mise en cache avec des seuils de sécurité appropriés.](thresholds.md) [En Java et Python, la demande de chiffrement spécifie le CMM de mise en cache, les données en texte brut à chiffrer et un contexte de chiffrement.](data-caching-details.md#caching-encryption-context) En C, le CMM de mise en cache est spécifié dans la session et la session est fournie à la demande de chiffrement.

Pour exécuter ces exemples, vous devez fournir le [nom de ressource Amazon (ARN) d'un AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/viewing-keys.html). Assurez-vous que vous êtes [autorisé à utiliser la AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html#key-policy-default-allow-users) pour générer une clé de données.

Pour des exemples concrets plus détaillés de création et d'utilisation d'un cache de clé de données, voir[Exemple de code de mise en cache des clés de données](sample-cache-example-code.md).

------
#### [ C ]

```
/*
 * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"). You may not use
 * this file except in compliance with the License. A copy of the License is
 * located at
 *
 *     http://aws.amazon.com/apache2.0/
 *
 * or in the "license" file accompanying this file. This file is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <aws/cryptosdk/cache.h>
#include <aws/cryptosdk/cpp/kms_keyring.h>
#include <aws/cryptosdk/session.h>

void encrypt_with_caching(
    uint8_t *ciphertext,     // output will go here (assumes ciphertext_capacity bytes already allocated)
    size_t *ciphertext_len,  // length of output will go here
    size_t ciphertext_capacity,
    const char *kms_key_arn,
    int max_entry_age,
    int cache_capacity) {
    const uint64_t MAX_ENTRY_MSGS = 100;

    struct aws_allocator *allocator = aws_default_allocator();
    
    // Load error strings for debugging
    aws_cryptosdk_load_error_strings();

    // Create a keyring
    struct aws_cryptosdk_keyring *kms_keyring = Aws::Cryptosdk::KmsKeyring::Builder().Build(kms_key_arn);

    // Create a cache
    struct aws_cryptosdk_materials_cache *cache = aws_cryptosdk_materials_cache_local_new(allocator, cache_capacity);

    // Create a caching CMM
    struct aws_cryptosdk_cmm *caching_cmm = aws_cryptosdk_caching_cmm_new_from_keyring(
        allocator, cache, kms_keyring, NULL, max_entry_age, AWS_TIMESTAMP_SECS);
    if (!caching_cmm) abort();

    if (aws_cryptosdk_caching_cmm_set_limit_messages(caching_cmm, MAX_ENTRY_MSGS)) abort();

    // Create a session
    struct aws_cryptosdk_session *session =        
        aws_cryptosdk_session_new_from_cmm_2(allocator, AWS_CRYPTOSDK_ENCRYPT, caching_cmm);
    if (!session) abort();

    // Encryption context
    struct aws_hash_table *enc_ctx = aws_cryptosdk_session_get_enc_ctx_ptr_mut(session);
    if (!enc_ctx) abort();
    AWS_STATIC_STRING_FROM_LITERAL(enc_ctx_key, "purpose");
    AWS_STATIC_STRING_FROM_LITERAL(enc_ctx_value, "test");
    if (aws_hash_table_put(enc_ctx, enc_ctx_key, (void *)enc_ctx_value, NULL)) abort();

    // Plaintext data to be encrypted
    const char *my_data = "My plaintext data";
    size_t my_data_len  = strlen(my_data);
    if (aws_cryptosdk_session_set_message_size(session, my_data_len)) abort();

    // When the session uses a caching CMM, the encryption operation uses the data key cache
    // specified in the caching CMM.
    size_t bytes_read;
    if (aws_cryptosdk_session_process(
            session,
            ciphertext,
            ciphertext_capacity,
            ciphertext_len,
            (const uint8_t *)my_data,
            my_data_len,
            &bytes_read))
        abort();
    if (!aws_cryptosdk_session_is_done(session) || bytes_read != my_data_len) abort();

    aws_cryptosdk_session_destroy(session);
    aws_cryptosdk_cmm_release(caching_cmm);
    aws_cryptosdk_materials_cache_release(cache);
    aws_cryptosdk_keyring_release(kms_keyring);
}
```

------
#### [ Java ]

L'exemple suivant utilise la version 2. *x* du Kit SDK de chiffrement AWS pour Java. Version 3. *x* du rend Kit SDK de chiffrement AWS pour Java obsolète le CMM de mise en cache des clés de données. Avec la version 3. *x*, vous pouvez également utiliser le trousseau de [clés AWS KMS hiérarchique](use-hierarchical-keyring.md), une solution alternative de mise en cache des matériaux cryptographiques.

```
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package com.amazonaws.crypto.examples;

import com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.CryptoMaterialsManager;
import com.amazonaws.encryptionsdk.MasterKeyProvider;
import com.amazonaws.encryptionsdk.caching.CachingCryptoMaterialsManager;
import com.amazonaws.encryptionsdk.caching.CryptoMaterialsCache;
import com.amazonaws.encryptionsdk.caching.LocalCryptoMaterialsCache;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKey;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKeyProvider;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * Encrypts a string using an &KMS; key and data key caching
 *
 * <p>
 * Arguments:
 * <ol>
 * <li>KMS Key ARN: To find the Amazon Resource Name of your &KMS; key,
 *     see 'Find the key ID and ARN' at https://docs.aws.amazon.com/kms/latest/developerguide/find-cmk-id-arn.html
 * <li>Max entry age: Maximum time (in seconds) that a cached entry can be used
 * <li>Cache capacity: Maximum number of entries in the cache
 * </ol>
 */
public class SimpleDataKeyCachingExample {

    /*
     * Security thresholds
     *   Max entry age is required.
     *   Max messages (and max bytes) per data key are optional
     */
    private static final int MAX_ENTRY_MSGS = 100;

    public static byte[] encryptWithCaching(String kmsKeyArn, int maxEntryAge, int cacheCapacity) {
        // Plaintext data to be encrypted
        byte[] myData = "My plaintext data".getBytes(StandardCharsets.UTF_8);

        // Encryption context
        // Most encrypted data should have an associated encryption context
        // to protect integrity. This sample uses placeholder values.
        // For more information see:
        // blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management
        final Map<String, String> encryptionContext = Collections.singletonMap("purpose", "test");

        // Create a master key provider
        MasterKeyProvider<KmsMasterKey> keyProvider = KmsMasterKeyProvider.builder()
            .buildStrict(kmsKeyArn);

        // Create a cache
        CryptoMaterialsCache cache = new LocalCryptoMaterialsCache(cacheCapacity);

        // Create a caching CMM
        CryptoMaterialsManager cachingCmm =
            CachingCryptoMaterialsManager.newBuilder().withMasterKeyProvider(keyProvider)
                .withCache(cache)
                .withMaxAge(maxEntryAge, TimeUnit.SECONDS)
                .withMessageUseLimit(MAX_ENTRY_MSGS)
                .build();

        // When the call to encryptData specifies a caching CMM,
        // the encryption operation uses the data key cache
        final AwsCrypto encryptionSdk = AwsCrypto.standard();
        return encryptionSdk.encryptData(cachingCmm, myData, encryptionContext).getResult();
    }
}
```

------
#### [ JavaScript Browser ]

```
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

/* This is a simple example of using a caching CMM with a KMS keyring
 * to encrypt and decrypt using the AWS Encryption SDK for Javascript in a browser.
 */

import {
  KmsKeyringBrowser,
  KMS,
  getClient,
  buildClient,
  CommitmentPolicy,
  WebCryptoCachingMaterialsManager,
  getLocalCryptographicMaterialsCache,
} from '@aws-crypto/client-browser'
import { toBase64 } from '@aws-sdk/util-base64-browser'

/* This builds the client with the REQUIRE_ENCRYPT_REQUIRE_DECRYPT commitment policy,
 * which enforces that this client only encrypts using committing algorithm suites
 * and enforces that this client
 * will only decrypt encrypted messages
 * that were created with a committing algorithm suite.
 * This is the default commitment policy
 * if you build the client with `buildClient()`.
 */
const { encrypt, decrypt } = buildClient(
  CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
)

/* This is injected by webpack.
 * The webpack.DefinePlugin or @aws-sdk/karma-credential-loader will replace the values when bundling.
 * The credential values are pulled from @aws-sdk/credential-provider-node
 * Use any method you like to get credentials into the browser.
 * See kms.webpack.config
 */
declare const credentials: {
  accessKeyId: string
  secretAccessKey: string
  sessionToken: string
}

/* This is done to facilitate testing. */
export async function testCachingCMMExample() {
  /* This example uses an &KMS; keyring. The generator key in a &KMS; keyring generates and encrypts the data key.
   * The caller needs kms:GenerateDataKey permission on the &KMS; key in generatorKeyId.
   */
  const generatorKeyId =
    'arn:aws:kms:us-west-2:658956600833:alias/EncryptDecrypt'

  /* Adding additional KMS keys that can decrypt.
   * The caller must have kms:Encrypt permission for every &KMS; key in keyIds.
   * You might list several keys in different AWS Regions.
   * This allows you to decrypt the data in any of the represented Regions.
   * In this example, the generator key
   * and the additional key are actually the same &KMS; key.
   * In `generatorId`, this &KMS; key is identified by its alias ARN.
   * In `keyIds`, this &KMS; key is identified by its key ARN.
   * In practice, you would specify different &KMS; keys,
   * or omit the `keyIds` parameter.
   * This is *only* to demonstrate how the &KMS; key ARNs are configured.
   */
  const keyIds = [
    'arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f',
  ]

  /* Need a client provider that will inject correct credentials.
   * The credentials here are injected by webpack from your environment bundle is created
   * The credential values are pulled using @aws-sdk/credential-provider-node.
   * See kms.webpack.config
   * You should inject your credential into the browser in a secure manner
   * that works with your application.
   */
  const { accessKeyId, secretAccessKey, sessionToken } = credentials

  /* getClient takes a KMS client constructor
   * and optional configuration values.
   * The credentials can be injected here,
   * because browsers do not have a standard credential discovery process the way Node.js does.
   */
  const clientProvider = getClient(KMS, {
    credentials: {
      accessKeyId,
      secretAccessKey,
      sessionToken,
    },
  })

  /* You must configure the KMS keyring with your &KMS; keys */
  const keyring = new KmsKeyringBrowser({
    clientProvider,
    generatorKeyId,
    keyIds,
  })

  /* Create a cache to hold the data keys (and related cryptographic material).
   * This example uses the local cache provided by the Encryption SDK.
   * The `capacity` value represents the maximum number of entries
   * that the cache can hold.
   * To make room for an additional entry,
   * the cache evicts the oldest cached entry.
   * Both encrypt and decrypt requests count independently towards this threshold.
   * Entries that exceed any cache threshold are actively removed from the cache.
   * By default, the SDK checks one item in the cache every 60 seconds (60,000 milliseconds).
   * To change this frequency, pass in a `proactiveFrequency` value
   * as the second parameter. This value is in milliseconds.
   */
  const capacity = 100
  const cache = getLocalCryptographicMaterialsCache(capacity)

  /* The partition name lets multiple caching CMMs share the same local cryptographic cache.
   * By default, the entries for each CMM are cached separately. However, if you want these CMMs to share the cache,
   * use the same partition name for both caching CMMs.
   * If you don't supply a partition name, the Encryption SDK generates a random name for each caching CMM.
   * As a result, sharing elements in the cache MUST be an intentional operation.
   */
  const partition = 'local partition name'

  /* maxAge is the time in milliseconds that an entry will be cached.
   * Elements are actively removed from the cache.
   */
  const maxAge = 1000 * 60

  /* The maximum number of bytes that will be encrypted under a single data key.
   * This value is optional,
   * but you should configure the lowest practical value.
   */
  const maxBytesEncrypted = 100

  /* The maximum number of messages that will be encrypted under a single data key.
   * This value is optional,
   * but you should configure the lowest practical value.
   */
  const maxMessagesEncrypted = 10

  const cachingCMM = new WebCryptoCachingMaterialsManager({
    backingMaterials: keyring,
    cache,
    partition,
    maxAge,
    maxBytesEncrypted,
    maxMessagesEncrypted,
  })

  /* Encryption context is a *very* powerful tool for controlling
   * and managing access.
   * When you pass an encryption context to the encrypt function,
   * the encryption context is cryptographically bound to the ciphertext.
   * If you don't pass in the same encryption context when decrypting,
   * the decrypt function fails.
   * The encryption context is ***not*** secret!
   * Encrypted data is opaque.
   * You can use an encryption context to assert things about the encrypted data.
   * The encryption context helps you to determine
   * whether the ciphertext you retrieved is the ciphertext you expect to decrypt.
   * For example, if you are are only expecting data from 'us-west-2',
   * the appearance of a different AWS Region in the encryption context can indicate malicious interference.
   * See: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
   *
   * Also, cached data keys are reused ***only*** when the encryption contexts passed into the functions are an exact case-sensitive match.
   * See: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/data-caching-details.html#caching-encryption-context
   */
  const encryptionContext = {
    stage: 'demo',
    purpose: 'simple demonstration app',
    origin: 'us-west-2',
  }

  /* Find data to encrypt. */
  const plainText = new Uint8Array([1, 2, 3, 4, 5])

  /* Encrypt the data.
   * The caching CMM only reuses data keys
   * when it know the length (or an estimate) of the plaintext.
   * However, in the browser,
   * you must provide all of the plaintext to the encrypt function.
   * Therefore, the encrypt function in the browser knows the length of the plaintext
   * and does not accept a plaintextLength option.
   */
  const { result } = await encrypt(cachingCMM, plainText, { encryptionContext })

  /* Log the plain text
   * only for testing and to show that it works.
   */
  console.log('plainText:', plainText)
  document.write('</br>plainText:' + plainText + '</br>')

  /* Log the base64-encoded result
   * so that you can try decrypting it with another AWS Encryption SDK implementation.
   */
  const resultBase64 = toBase64(result)
  console.log(resultBase64)
  document.write(resultBase64)

  /* Decrypt the data.
   * NOTE: This decrypt request will not use the data key
   * that was cached during the encrypt operation.
   * Data keys for encrypt and decrypt operations are cached separately.
   */
  const { plaintext, messageHeader } = await decrypt(cachingCMM, result)

  /* Grab the encryption context so you can verify it. */
  const { encryptionContext: decryptedContext } = messageHeader

  /* Verify the encryption context.
   * If you use an algorithm suite with signing,
   * the Encryption SDK adds a name-value pair to the encryption context that contains the public key.
   * Because the encryption context might contain additional key-value pairs,
   * do not include a test that requires that all key-value pairs match.
   * Instead, verify that the key-value pairs that you supplied to the `encrypt` function are included in the encryption context that the `decrypt` function returns.
   */
  Object.entries(encryptionContext).forEach(([key, value]) => {
    if (decryptedContext[key] !== value)
      throw new Error('Encryption Context does not match expected values')
  })

  /* Log the clear message
   * only for testing and to show that it works.
   */
  document.write('</br>Decrypted:' + plaintext)
  console.log(plaintext)

  /* Return the values to make testing easy. */
  return { plainText, plaintext }
}
```

------
#### [ JavaScript Node.js ]

```
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import {
  KmsKeyringNode,
  buildClient,
  CommitmentPolicy,
  NodeCachingMaterialsManager,
  getLocalCryptographicMaterialsCache,
} from '@aws-crypto/client-node'

/* This builds the client with the REQUIRE_ENCRYPT_REQUIRE_DECRYPT commitment policy,
 * which enforces that this client only encrypts using committing algorithm suites
 * and enforces that this client
 * will only decrypt encrypted messages
 * that were created with a committing algorithm suite.
 * This is the default commitment policy
 * if you build the client with `buildClient()`.
 */
const { encrypt, decrypt } = buildClient(
  CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
)

export async function cachingCMMNodeSimpleTest() {
  /* An &KMS; key is required to generate the data key.
   * You need kms:GenerateDataKey permission on the &KMS; key in generatorKeyId.
   */
  const generatorKeyId =
    'arn:aws:kms:us-west-2:658956600833:alias/EncryptDecrypt'

  /* Adding alternate &KMS; keys that can decrypt.
   * Access to kms:Encrypt is required for every &KMS; key in keyIds.
   * You might list several keys in different AWS Regions.
   * This allows you to decrypt the data in any of the represented Regions.
   * In this example, the generator key
   * and the additional key are actually the same &KMS; key.
   * In `generatorId`, this &KMS; key is identified by its alias ARN.
   * In `keyIds`, this &KMS; key is identified by its key ARN.
   * In practice, you would specify different &KMS; keys,
   * or omit the `keyIds` parameter.
   * This is *only* to demonstrate how the &KMS; key ARNs are configured.
   */
  const keyIds = [
    'arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f',
  ]

  /* The &KMS; keyring must be configured with the desired &KMS; keys
   * This example passes the keyring to the caching CMM
   * instead of using it directly.
   */
  const keyring = new KmsKeyringNode({ generatorKeyId, keyIds })

  /* Create a cache to hold the data keys (and related cryptographic material).
   * This example uses the local cache provided by the Encryption SDK.
   * The `capacity` value represents the maximum number of entries
   * that the cache can hold.
   * To make room for an additional entry,
   * the cache evicts the oldest cached entry.
   * Both encrypt and decrypt requests count independently towards this threshold.
   * Entries that exceed any cache threshold are actively removed from the cache.
   * By default, the SDK checks one item in the cache every 60 seconds (60,000 milliseconds).
   * To change this frequency, pass in a `proactiveFrequency` value
   * as the second parameter. This value is in milliseconds.
   */
  const capacity = 100
  const cache = getLocalCryptographicMaterialsCache(capacity)

  /* The partition name lets multiple caching CMMs share the same local cryptographic cache.
   * By default, the entries for each CMM are cached separately. However, if you want these CMMs to share the cache,
   * use the same partition name for both caching CMMs.
   * If you don't supply a partition name, the Encryption SDK generates a random name for each caching CMM.
   * As a result, sharing elements in the cache MUST be an intentional operation.
   */
  const partition = 'local partition name'

  /* maxAge is the time in milliseconds that an entry will be cached.
   * Elements are actively removed from the cache.
   */
  const maxAge = 1000 * 60

  /* The maximum amount of bytes that will be encrypted under a single data key.
   * This value is optional,
   * but you should configure the lowest value possible.
   */
  const maxBytesEncrypted = 100

  /* The maximum number of messages that will be encrypted under a single data key.
   * This value is optional,
   * but you should configure the lowest value possible.
   */
  const maxMessagesEncrypted = 10

  const cachingCMM = new NodeCachingMaterialsManager({
    backingMaterials: keyring,
    cache,
    partition,
    maxAge,
    maxBytesEncrypted,
    maxMessagesEncrypted,
  })

  /* Encryption context is a *very* powerful tool for controlling
   * and managing access.
   * When you pass an encryption context to the encrypt function,
   * the encryption context is cryptographically bound to the ciphertext.
   * If you don't pass in the same encryption context when decrypting,
   * the decrypt function fails.
   * The encryption context is ***not*** secret!
   * Encrypted data is opaque.
   * You can use an encryption context to assert things about the encrypted data.
   * The encryption context helps you to determine
   * whether the ciphertext you retrieved is the ciphertext you expect to decrypt.
   * For example, if you are are only expecting data from 'us-west-2',
   * the appearance of a different AWS Region in the encryption context can indicate malicious interference.
   * See: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
   *
   * Also, cached data keys are reused ***only*** when the encryption contexts passed into the functions are an exact case-sensitive match.
   * See: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/data-caching-details.html#caching-encryption-context
   */
  const encryptionContext = {
    stage: 'demo',
    purpose: 'simple demonstration app',
    origin: 'us-west-2',
  }

  /* Find data to encrypt.  A simple string. */
  const cleartext = 'asdf'

  /* Encrypt the data.
   * The caching CMM only reuses data keys
   * when it know the length (or an estimate) of the plaintext.
   * If you do not know the length,
   * because the data is a stream
   * provide an estimate of the largest expected value.
   *
   * If your estimate is smaller than the actual plaintext length
   * the AWS Encryption SDK will throw an exception.
   *
   * If the plaintext is not a stream,
   * the AWS Encryption SDK uses the actual plaintext length
   * instead of any length you provide.
   */
  const { result } = await encrypt(cachingCMM, cleartext, {
    encryptionContext,
    plaintextLength: 4,
  })

  /* Decrypt the data.
   * NOTE: This decrypt request will not use the data key
   * that was cached during the encrypt operation.
   * Data keys for encrypt and decrypt operations are cached separately.
   */
  const { plaintext, messageHeader } = await decrypt(cachingCMM, result)

  /* Grab the encryption context so you can verify it. */
  const { encryptionContext: decryptedContext } = messageHeader

  /* Verify the encryption context.
   * If you use an algorithm suite with signing,
   * the Encryption SDK adds a name-value pair to the encryption context that contains the public key.
   * Because the encryption context might contain additional key-value pairs,
   * do not include a test that requires that all key-value pairs match.
   * Instead, verify that the key-value pairs that you supplied to the `encrypt` function are included in the encryption context that the `decrypt` function returns.
   */
  Object.entries(encryptionContext).forEach(([key, value]) => {
    if (decryptedContext[key] !== value)
      throw new Error('Encryption Context does not match expected values')
  })

  /* Return the values so the code can be tested. */
  return { plaintext, result, cleartext, messageHeader }
}
```

------
#### [ Python ]

```
# Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
"""Example of encryption with data key caching."""
import aws_encryption_sdk
from aws_encryption_sdk import CommitmentPolicy


def encrypt_with_caching(kms_key_arn, max_age_in_cache, cache_capacity):
    """Encrypts a string using an &KMS; key and data key caching.

    :param str kms_key_arn: Amazon Resource Name (ARN) of the &KMS; key
    :param float max_age_in_cache: Maximum time in seconds that a cached entry can be used
    :param int cache_capacity: Maximum number of entries to retain in cache at once
    """
    # Data to be encrypted
    my_data = "My plaintext data"

    # Security thresholds
    #   Max messages (or max bytes per) data key are optional
    MAX_ENTRY_MESSAGES = 100

    # Create an encryption context
    encryption_context = {"purpose": "test"}

    # Set up an encryption client with an explicit commitment policy. Note that if you do not explicitly choose a
    # commitment policy, REQUIRE_ENCRYPT_REQUIRE_DECRYPT is used by default.
    client = aws_encryption_sdk.EncryptionSDKClient(commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT)

    # Create a master key provider for the &KMS; key
    key_provider = aws_encryption_sdk.StrictAwsKmsMasterKeyProvider(key_ids=[kms_key_arn])

    # Create a local cache
    cache = aws_encryption_sdk.LocalCryptoMaterialsCache(cache_capacity)

    # Create a caching CMM
    caching_cmm = aws_encryption_sdk.CachingCryptoMaterialsManager(
        master_key_provider=key_provider,
        cache=cache,
        max_age=max_age_in_cache,
        max_messages_encrypted=MAX_ENTRY_MESSAGES,
    )

    # When the call to encrypt data specifies a caching CMM,
    # the encryption operation uses the data key cache specified
    # in the caching CMM
    encrypted_message, _header = client.encrypt(
        source=my_data, materials_manager=caching_cmm, encryption_context=encryption_context
    )

    return encrypted_message
```

------

# Définition des seuils de sécurité du cache
<a name="thresholds"></a>

Lorsque vous implémentez la mise en cache des clés de données, vous devez configurer les seuils de sécurité appliqués par le [CMM de mise en cache](data-caching-details.md#caching-cmm). 

Les seuils de sécurité vous aident à limiter la durée d'utilisation de chaque clé de données mise en cache et la quantité de données protégée par chaque clé de données. Le CMM de mise en cache renvoie les clés de données mises en cache uniquement lorsque l'entrée du cache est conforme à tous les seuils de sécurité. Si l'entrée de cache dépasse un seuil, elle n'est pas utilisée pour l'opération actuelle et elle est expulsée du cache dès que possible. La première utilisation de chaque clé de données (avant la mise en cache) n'est pas comptabilisée dans ces seuils. 

En règle générale, utilisez le volume de cache minimum nécessaire pour atteindre vos objectifs de coûts et de performance. 

Le AWS Encryption SDK seul cache les clés de données chiffrées à l'aide d'une fonction de [dérivation de clés](https://en.wikipedia.org/wiki/Key_derivation_function). Il établit également des limites supérieures pour certaines valeurs de seuil. Ces restrictions garantissent que les clés de données ne sont pas réutilisées au-delà de leurs limites de chiffrement. Cependant, étant donné que vos clés de données en texte brut sont mises en cache (dans la mémoire, par défaut), essayez de réduire le temps d'enregistrement des clés. Essayez également de limiter les données qui pourraient être exposées si une clé est compromise.

Pour des exemples de définition de seuils de sécurité du cache, voir [AWS Encryption SDK: Comment déterminer si la mise en cache des clés de données convient à votre application](https://aws.amazon.com/blogs/security/aws-encryption-sdk-how-to-decide-if-data-key-caching-is-right-for-your-application/) dans le blog sur la AWS sécurité.

**Note**  
Le CMM de mise en cache applique tous les seuils suivants. Si vous ne spécifiez pas de valeur facultative, le CMM de mise en cache utilise la valeur par défaut.  
Pour désactiver temporairement la mise en cache des clés de données, les implémentations Java et Python AWS Encryption SDK fournissent un cache de *matériaux cryptographiques nul (cache* nul). Le cache nul renvoie un message d'échec pour chaque demande `GET` et ne répond pas aux demandes `PUT`. Nous vous recommandons d'utiliser le cache nul au lieu de la définir la [capacité de cache](data-caching-details.md#simplecache) ou les seuils de sécurité à 0. Pour plus d'informations, consultez le cache nul dans [Java](https://aws.github.io/aws-encryption-sdk-java/com/amazonaws/encryptionsdk/caching/NullCryptoMaterialsCache.html) and [Python](https://aws-encryption-sdk-python.readthedocs.io/en/latest/generated/aws_encryption_sdk.caches.null.html).

**Âge maximum (obligatoire)**  
Détermine la durée pendant laquelle une entrée mise en cache peut être utilisée, à partir du moment où elle a été ajoutée. Cette valeur est obligatoire. Saisissez une valeur supérieure à 0. AWS Encryption SDK Cela ne limite pas la valeur d'âge maximale.  
Toutes les implémentations linguistiques du AWS Encryption SDK définissent l'âge maximum en secondes, à l'exception du Kit SDK de chiffrement AWS pour JavaScript, qui utilise des millisecondes.  
Utilisez l'intervalle le plus court qui permet cependant à votre application de tirer parti du cache. Vous pouvez utiliser le seuil d'âge maximal comme une stratégie de rotation des clés. Utilisez-le pour limiter la réutilisation des clés de données, minimiser l'exposition des matériaux de chiffrement et expulser les clés de données dont les stratégies ont pu être modifiées pendant qu'elles étaient mises en cache.

**Nombre maximal de messages chiffrés (facultatif)**  
Spécifie le nombre maximal de messages qu'une clé de données mise en cache peut chiffrer. Cette valeur est facultative. Saisissez une valeur comprise entre 1 et 2^32 messages. La valeur par défaut est 2^32 messages.  
Définissez le nombre de messages protégés par chaque clé mise en cache de sorte qu'il soit suffisamment grand pour obtenir des valeurs par la réutilisation, mais suffisamment petit pour limiter le nombre de messages pouvant être exposés si une clé est compromise.

**Nombre maximal d'octets chiffrés (facultatif)**  
Spécifie le nombre maximal d'octets qu'une clé de données mise en cache peut chiffrer. Cette valeur est facultative. Saisissez une valeur comprise entre 0 et 2^63 - 1. La valeur par défaut est 2^63 - 1. Une valeur de 0 vous permet d'utiliser la mise en cache des clés de données uniquement lorsque vous chiffrez des chaînes de message vides.  
Les octets de la demande en cours sont inclus lors de l'évaluation de ce seuil. Si le nombre d'octets traités plus le nombre d'octets en cours dépassent le seuil, la clé de données mise en cache est expulsée du cache, même si elle aurait pu être utilisée pour une demande plus petite. 

# Détails de la mise en cache des clés de données
<a name="data-caching-details"></a>

La plupart des applications peuvent utiliser l'implémentation par défaut de la mise en cache des clés de données sans écrire de code personnalisé. Cette section décrit l'implémentation par défaut, ainsi que certaines informations sur les options. 

**Topics**
+ [Fonctionnement de la mise en cache des clés de données](#how-caching-works)
+ [Création d'un cache de matériaux de chiffrement](#simplecache)
+ [Création d'un gestionnaire des matériaux de chiffrement de mise en cache](#caching-cmm)
+ [Qu'est-ce qu'une entrée de cache de clé de données ?](#cache-entries)
+ [Contexte de chiffrement : sélection des entrées de cache](#caching-encryption-context)
+ [Mon application utilise-t-elle des clés de données mises en cache ?](#caching-effect)

## Fonctionnement de la mise en cache des clés de données
<a name="how-caching-works"></a>

Lorsque vous utilisez la mise en cache des clés de données dans une demande afin de chiffrer ou déchiffrer des données, le kit AWS Encryption SDK cherche d'abord dans le cache une clé de données correspondant à la demande. Si le kit trouve une correspondance valide, il utilise la clé de données mise en cache pour chiffrer les données. Sinon, il génère une nouvelle clé de données, comme il le ferait en l'absence de cache. 

La mise en cache des clés de données n'est pas utilisée pour les données de taille inconnue, par exemple les données diffusées. Cela permet au CMM de mise en cache d'appliquer correctement le seuil [maximal d'octets](thresholds.md). Pour éviter ce comportement, ajoutez la taille du message à la demande de chiffrement. 

Outre le cache, la mise en cache des clés de données utilise un [gestionnaire de matériel cryptographique de mise en cache](#caching-cmm) (CMM de mise en cache). [Le CMM de mise en cache est un [gestionnaire de matériaux cryptographiques (CMM)](concepts.md#crypt-materials-manager) spécialisé qui interagit avec un [cache](#simplecache) et un CMM sous-jacent.](concepts.md#crypt-materials-manager) (Lorsque vous spécifiez un [fournisseur de clés principales](concepts.md#master-key-provider) ou un trousseau de clés, un CMM par défaut est AWS Encryption SDK créé pour vous.) Le CMM de mise en cache met en cache les clés de données renvoyées par le CMM sous-jacent. Le CMM de mise en cache applique également les seuils de sécurité du cache que vous définissez. 

Pour éviter que la mauvaise clé de données ne soit sélectionnée dans le cache, toutes les mises en cache compatibles CMMs nécessitent que les propriétés suivantes du matériel cryptographique mis en cache correspondent au matériel demandé.
+ [Suite d'algorithmes](concepts.md#crypto-algorithm)
+ [Contexte de chiffrement](#caching-encryption-context) (même lorsqu'il est vide)
+ Nom de partition (chaîne identifiant le CMM de mise en cache)
+ (Déchiffrement uniquement) Clés de données de chiffrement

**Note**  
Les clés de données ne sont mises en AWS Encryption SDK cache que lorsque la [suite d'algorithmes](concepts.md#crypto-algorithm) utilise une fonction de [dérivation de clés](https://en.wikipedia.org/wiki/Key_derivation_function).

Les flux de travail suivants illustrent le traitement d'une demande de chiffrement de données avec et sans mise en cache des clés de données. Ils montrent comment les composants de mise en cache que vous créez, notamment le cache et le CMM de mise en cache, sont utilisés dans le processus.

### Chiffrement de données sans mise en cache
<a name="workflow-wo-cache"></a>

Pour obtenir les matériaux de chiffrement sans mise en cache :

1. Une application demande de AWS Encryption SDK chiffrer les données. 

   La demande indique un fournisseur de clés principales ou un trousseau de clés. AWS Encryption SDK crée un CMM par défaut qui interagit avec votre fournisseur de clés principales ou votre trousseau de clés.

1. Il AWS Encryption SDK demande au CMM du matériel de chiffrement (obtenir du matériel cryptographique).

1. Le CMM demande du matériel cryptographique à son [trousseau de clés](concepts.md#keyring) (C et JavaScript) ou à son [fournisseur de clés principales](concepts.md#master-key-provider) (Java et Python). Cela peut impliquer un appel à un service cryptographique, tel que AWS Key Management Service (AWS KMS). Le CMM renvoie le matériel de chiffrement au AWS Encryption SDK.

1.  AWS Encryption SDK Utilise la clé de données en texte brut pour chiffrer les données. Il stocke les données chiffrées et des clés de données chiffrées dans un [message chiffré](concepts.md#message), qu'il renvoie à l'utilisateur.

![\[Chiffrement de données sans mise en cache\]](http://docs.aws.amazon.com/fr_fr/encryption-sdk/latest/developer-guide/images/encrypt-workflow-no-cache.png)


### Chiffrement de données avec mise en cache
<a name="workflow-with-cache"></a>

Pour obtenir les matériaux de chiffrement sans mise en cache de clé de données :

1. Une application demande de AWS Encryption SDK chiffrer les données. 

   La demande spécifie un [gestionnaire de matériel cryptographique de mise en cache (CMM de mise en cache)](#caching-cmm) qui est associé à un gestionnaire de matériel cryptographique (CMM) sous-jacent. Lorsque vous spécifiez un fournisseur de clés principales ou un trousseau de clés, un CMM par défaut est AWS Encryption SDK créé pour vous.

1. Le SDK demande au CMM de mise en cache spécifié le matériel de chiffrement.

1. Le CMM de mise en cache demande du matériel de chiffrement à partir du cache.

   1. Si le cache trouve une correspondance, il met à jour les valeurs d'âge et d'utilisation de l'entrée de cache correspondante et renvoie les matériaux de chiffrement mis en cache au CMM de mise en cache. 

      Si l'entrée du cache est conforme à ses [seuils de sécurité](thresholds.md), le CMM de mise en cache la renvoie au SDK. Dans le cas contraire, il indique au cache d'expulser l'entrée et poursuit comme s'il n'y avait pas de correspondance.

   1. Si le cache ne trouve pas de correspondance valide, le CMM de mise en cache demande à son CMM sous-jacent de générer une nouvelle clé de données. 

      Le CMM sous-jacent obtient le matériel cryptographique auprès de son trousseau de clés (C et JavaScript) ou de son fournisseur de clés principales (Java et Python). Pour cela, il peut être nécessaire d'appeler un service, comme AWS Key Management Service. Le CMM sous-jacent renvoie le texte clair et les copies chiffrées de la clé de données au CMM de mise en cache. 

      Le CMM de mise en cache enregistre les nouveaux matériaux de chiffrement dans le cache.

1. Le CMM de mise en cache renvoie les matériaux de chiffrement au. AWS Encryption SDK

1.  AWS Encryption SDK Utilise la clé de données en texte brut pour chiffrer les données. Il stocke les données chiffrées et des clés de données chiffrées dans un [message chiffré](concepts.md#message), qu'il renvoie à l'utilisateur.

![\[Chiffrement de données avec la mise en cache des clés de données\]](http://docs.aws.amazon.com/fr_fr/encryption-sdk/latest/developer-guide/images/encrypt-workflow-with-cache.png)


## Création d'un cache de matériaux de chiffrement
<a name="simplecache"></a>

 AWS Encryption SDK définit les exigences relatives à un cache de matériel cryptographique utilisé pour la mise en cache de clés de données. Il fournit également un cache local, qui est un cache configurable, en mémoire, le [moins récemment utilisé (LRU)](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_Recently_Used_.28LRU.29). Pour créer une instance du cache local, utilisez le `LocalCryptoMaterialsCache` constructeur en Java et Python, la getLocalCryptographic MaterialsCache fonction en JavaScript ou le `aws_cryptosdk_materials_cache_local_new` constructeur en C.

Le cache local inclut une logique pour la gestion de base du cache, y compris l'ajout, l'expulsion et la mise en correspondance des entrées mises en cache, ainsi que la maintenance du cache. Vous n'avez pas besoin d'écrire une logique de gestion de cache personnalisée. Vous pouvez utiliser le cache local tel quel, le personnaliser ou le remplacer par un cache compatible. 

Lorsque vous créez un cache local, vous définissez sa *capacité*, c'est-à-dire le nombre maximum d'entrées que le cache peut contenir. Ce paramètre vous permet de concevoir un cache efficace avec une réutilisation des clés de données limitée.

Les Kit SDK de chiffrement AWS pour Java et fournissent Kit SDK de chiffrement AWS pour Python également un *cache de matériaux cryptographiques nul* (NullCryptoMaterialsCache). Le NullCryptoMaterialsCache renvoie un échec pour toutes les `GET` opérations et ne répond pas aux `PUT` opérations. Vous pouvez l' NullCryptoMaterialsCache utiliser pour tester ou pour désactiver temporairement la mise en cache dans une application qui inclut du code de mise en cache. 

Dans le AWS Encryption SDK, chaque cache de matériel cryptographique est associé à un [gestionnaire de matériel cryptographique de mise en cache](#caching-cmm) (CMM de mise en cache). Le CMM de mise en cache obtient les clés de données du cache, les place dans le cache et applique les [seuils de sécurité](thresholds.md) que vous définissez. Lorsque vous créez un CMM de mise en cache, vous spécifiez le cache qu'il utilise et le CMM sous-jacent ou le fournisseur de clés principales qui génère les clés de données qu'il met en cache.

## Création d'un gestionnaire des matériaux de chiffrement de mise en cache
<a name="caching-cmm"></a>

Pour activer la mise en cache des clés de données, vous devez créer un [cache](#simplecache) et un *gestionnaire de matériel cryptographique de mise en cache* (CMM de mise en cache). [[Ensuite, dans vos demandes de chiffrement ou de déchiffrement de données, vous spécifiez un CMM de mise en cache, au lieu d'un [gestionnaire de matériel cryptographique (CMM)](concepts.md#crypt-materials-manager) standard, d'un fournisseur de clés principales ou d'un trousseau de clés.](concepts.md#keyring)](concepts.md#master-key-provider)

Il existe deux types de CMMs. Les deux récupèrent des clés de données (et les matériaux de chiffrement associés), mais de différentes façons, comme indiqué ci-dessous :
+ Un CMM est associé à un trousseau de clés (C ou JavaScript) ou à un fournisseur de clés principales (Java et Python). Lorsque le SDK demande au CMM du matériel de chiffrement ou de déchiffrement, le CMM obtient le matériel auprès de son trousseau de clés ou de son fournisseur de clés principales. Dans Java et Python, le CMM utilise ensuite les clés principales pour générer, chiffrer ou déchiffrer les clés de données. En C et C JavaScript, le trousseau de clés génère, chiffre et renvoie le matériel cryptographique.
+ Un CMM de mise en cache est associé à un cache, tel qu'un [cache local](#simplecache), et à un CMM sous-jacent. Lorsque le SDK demande au CMM de mise en cache des documents cryptographiques, le CMM de mise en cache essaie de les extraire du cache. S'il ne trouve pas de correspondance, le CMM de mise en cache demande les matériaux à son CMM sous-jacent. Il met ensuite en cache les nouveaux matériaux cryptographiques avant de les renvoyer au mandataire. 

Le CMM de mise en cache applique également les [seuils de sécurité](thresholds.md) que vous définissez pour chaque entrée de cache. Étant donné que les seuils de sécurité sont définis et appliqués par le CMM de mise en cache, vous pouvez utiliser n'importe quel cache compatible, même s'il n'est pas conçu pour le matériel sensible.

## Qu'est-ce qu'une entrée de cache de clé de données ?
<a name="cache-entries"></a>

La mise en cache des clés de données stocke les clés de données et les matériaux de chiffrement connexes dans un cache. Chaque entrée comprend les éléments répertoriés ci-dessous. Ces informations peuvent vous être utiles lorsque vous décidez d'utiliser la fonctionnalité de mise en cache des clés de données et lorsque vous définissez des seuils de sécurité pour un gestionnaire de matériel cryptographique de mise en cache (CMM de mise en cache).

**Entrées mises en cache pour les demandes de chiffrement**  
Les entrées qui sont ajoutées à un cache de clé de données suite à une opération de chiffrement incluent les éléments suivants :
+ Clé de données en texte brut
+ Clés de données chiffrées (une ou plusieurs)
+ [Contexte de chiffrement](#caching-encryption-context) 
+ Clé de signature de message (le cas échéant)
+ [Suite d'algorithmes](concepts.md#crypto-algorithm)
+ Métadonnées, y compris les compteurs d'utilisation pour appliquer les seuils de sécurité

**Entrées mises en cache pour les demandes de déchiffrement**  
Les entrées qui sont ajoutées à un cache de clé de données suite à une opération de déchiffrement incluent les éléments suivants :
+ Clé de données en texte brut
+ Clé de vérification de signature (le cas échéant)
+ Métadonnées, y compris les compteurs d'utilisation pour appliquer les seuils de sécurité

## Contexte de chiffrement : sélection des entrées de cache
<a name="caching-encryption-context"></a>

Vous pouvez spécifier un contexte de chiffrement dans toute demande afin de chiffrer des données. Toutefois, le contexte de chiffrement joue un rôle particulier dans la mise en cache des clés de données. Il vous permet de créer des sous-groupes de clés de données dans votre cache, même lorsque les clés de données proviennent du même CMM de mise en cache.

Un [contexte de chiffrement](concepts.md#encryption-context) est un ensemble de paires clé-valeur contenant les données non secrètes arbitraires. Pendant le chiffrement, le contexte de chiffrement est lié de façon chiffrée aux données chiffrées. Le même contexte de chiffrement est donc requis pour déchiffrer les données. Dans le AWS Encryption SDK, le contexte de chiffrement est stocké dans le [message crypté](concepts.md#message) avec les données chiffrées et les clés de données. 

Lorsque vous utilisez un cache de clé de données, vous pouvez également utiliser le contexte de chiffrement pour sélectionner des clés de données mises en cache particulières pour vos opérations de chiffrement. Le contexte de chiffrement est enregistré dans l'entrée de cache avec la clé de données (il fait partie de l'ID de l'entrée de cache). Les clés de données mises en cache sont réutilisées uniquement en cas de correspondance de leurs contextes de chiffrement. Si vous souhaitez réutiliser certaines clés de données pour une demande de chiffrement, spécifiez le même contexte de chiffrement. Si vous souhaitez éviter ces clés de données, spécifiez un autre contexte de chiffrement. 

Le contexte de chiffrement est toujours facultatif, mais il est recommandé. Si vous ne spécifiez pas de contexte de chiffrement dans votre demande, un contexte de chiffrement vide est inclus dans l'ID de l'entrée de cache et associé à chaque demande.

## Mon application utilise-t-elle des clés de données mises en cache ?
<a name="caching-effect"></a>

La mise en cache des clés de données est une stratégie d'optimisation très efficace pour certaines applications et charges de travail. Cependant, comme cela comporte un certain risque, il est important de déterminer dans quelle mesure il est susceptible d'être efficace pour votre situation, puis de décider si les avantages l'emportent sur les risques.

Étant donné que la mise en cache des clés de données réutilise les clés de données, l'effet le plus évident est de réduire le nombre d'appels pour générer de nouvelles clés de données. Lorsque la mise en cache des clés de données est implémentée, l' AWS KMS `GenerateDataKey`opération n' AWS Encryption SDK appelle l'opération que pour créer la clé de données initiale et lorsque le cache est manquant. Mais la mise en cache améliore les performances de manière perceptible uniquement dans les applications qui génèrent de nombreuses clés de données avec les mêmes caractéristiques, y compris le même contexte de chiffrement et la même suite d'algorithmes.

Pour déterminer si votre implémentation du AWS Encryption SDK utilise réellement des clés de données provenant du cache, essayez les techniques suivantes.
+ Dans les journaux de votre infrastructure de clés principales, vérifiez la fréquence des appels pour créer de nouvelles clés de données. Lorsque la mise en cache des clés de données est efficace, le nombre d'appels pour créer de nouvelles clés doit diminuer sensiblement. Par exemple, si vous utilisez un fournisseur de clés AWS KMS principales ou un trousseau de clés, recherchez les [GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)appels dans les CloudTrail journaux. 
+ Comparez les [messages chiffrés](concepts.md#message) renvoyés par AWS Encryption SDK en réponse à différentes demandes de chiffrement. Par exemple, si vous utilisez le Kit SDK de chiffrement AWS pour Java, comparez l'[ParsedCiphertext](https://aws.github.io/aws-encryption-sdk-java/com/amazonaws/encryptionsdk/ParsedCiphertext.html)objet issu de différents appels de chiffrement. Dans le Kit SDK de chiffrement AWS pour JavaScript, comparez le contenu de la `encryptedDataKeys` propriété du [MessageHeader](https://github.com/aws/aws-encryption-sdk-javascript/blob/master/modules/serialize/src/types.ts#L21). Lorsque les clés de données sont réutilisées, les clés de données chiffrées dans le message chiffré sont identiques.

# Exemple de mise en cache des clés de données
<a name="sample-cache-example"></a>

Cet exemple utilise la [mise en cache des clés de données](data-key-caching.md) avec un [cache local](data-caching-details.md#simplecache) pour accélérer une application dans laquelle les données générées par plusieurs appareils sont chiffrées et stockées dans différentes régions.

Dans ce scénario, plusieurs producteurs de données génèrent des données, les chiffrent et les écrivent dans un flux [Kinesis](https://aws.amazon.com/kinesis/streams/) dans chaque région. [AWS Lambda](https://aws.amazon.com/lambda/)les fonctions (consommateurs) déchiffrent les flux et écrivent des données en texte brut dans une table DynamoDB de la région. Les producteurs de données et les consommateurs utilisent le fournisseur de clés [AWS KMS principales AWS Encryption SDK et un fournisseur de clés principales](concepts.md#master-key-provider). Pour réduire le nombre d'appels à KMS, chaque producteur et consommateur dispose de son propre cache local.

Vous pouvez trouver le code source de ces exemples en [Java et Python](sample-cache-example-code.md). L'échantillon inclut également un CloudFormation modèle qui définit les ressources pour les échantillons.

![\[Ce diagramme montre comment les producteurs et les consommateurs de données utilisent Amazon Kinesis Data Streams et Amazon DynamoDB. AWS KMS\]](http://docs.aws.amazon.com/fr_fr/encryption-sdk/latest/developer-guide/images/simplecache-example.png)


## Résultats du cache local
<a name="caching-example-impact"></a>

Le tableau suivant montre qu'un cache local réduit le nombre total d'appels à KMS (par seconde et par région) dans cet exemple à 1 % de sa valeur d'origine.


**Demandes de producteurs**  
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/fr_fr/encryption-sdk/latest/developer-guide/sample-cache-example.html)


**Demandes de consommateurs**  
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/fr_fr/encryption-sdk/latest/developer-guide/sample-cache-example.html)

# Exemple de code de mise en cache des clés de données
<a name="sample-cache-example-code"></a>

Cet exemple de code crée une implémentation simple de la mise en cache des clés de données avec un [cache local](data-caching-details.md#simplecache) en Java et Python. Le code crée deux instances d'un cache local : l'une pour les [producteurs de données](#caching-producer) qui chiffrent les données et l'autre pour [les consommateurs de données](#caching-consumer) (AWS Lambda fonctions) qui les déchiffrent. Pour plus de détails sur l'implémentation de la mise en cache des clés de données dans chaque langage, consultez la [documentation [Javadoc et](https://aws.github.io/aws-encryption-sdk-java/) Python](https://aws-encryption-sdk-python.readthedocs.io/en/latest/) du. AWS Encryption SDK

La mise en cache des clés de données est disponible pour tous les [langages de programmation](programming-languages.md) pris en AWS Encryption SDK charge. 

Pour des exemples complets et testés d'utilisation de la mise en cache des clés de données dans le AWS Encryption SDK, voir :
+ C/C\$1\$1 : [caching\$1cmm.cpp](https://github.com/aws/aws-encryption-sdk-c/blob/master/examples/caching_cmm.cpp) 
+ Java : [SimpleDataKeyCachingExample.java](https://github.com/aws/aws-encryption-sdk-java/blob/master/src/examples/java/com/amazonaws/crypto/examples/v2/SimpleDataKeyCachingExample.java)
+ JavaScript Navigateur : [caching\$1cmm.ts](https://github.com/aws/aws-encryption-sdk-javascript/blob/master/modules/example-browser/src/caching_cmm.ts) 
+ JavaScript Node.js : [caching\$1cmm.ts](https://github.com/aws/aws-encryption-sdk-javascript/blob/master/modules/example-node/src/caching_cmm.ts) 
+ Python : [data\$1key\$1caching\$1basic.py](https://github.com/aws/aws-encryption-sdk-python/blob/master/examples/src/legacy/data_key_caching_basic.py)

## Producer
<a name="caching-producer"></a>

[Le producteur obtient une carte, la convertit en JSON, l'utilise AWS Encryption SDK pour la chiffrer et envoie l'enregistrement de texte chiffré vers un flux Kinesis dans chacune d'elles.](https://aws.amazon.com/kinesis/streams/) Région AWS

[Le code définit un [gestionnaire de matériel cryptographique de mise](data-caching-details.md#caching-cmm) en cache (CMM de mise en cache) et l'associe à un [cache local et à un fournisseur](data-caching-details.md#simplecache) de clé principale sous-jacent AWS KMS .](concepts.md#master-key-provider) Le CMM de mise en cache met en cache les clés de données (et le [matériel cryptographique associé](data-caching-details.md#cache-entries)) provenant du fournisseur de clé principale. Il interagit également avec le cache au nom du kit SDK et applique les seuils de sécurité que vous définissez. 

Étant donné que l'appel à la méthode de chiffrement spécifie un CMM de mise en cache, au lieu d'un [gestionnaire de matériel cryptographique (CMM)](concepts.md#crypt-materials-manager) ou d'un fournisseur de clé principale standard, le chiffrement utilisera la mise en cache des clés de données.

------
#### [ Java ]

L'exemple suivant utilise la version 2. *x* du Kit SDK de chiffrement AWS pour Java. Version 3. *x* du rend Kit SDK de chiffrement AWS pour Java obsolète le CMM de mise en cache des clés de données. Avec la version 3. *x*, vous pouvez également utiliser le trousseau de [clés AWS KMS hiérarchique](use-hierarchical-keyring.md), une solution alternative de mise en cache des matériaux cryptographiques.

```
/*
 * Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
 * in compliance with the License. A copy of the License is located at
 *
 * http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package com.amazonaws.crypto.examples.kinesisdatakeycaching;

import com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.CommitmentPolicy;
import com.amazonaws.encryptionsdk.CryptoResult;
import com.amazonaws.encryptionsdk.MasterKeyProvider;
import com.amazonaws.encryptionsdk.caching.CachingCryptoMaterialsManager;
import com.amazonaws.encryptionsdk.caching.LocalCryptoMaterialsCache;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKey;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKeyProvider;
import com.amazonaws.encryptionsdk.multi.MultipleProviderFactory;
import com.amazonaws.util.json.Jackson;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.core.SdkBytes;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.kinesis.KinesisClient;
import software.amazon.awssdk.services.kms.KmsClient;

/**
 * Pushes data to Kinesis Streams in multiple Regions.
 */
public class MultiRegionRecordPusher {

    private static final long MAX_ENTRY_AGE_MILLISECONDS = 300000;
    private static final long MAX_ENTRY_USES = 100;
    private static final int MAX_CACHE_ENTRIES = 100;
    private final String streamName_;
    private final ArrayList<KinesisClient> kinesisClients_;
    private final CachingCryptoMaterialsManager cachingMaterialsManager_;
    private final AwsCrypto crypto_;

    /**
     * Creates an instance of this object with Kinesis clients for all target Regions and a cached
     * key provider containing KMS master keys in all target Regions.
     */
    public MultiRegionRecordPusher(final Region[] regions, final String kmsAliasName,
        final String streamName) {
        streamName_ = streamName;
        crypto_ = AwsCrypto.builder()
            .withCommitmentPolicy(CommitmentPolicy.RequireEncryptRequireDecrypt)
            .build();
        kinesisClients_ = new ArrayList<>();

        AwsCredentialsProvider credentialsProvider = DefaultCredentialsProvider.builder().build();

        // Build KmsMasterKey and AmazonKinesisClient objects for each target region
        List<KmsMasterKey> masterKeys = new ArrayList<>();
        for (Region region : regions) {
            kinesisClients_.add(KinesisClient.builder()
                .credentialsProvider(credentialsProvider)
                .region(region)
                .build());

            KmsMasterKey regionMasterKey = KmsMasterKeyProvider.builder()
                .defaultRegion(region)
                .builderSupplier(() -> KmsClient.builder().credentialsProvider(credentialsProvider))
                .buildStrict(kmsAliasName)
                .getMasterKey(kmsAliasName);

            masterKeys.add(regionMasterKey);
        }

        // Collect KmsMasterKey objects into single provider and add cache
        MasterKeyProvider<?> masterKeyProvider = MultipleProviderFactory.buildMultiProvider(
            KmsMasterKey.class,
            masterKeys
        );

        cachingMaterialsManager_ = CachingCryptoMaterialsManager.newBuilder()
            .withMasterKeyProvider(masterKeyProvider)
            .withCache(new LocalCryptoMaterialsCache(MAX_CACHE_ENTRIES))
            .withMaxAge(MAX_ENTRY_AGE_MILLISECONDS, TimeUnit.MILLISECONDS)
            .withMessageUseLimit(MAX_ENTRY_USES)
            .build();
    }

    /**
     * JSON serializes and encrypts the received record data and pushes it to all target streams.
     */
    public void putRecord(final Map<Object, Object> data) {
        String partitionKey = UUID.randomUUID().toString();
        Map<String, String> encryptionContext = new HashMap<>();
        encryptionContext.put("stream", streamName_);

        // JSON serialize data
        String jsonData = Jackson.toJsonString(data);

        // Encrypt data
        CryptoResult<byte[], ?> result = crypto_.encryptData(
            cachingMaterialsManager_,
            jsonData.getBytes(),
            encryptionContext
        );
        byte[] encryptedData = result.getResult();

        // Put records to Kinesis stream in all Regions
        for (KinesisClient regionalKinesisClient : kinesisClients_) {
            regionalKinesisClient.putRecord(builder ->
                builder.streamName(streamName_)
                    .data(SdkBytes.fromByteArray(encryptedData))
                    .partitionKey(partitionKey));
        }
    }
}
```

------
#### [ Python ]

```
"""
Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 
Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
in compliance with the License. A copy of the License is located at
 
https://aws.amazon.com/apache-2-0/
 
or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
"""
import json
import uuid
 
from aws_encryption_sdk import EncryptionSDKClient, StrictAwsKmsMasterKeyProvider, CachingCryptoMaterialsManager, LocalCryptoMaterialsCache, CommitmentPolicy
from aws_encryption_sdk.key_providers.kms import KMSMasterKey
import boto3
 
 
class MultiRegionRecordPusher(object):
    """Pushes data to Kinesis Streams in multiple Regions."""
    CACHE_CAPACITY = 100
    MAX_ENTRY_AGE_SECONDS = 300.0
    MAX_ENTRY_MESSAGES_ENCRYPTED = 100
 
    def __init__(self, regions, kms_alias_name, stream_name):
        self._kinesis_clients = []
        self._stream_name = stream_name
 
        # Set up EncryptionSDKClient
        _client = EncryptionSDKClient(CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT)
 
        # Set up KMSMasterKeyProvider with cache
        _key_provider = StrictAwsKmsMasterKeyProvider(kms_alias_name)
 
        # Add MasterKey and Kinesis client for each Region
        for region in regions:
            self._kinesis_clients.append(boto3.client('kinesis', region_name=region))
            regional_master_key = KMSMasterKey(
                client=boto3.client('kms', region_name=region),
                key_id=kms_alias_name
            )
            _key_provider.add_master_key_provider(regional_master_key)
 
        cache = LocalCryptoMaterialsCache(capacity=self.CACHE_CAPACITY)
        self._materials_manager = CachingCryptoMaterialsManager(
            master_key_provider=_key_provider,
            cache=cache,
            max_age=self.MAX_ENTRY_AGE_SECONDS,
            max_messages_encrypted=self.MAX_ENTRY_MESSAGES_ENCRYPTED
        )
 
    def put_record(self, record_data):
        """JSON serializes and encrypts the received record data and pushes it to all target streams.
 
        :param dict record_data: Data to write to stream
        """
        # Kinesis partition key to randomize write load across stream shards
        partition_key = uuid.uuid4().hex
 
        encryption_context = {'stream': self._stream_name}
 
        # JSON serialize data
        json_data = json.dumps(record_data)
 
        # Encrypt data
        encrypted_data, _header = _client.encrypt(
            source=json_data,
            materials_manager=self._materials_manager,
            encryption_context=encryption_context
        )
 
        # Put records to Kinesis stream in all Regions
        for client in self._kinesis_clients:
            client.put_record(
                StreamName=self._stream_name,
                Data=encrypted_data,
                PartitionKey=partition_key
            )
```

------

## Consommateur
<a name="caching-consumer"></a>

Le consommateur de données est une [AWS Lambda](https://aws.amazon.com/lambda/)fonction déclenchée par des événements [Kinesis](https://aws.amazon.com/kinesis/). [Il déchiffre et désérialise chaque enregistrement, puis écrit l'enregistrement en texte brut dans une table Amazon DynamoDB de la même région.](https://aws.amazon.com/dynamodb/)

À l'instar du code producteur, le code consommateur permet la mise en cache des clés de données en utilisant un gestionnaire de matériel cryptographique de mise en cache (CMM de mise en cache) lors des appels à la méthode de déchiffrement. 

Le code Java crée un fournisseur de clé principale en *mode strict* avec une valeur spécifiée AWS KMS key. [Le mode strict n'est pas obligatoire lors du déchiffrement, mais il s'agit d'une bonne pratique.](best-practices.md#strict-discovery-mode) Le code Python utilise le *mode découverte*, qui permet d' AWS Encryption SDK utiliser n'importe quelle clé d'encapsulation qui a chiffré une clé de données pour la déchiffrer.

------
#### [ Java ]

L'exemple suivant utilise la version 2. *x* du Kit SDK de chiffrement AWS pour Java. Version 3. *x* du rend Kit SDK de chiffrement AWS pour Java obsolète le CMM de mise en cache des clés de données. Avec la version 3. *x*, vous pouvez également utiliser le trousseau de [clés AWS KMS hiérarchique](use-hierarchical-keyring.md), une solution alternative de mise en cache des matériaux cryptographiques.

Ce code crée un fournisseur de clé principale pour le déchiffrement en mode strict. Ils ne AWS Encryption SDK peuvent utiliser que celui que AWS KMS keys vous spécifiez pour déchiffrer votre message.

```
/*
 * Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
 * in compliance with the License. A copy of the License is located at
 *
 * http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package com.amazonaws.crypto.examples.kinesisdatakeycaching;

import com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.CommitmentPolicy;
import com.amazonaws.encryptionsdk.CryptoResult;
import com.amazonaws.encryptionsdk.caching.CachingCryptoMaterialsManager;
import com.amazonaws.encryptionsdk.caching.LocalCryptoMaterialsCache;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKeyProvider;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.events.KinesisEvent;
import com.amazonaws.services.lambda.runtime.events.KinesisEvent.KinesisEventRecord;
import com.amazonaws.util.BinaryUtils;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;

/**
 * Decrypts all incoming Kinesis records and writes records to DynamoDB.
 */
public class LambdaDecryptAndWrite {

    private static final long MAX_ENTRY_AGE_MILLISECONDS = 600000;
    private static final int MAX_CACHE_ENTRIES = 100;
    private final CachingCryptoMaterialsManager cachingMaterialsManager_;
    private final AwsCrypto crypto_;
    private final DynamoDbTable<Item> table_;

    /**
     * Because the cache is used only for decryption, the code doesn't set the max bytes or max
     * message security thresholds that are enforced only on on data keys used for encryption.
     */
    public LambdaDecryptAndWrite() {
        String kmsKeyArn = System.getenv("CMK_ARN");
        cachingMaterialsManager_ = CachingCryptoMaterialsManager.newBuilder()
            .withMasterKeyProvider(KmsMasterKeyProvider.builder().buildStrict(kmsKeyArn))
            .withCache(new LocalCryptoMaterialsCache(MAX_CACHE_ENTRIES))
            .withMaxAge(MAX_ENTRY_AGE_MILLISECONDS, TimeUnit.MILLISECONDS)
            .build();

        crypto_ = AwsCrypto.builder()
            .withCommitmentPolicy(CommitmentPolicy.RequireEncryptRequireDecrypt)
            .build();

        String tableName = System.getenv("TABLE_NAME");
        DynamoDbEnhancedClient dynamodb = DynamoDbEnhancedClient.builder().build();
        table_ = dynamodb.table(tableName, TableSchema.fromClass(Item.class));
    }

    /**
     * @param event
     * @param context
     */
    public void handleRequest(KinesisEvent event, Context context)
        throws UnsupportedEncodingException {
        for (KinesisEventRecord record : event.getRecords()) {
            ByteBuffer ciphertextBuffer = record.getKinesis().getData();
            byte[] ciphertext = BinaryUtils.copyAllBytesFrom(ciphertextBuffer);

            // Decrypt and unpack record
            CryptoResult<byte[], ?> plaintextResult = crypto_.decryptData(cachingMaterialsManager_,
                ciphertext);

            // Verify the encryption context value
            String streamArn = record.getEventSourceARN();
            String streamName = streamArn.substring(streamArn.indexOf("/") + 1);
            if (!streamName.equals(plaintextResult.getEncryptionContext().get("stream"))) {
                throw new IllegalStateException("Wrong Encryption Context!");
            }

            // Write record to DynamoDB
            String jsonItem = new String(plaintextResult.getResult(), StandardCharsets.UTF_8);
            System.out.println(jsonItem);
            table_.putItem(Item.fromJSON(jsonItem));
        }
    }

    private static class Item {

        static Item fromJSON(String jsonText) {
            // Parse JSON and create new Item
            return new Item();
        }
    }
}
```

------
#### [ Python ]

Ce code Python est déchiffré avec un fournisseur de clé principale en mode découverte. Il permet d' AWS Encryption SDK utiliser n'importe quelle clé d'encapsulation qui a chiffré une clé de données pour la déchiffrer. Le mode strict, dans lequel vous spécifiez les clés d'encapsulation qui peuvent être utilisées pour le déchiffrement, est une [bonne pratique](best-practices.md#strict-discovery-mode).

```
"""
Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 
Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
in compliance with the License. A copy of the License is located at
 
https://aws.amazon.com/apache-2-0/
 
or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
"""
import base64
import json
import logging
import os
 
from aws_encryption_sdk import EncryptionSDKClient, DiscoveryAwsKmsMasterKeyProvider, CachingCryptoMaterialsManager, LocalCryptoMaterialsCache, CommitmentPolicy
import boto3
 
_LOGGER = logging.getLogger(__name__)
_is_setup = False
CACHE_CAPACITY = 100
MAX_ENTRY_AGE_SECONDS = 600.0
 
def setup():
    """Sets up clients that should persist across Lambda invocations."""
    global encryption_sdk_client
    encryption_sdk_client = EncryptionSDKClient(CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT)
 
    global materials_manager
    key_provider = DiscoveryAwsKmsMasterKeyProvider()
    cache = LocalCryptoMaterialsCache(capacity=CACHE_CAPACITY)
           
    #  Because the cache is used only for decryption, the code doesn't set
    #   the max bytes or max message security thresholds that are enforced
    #   only on on data keys used for encryption.
    materials_manager = CachingCryptoMaterialsManager(
        master_key_provider=key_provider,
        cache=cache,
        max_age=MAX_ENTRY_AGE_SECONDS
    )
    global table
    table_name = os.environ.get('TABLE_NAME')
    table = boto3.resource('dynamodb').Table(table_name)
    global _is_setup
    _is_setup = True
 
 
def lambda_handler(event, context):
    """Decrypts all incoming Kinesis records and writes records to DynamoDB."""
    _LOGGER.debug('New event:')
    _LOGGER.debug(event)
    if not _is_setup:
        setup()
    with table.batch_writer() as batch:
        for record in event.get('Records', []):
            # Record data base64-encoded by Kinesis
            ciphertext = base64.b64decode(record['kinesis']['data'])
 
            # Decrypt and unpack record
            plaintext, header = encryption_sdk_client.decrypt(
                source=ciphertext,
                materials_manager=materials_manager
            )
            item = json.loads(plaintext)
 
            # Verify the encryption context value
            stream_name = record['eventSourceARN'].split('/', 1)[1]
            if stream_name != header.encryption_context['stream']:
                raise ValueError('Wrong Encryption Context!')
 
            # Write record to DynamoDB
            batch.put_item(Item=item)
```

------

# Exemple de mise en cache de clés de données : modèle CloudFormation
<a name="sample-cache-example-cloudformation"></a>

Ce CloudFormation modèle met en place toutes les AWS ressources nécessaires pour reproduire l'[exemple de mise en cache des clés de données](sample-cache-example.md).

------
#### [ JSON ]

```
{
    "Parameters": {
        "SourceCodeBucket": {
            "Type": "String",
            "Description": "S3 bucket containing Lambda source code zip files"
        },
        "PythonLambdaS3Key": {
            "Type": "String",
            "Description": "S3 key containing Python Lambda source code zip file"
        },
        "PythonLambdaObjectVersionId": {
            "Type": "String",
            "Description": "S3 version id for S3 key containing Python Lambda source code zip file"
        },
        "JavaLambdaS3Key": {
            "Type": "String",
            "Description": "S3 key containing Python Lambda source code zip file"
        },
        "JavaLambdaObjectVersionId": {
            "Type": "String",
            "Description": "S3 version id for S3 key containing Python Lambda source code zip file"
        },
        "KeyAliasSuffix": {
            "Type": "String",
            "Description": "Suffix to use for KMS key Alias (ie: alias/KeyAliasSuffix)"
        },
        "StreamName": {
            "Type": "String",
            "Description": "Name to use for Kinesis Stream"
        }
    },
    "Resources": {
        "InputStream": {
            "Type": "AWS::Kinesis::Stream",
            "Properties": {
                "Name": {
                    "Ref": "StreamName"
                },
                "ShardCount": 2
            }
        },
        "PythonLambdaOutputTable": {
            "Type": "AWS::DynamoDB::Table",
            "Properties": {
                "AttributeDefinitions": [
                    {
                        "AttributeName": "id",
                        "AttributeType": "S"
                    }
                ],
                "KeySchema": [
                    {
                        "AttributeName": "id",
                        "KeyType": "HASH"
                    }
                ],
                "ProvisionedThroughput": {
                    "ReadCapacityUnits": 1,
                    "WriteCapacityUnits": 1
                }
            }
        },
        "PythonLambdaRole": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",		 	 	 
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Principal": {
                                "Service": "lambda.amazonaws.com"
                            },
                            "Action": "sts:AssumeRole"
                        }
                    ]
                },
                "ManagedPolicyArns": [
                    "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
                ],
                "Policies": [
                    {
                        "PolicyName": "PythonLambdaAccess",
                        "PolicyDocument": {
                            "Version": "2012-10-17",		 	 	 
                            "Statement": [
                                {
                                    "Effect": "Allow",
                                    "Action": [
                                        "dynamodb:DescribeTable",
                                        "dynamodb:BatchWriteItem"
                                    ],
                                    "Resource": {
                                        "Fn::Sub": "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${PythonLambdaOutputTable}"
                                    }
                                },
                                {
                                    "Effect": "Allow",
                                    "Action": [
                                        "dynamodb:PutItem"
                                    ],
                                    "Resource": {
                                        "Fn::Sub": "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${PythonLambdaOutputTable}*"
                                    }
                                },
                                {
                                    "Effect": "Allow",
                                    "Action": [
                                        "kinesis:GetRecords",
                                        "kinesis:GetShardIterator",
                                        "kinesis:DescribeStream",
                                        "kinesis:ListStreams"
                                    ],
                                    "Resource": {
                                        "Fn::Sub": "arn:aws:kinesis:${AWS::Region}:${AWS::AccountId}:stream/${InputStream}"
                                    }
                                }
                            ]
                        }
                    }
                ]
            }
        },
        "PythonLambdaFunction": {
            "Type": "AWS::Lambda::Function",
            "Properties": {
                "Description": "Python consumer",
                "Runtime": "python2.7",
                "MemorySize": 512,
                "Timeout": 90,
                "Role": {
                    "Fn::GetAtt": [
                        "PythonLambdaRole",
                        "Arn"
                    ]
                },
                "Handler": "aws_crypto_examples.kinesis_datakey_caching.consumer.lambda_handler",
                "Code": {
                    "S3Bucket": {
                        "Ref": "SourceCodeBucket"
                    },
                    "S3Key": {
                        "Ref": "PythonLambdaS3Key"
                    },
                    "S3ObjectVersion": {
                        "Ref": "PythonLambdaObjectVersionId"
                    }
                },
                "Environment": {
                    "Variables": {
                        "TABLE_NAME": {
                            "Ref": "PythonLambdaOutputTable"
                        }
                    }
                }
            }
        },
        "PythonLambdaSourceMapping": {
            "Type": "AWS::Lambda::EventSourceMapping",
            "Properties": {
                "BatchSize": 1,
                "Enabled": true,
                "EventSourceArn": {
                    "Fn::Sub": "arn:aws:kinesis:${AWS::Region}:${AWS::AccountId}:stream/${InputStream}"
                },
                "FunctionName": {
                    "Ref": "PythonLambdaFunction"
                },
                "StartingPosition": "TRIM_HORIZON"
            }
        },
        "JavaLambdaOutputTable": {
            "Type": "AWS::DynamoDB::Table",
            "Properties": {
                "AttributeDefinitions": [
                    {
                        "AttributeName": "id",
                        "AttributeType": "S"
                    }
                ],
                "KeySchema": [
                    {
                        "AttributeName": "id",
                        "KeyType": "HASH"
                    }
                ],
                "ProvisionedThroughput": {
                    "ReadCapacityUnits": 1,
                    "WriteCapacityUnits": 1
                }
            }
        },
        "JavaLambdaRole": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",		 	 	 
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Principal": {
                                "Service": "lambda.amazonaws.com"
                            },
                            "Action": "sts:AssumeRole"
                        }
                    ]
                },
                "ManagedPolicyArns": [
                    "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
                ],
                "Policies": [
                    {
                        "PolicyName": "JavaLambdaAccess",
                        "PolicyDocument": {
                            "Version": "2012-10-17",		 	 	 
                            "Statement": [
                                {
                                    "Effect": "Allow",
                                    "Action": [
                                        "dynamodb:DescribeTable",
                                        "dynamodb:BatchWriteItem"
                                    ],
                                    "Resource": {
                                        "Fn::Sub": "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${JavaLambdaOutputTable}"
                                    }
                                },
                                {
                                    "Effect": "Allow",
                                    "Action": [
                                        "dynamodb:PutItem"
                                    ],
                                    "Resource": {
                                        "Fn::Sub": "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${JavaLambdaOutputTable}*"
                                    }
                                },
                                {
                                    "Effect": "Allow",
                                    "Action": [
                                        "kinesis:GetRecords",
                                        "kinesis:GetShardIterator",
                                        "kinesis:DescribeStream",
                                        "kinesis:ListStreams"
                                    ],
                                    "Resource": {
                                        "Fn::Sub": "arn:aws:kinesis:${AWS::Region}:${AWS::AccountId}:stream/${InputStream}"
                                    }
                                }
                            ]
                        }
                    }
                ]
            }
        },
        "JavaLambdaFunction": {
            "Type": "AWS::Lambda::Function",
            "Properties": {
                "Description": "Java consumer",
                "Runtime": "java8",
                "MemorySize": 512,
                "Timeout": 90,
                "Role": {
                    "Fn::GetAtt": [
                        "JavaLambdaRole",
                        "Arn"
                    ]
                },
                "Handler": "com.amazonaws.crypto.examples.kinesisdatakeycaching.LambdaDecryptAndWrite::handleRequest",
                "Code": {
                    "S3Bucket": {
                        "Ref": "SourceCodeBucket"
                    },
                    "S3Key": {
                        "Ref": "JavaLambdaS3Key"
                    },
                    "S3ObjectVersion": {
                        "Ref": "JavaLambdaObjectVersionId"
                    }
                },
                "Environment": {
                    "Variables": {
                        "TABLE_NAME": {
                            "Ref": "JavaLambdaOutputTable"
                        },
                        "CMK_ARN": {
                            "Fn::GetAtt": [
                                "RegionKinesisCMK",
                                "Arn"
                            ]
                        }
                    }
                }
            }
        },
        "JavaLambdaSourceMapping": {
            "Type": "AWS::Lambda::EventSourceMapping",
            "Properties": {
                "BatchSize": 1,
                "Enabled": true,
                "EventSourceArn": {
                    "Fn::Sub": "arn:aws:kinesis:${AWS::Region}:${AWS::AccountId}:stream/${InputStream}"
                },
                "FunctionName": {
                    "Ref": "JavaLambdaFunction"
                },
                "StartingPosition": "TRIM_HORIZON"
            }
        },
        "RegionKinesisCMK": {
            "Type": "AWS::KMS::Key",
            "Properties": {
                "Description": "Used to encrypt data passing through Kinesis Stream in this region",
                "Enabled": true,
                "KeyPolicy": {
                    "Version": "2012-10-17",		 	 	 
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Principal": {
                                "AWS": {
                                    "Fn::Sub": "arn:aws:iam::${AWS::AccountId}:root"
                                }
                            },
                            "Action": [
                                "kms:Encrypt",
                                "kms:GenerateDataKey",
                                "kms:CreateAlias",
                                "kms:DeleteAlias",
                                "kms:DescribeKey",
                                "kms:DisableKey",
                                "kms:EnableKey",
                                "kms:PutKeyPolicy",
                                "kms:ScheduleKeyDeletion",
                                "kms:UpdateAlias",
                                "kms:UpdateKeyDescription"
                            ],
                            "Resource": "*"
                        },
                        {
                            "Effect": "Allow",
                            "Principal": {
                                "AWS": [
                                    {
                                        "Fn::GetAtt": [
                                            "PythonLambdaRole",
                                            "Arn"
                                        ]
                                    },
                                    {
                                        "Fn::GetAtt": [
                                            "JavaLambdaRole",
                                            "Arn"
                                        ]
                                    }
                                ]
                            },
                            "Action": "kms:Decrypt",
                            "Resource": "*"
                        }
                    ]
                }
            }
        },
        "RegionKinesisCMKAlias": {
            "Type": "AWS::KMS::Alias",
            "Properties": {
                "AliasName": {
                    "Fn::Sub": "alias/${KeyAliasSuffix}"
                },
                "TargetKeyId": {
                    "Ref": "RegionKinesisCMK"
                }
            }
        }
    }
}
```

------
#### [ YAML ]

```
Parameters:
    SourceCodeBucket:
        Type: String
        Description: S3 bucket containing Lambda source code zip files
    PythonLambdaS3Key:
        Type: String
        Description: S3 key containing Python Lambda source code zip file
    PythonLambdaObjectVersionId:
        Type: String
        Description: S3 version id for S3 key containing Python Lambda source code zip file
    JavaLambdaS3Key:
        Type: String
        Description: S3 key containing Python Lambda source code zip file
    JavaLambdaObjectVersionId:
        Type: String
        Description: S3 version id for S3 key containing Python Lambda source code zip file
    KeyAliasSuffix:
        Type: String
        Description: 'Suffix to use for KMS CMK Alias (ie: alias/<KeyAliasSuffix>)'
    StreamName:
        Type: String
        Description: Name to use for Kinesis Stream
Resources:
    InputStream:
        Type: AWS::Kinesis::Stream
        Properties:
            Name: !Ref StreamName
            ShardCount: 2
    PythonLambdaOutputTable:
        Type: AWS::DynamoDB::Table
        Properties:
            AttributeDefinitions:
                -
                    AttributeName: id
                    AttributeType: S
            KeySchema:
                -
                    AttributeName: id
                    KeyType: HASH
            ProvisionedThroughput:
                ReadCapacityUnits: 1
                WriteCapacityUnits: 1
    PythonLambdaRole:
        Type: AWS::IAM::Role
        Properties:
            AssumeRolePolicyDocument:
                Version: 2012-10-17
                Statement:
                    -
                        Effect: Allow
                        Principal:
                            Service: lambda.amazonaws.com
                        Action: sts:AssumeRole
            ManagedPolicyArns:
                - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
            Policies:
                -
                    PolicyName: PythonLambdaAccess
                    PolicyDocument:
                        Version: 2012-10-17
                        Statement:
                            -
                                Effect: Allow
                                Action:
                                    - dynamodb:DescribeTable
                                    - dynamodb:BatchWriteItem
                                Resource: !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${PythonLambdaOutputTable}
                            -
                                Effect: Allow
                                Action:
                                    - dynamodb:PutItem
                                Resource: !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${PythonLambdaOutputTable}*
                            -
                                Effect: Allow
                                Action:
                                    - kinesis:GetRecords
                                    - kinesis:GetShardIterator
                                    - kinesis:DescribeStream
                                    - kinesis:ListStreams
                                Resource: !Sub arn:aws:kinesis:${AWS::Region}:${AWS::AccountId}:stream/${InputStream}
    PythonLambdaFunction:
        Type: AWS::Lambda::Function
        Properties:
            Description: Python consumer
            Runtime: python2.7
            MemorySize: 512
            Timeout: 90
            Role: !GetAtt PythonLambdaRole.Arn
            Handler: aws_crypto_examples.kinesis_datakey_caching.consumer.lambda_handler
            Code:
                S3Bucket: !Ref SourceCodeBucket
                S3Key: !Ref PythonLambdaS3Key
                S3ObjectVersion: !Ref PythonLambdaObjectVersionId
            Environment:
                Variables:
                    TABLE_NAME: !Ref PythonLambdaOutputTable
    PythonLambdaSourceMapping:
        Type: AWS::Lambda::EventSourceMapping
        Properties:
            BatchSize: 1
            Enabled: true
            EventSourceArn: !Sub arn:aws:kinesis:${AWS::Region}:${AWS::AccountId}:stream/${InputStream}
            FunctionName: !Ref PythonLambdaFunction
            StartingPosition: TRIM_HORIZON
    JavaLambdaOutputTable:
        Type: AWS::DynamoDB::Table
        Properties:
            AttributeDefinitions:
                -
                    AttributeName: id
                    AttributeType: S
            KeySchema:
                -
                    AttributeName: id
                    KeyType: HASH
            ProvisionedThroughput:
                ReadCapacityUnits: 1
                WriteCapacityUnits: 1
    JavaLambdaRole:
        Type: AWS::IAM::Role
        Properties:
            AssumeRolePolicyDocument:
                Version: 2012-10-17
                Statement:
                    -
                        Effect: Allow
                        Principal:
                            Service: lambda.amazonaws.com
                        Action: sts:AssumeRole
            ManagedPolicyArns:
                - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
            Policies:
                -
                    PolicyName: JavaLambdaAccess
                    PolicyDocument:
                        Version: 2012-10-17
                        Statement:
                            -
                                Effect: Allow
                                Action:
                                    - dynamodb:DescribeTable
                                    - dynamodb:BatchWriteItem
                                Resource: !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${JavaLambdaOutputTable}
                            -
                                Effect: Allow
                                Action:
                                    - dynamodb:PutItem
                                Resource: !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${JavaLambdaOutputTable}*
                            -
                                Effect: Allow
                                Action:
                                    - kinesis:GetRecords
                                    - kinesis:GetShardIterator
                                    - kinesis:DescribeStream
                                    - kinesis:ListStreams
                                Resource: !Sub arn:aws:kinesis:${AWS::Region}:${AWS::AccountId}:stream/${InputStream}
    JavaLambdaFunction:
        Type: AWS::Lambda::Function
        Properties:
            Description: Java consumer
            Runtime: java8
            MemorySize: 512
            Timeout: 90
            Role: !GetAtt JavaLambdaRole.Arn
            Handler: com.amazonaws.crypto.examples.kinesisdatakeycaching.LambdaDecryptAndWrite::handleRequest
            Code:
                S3Bucket: !Ref SourceCodeBucket
                S3Key: !Ref JavaLambdaS3Key
                S3ObjectVersion: !Ref JavaLambdaObjectVersionId
            Environment:
                Variables:
                    TABLE_NAME: !Ref JavaLambdaOutputTable
                    CMK_ARN: !GetAtt RegionKinesisCMK.Arn
    JavaLambdaSourceMapping:
        Type: AWS::Lambda::EventSourceMapping
        Properties:
            BatchSize: 1
            Enabled: true
            EventSourceArn: !Sub arn:aws:kinesis:${AWS::Region}:${AWS::AccountId}:stream/${InputStream}
            FunctionName: !Ref JavaLambdaFunction
            StartingPosition: TRIM_HORIZON
    RegionKinesisCMK:
        Type: AWS::KMS::Key
        Properties:
            Description: Used to encrypt data passing through Kinesis Stream in this region
            Enabled: true
            KeyPolicy:
                Version: 2012-10-17
                Statement:
                    -
                        Effect: Allow
                        Principal:
                            AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
                        Action:
                            # Data plane actions
                            - kms:Encrypt
                            - kms:GenerateDataKey
                            # Control plane actions
                            - kms:CreateAlias
                            - kms:DeleteAlias
                            - kms:DescribeKey
                            - kms:DisableKey
                            - kms:EnableKey
                            - kms:PutKeyPolicy
                            - kms:ScheduleKeyDeletion
                            - kms:UpdateAlias
                            - kms:UpdateKeyDescription
                        Resource: '*'
                    -
                        Effect: Allow
                        Principal:
                            AWS:
                                - !GetAtt PythonLambdaRole.Arn
                                - !GetAtt JavaLambdaRole.Arn
                        Action: kms:Decrypt
                        Resource: '*'
    RegionKinesisCMKAlias:
        Type: AWS::KMS::Alias
        Properties:
            AliasName: !Sub alias/${KeyAliasSuffix}
            TargetKeyId: !Ref RegionKinesisCMK
```

------