

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Armazenamento em cache de chaves de dados
<a name="data-key-caching"></a>

O *armazenamento em cache de chaves de dados* armazena [chaves de dados](concepts.md#DEK) e o [material criptográfico relacionado](data-caching-details.md#cache-entries) em um cache. Quando você criptografa ou descriptografa dados, ele AWS Encryption SDK procura uma chave de dados correspondente no cache. Se encontrar uma correspondência, ele usará a chave de dados armazenada em cache em vez de gerar uma nova. O armazenamento em cache de chaves de dados pode melhorar o desempenho, reduzir os custos e ajudar você a manter os limites do serviço à medida que seu aplicativo é escalado. 

O aplicativo poderá se beneficiar do armazenamento em cache de chaves de dados se:
+ Puder reutilizar chaves de dados.
+ Gerar várias chaves de dados. 
+ As operações de criptografia estiverem inaceitavelmente lentas, caras, limitadas ou usarem recursos de forma intensiva.

O armazenamento em cache pode reduzir o uso de serviços criptográficos, como AWS Key Management Service ()AWS KMS. Se você está atingindo seu [AWS KMS requests-per-secondlimite](https://docs.aws.amazon.com/kms/latest/developerguide/limits.html#requests-per-second), o armazenamento em cache pode ajudar. Seu aplicativo pode usar chaves em cache para atender a algumas de suas solicitações de chave de dados em vez de chamar AWS KMS. (Você também pode criar um caso no [AWS Support Center](https://console.aws.amazon.com/support/home#/) para aumentar o limite da conta.)

 AWS Encryption SDK Isso ajuda você a criar e gerenciar seu cache de chaves de dados. Ele fornece um [cache local](data-caching-details.md#simplecache) e um [gerenciador de armazenamento em cache de materiais criptográficos](data-caching-details.md#caching-cmm) (CMM de armazenamento em cache) que interage com o cache e impõe [limites de segurança](thresholds.md) definidos por você. Juntos, esses componentes ajudam você a se beneficiar da eficiência de reutilização de chaves de dados mantendo a segurança do sistema.

O armazenamento em cache da chave de dados é um recurso opcional do AWS Encryption SDK que você deve usar com cautela. Por padrão, AWS Encryption SDK gera uma nova chave de dados para cada operação de criptografia. Essa técnica é compatível com as melhores práticas criptográficas, que desencorajam a reutilização excessiva de chaves de dados. Em geral, use o armazenamento em cache de chaves de dados somente quando ele for necessário para atender às suas metas de desempenho. Em seguida, use os [limites de segurança](thresholds.md) do armazenamento em cache de chaves de dados para garantir que você use a quantidade mínima de armazenamento em cache necessário para atender a suas metas de desempenho e custo. 

Versão 3. *x* of the suporta AWS Encryption SDK for Java apenas o CMM de armazenamento em cache com a interface antiga de provedores de chaves mestras, não a interface de chaveiro. No entanto, versão 4. *x* e versões posteriores do AWS Encryption SDK para .NET, versão 3. *x* do AWS Encryption SDK for Java, versão 4. *x* do AWS Encryption SDK for Python, versão 1. *x* do AWS Encryption SDK para Rust e versão 0.1. *x* ou versões posteriores do AWS Encryption SDK for Go suportam o [AWS KMS chaveiro hierárquico](use-hierarchical-keyring.md), uma solução alternativa de cache de materiais criptográficos. O conteúdo criptografado com o AWS KMS chaveiro hierárquico só pode ser descriptografado com o chaveiro hierárquico. AWS KMS 

Para ver uma discussão detalhada dessas vantagens e desvantagens de segurança, consulte [AWS Encryption SDK: Como decidir se o armazenamento em cache de chaves de dados é ideal para sua aplicação](https://aws.amazon.com/blogs/security/aws-encryption-sdk-how-to-decide-if-data-key-caching-is-right-for-your-application/) no Blog de segurança da AWS .

**Topics**
+ [Como usar o armazenamento em cache de chaves de dados](implement-caching.md)
+ [Definir limites de segurança do cache](thresholds.md)
+ [Detalhes do armazenamento em cache de chaves de dados](data-caching-details.md)
+ [Exemplo de armazenamento em cache de chaves de dados](sample-cache-example.md)

# Como usar o armazenamento em cache de chaves de dados
<a name="implement-caching"></a>

Este tópico mostra como usar o armazenamento em cache de chaves de dados em seu aplicativo. Ele fornece uma demonstração passo a passo do processo. Em seguida, ele combina as etapas em um exemplo simples que usa o armazenamento em cache da chave de dados em uma operação para criptografar uma string.

Esses exemplos mostram como usar a versão 2.0.[*x*](about-versions.md) e versões posteriores do AWS Encryption SDK. Para exemplos que usam versões anteriores, encontre sua versão na lista de [lançamentos](https://github.com/aws/aws-encryption-sdk-c/releases) do GitHub repositório da sua [linguagem de programação](programming-languages.md).

Para obter exemplos completos e testados do uso do armazenamento em cache de chaves de dados no AWS Encryption SDK, consulte:
+ 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 Navegador: [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)

O [AWS Encryption SDK para .NET](dot-net.md) não oferece é compatível com o cache de chaves de dados.

**Topics**
+ [Usando o cache de chaves de dados: Step-by-step](#implement-caching-steps)
+ [Armazenamento em cache de chaves de dados de exemplo: criptografar uma string](#caching-example-encrypt-string)

## Usando o cache de chaves de dados: Step-by-step
<a name="implement-caching-steps"></a>

Essas step-by-step instruções mostram como criar os componentes necessários para implementar o armazenamento em cache de chaves de dados.
+ [Crie um cache de chave de dados](data-caching-details.md#simplecache). Nesses exemplos, usamos o cache local que o AWS Encryption SDK fornece. Limitamos o cache a 10 chaves de dados.

   

------
#### [ 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 ]

  O exemplo a seguir usa a versão 2. *x* do AWS Encryption SDK for Java. Versão 3. *x* do AWS Encryption SDK for Java desaprova o CMM de armazenamento em cache da chave de dados. Com a versão 3. *x*, você também pode usar o [AWS KMS chaveiro hierárquico](use-hierarchical-keyring.md), uma solução alternativa de cache de materiais criptográficos.

  ```
  // 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)
  ```

------

   
+ Crie um [provedor de chave mestra](concepts.md#master-key-provider) (Java e Python) ou um [chaveiro](concepts.md#keyring) (C e). JavaScript Esses exemplos usam um provedor de chave mestra AWS Key Management Service (AWS KMS) ou um [AWS KMS chaveiro](use-kms-keyring.md) compatível.

   

------
#### [ 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 ]

  O exemplo a seguir usa a versão 2. *x* do AWS Encryption SDK for Java. Versão 3. *x* do AWS Encryption SDK for Java desaprova o CMM de armazenamento em cache da chave de dados. Com a versão 3. *x*, você também pode usar o [AWS KMS chaveiro hierárquico](use-hierarchical-keyring.md), uma solução alternativa de cache de materiais criptográficos.

  ```
  // 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 ]

  No navegador, você deve injetar suas credenciais com segurança. Este exemplo define credenciais em um webpack (kms.webpack.config) que resolve credenciais no runtime. Ele cria uma instância AWS KMS cliente-provedor a partir de um AWS KMS cliente e das credenciais. Então, ao criar o chaveiro, ele passa o provedor do cliente para o construtor junto com o 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])
  ```

------

   
+ [Crie um gerenciador de armazenamento em cache de materiais criptográficos](data-caching-details.md#caching-cmm) (CMM de armazenamento em cache). 

   

  Associe o CMM de armazenamento em cache ao seu cache e seu provedor de chaves mestras. Em seguida, [defina os limites de segurança do cache](thresholds.md) no CMM de armazenamento em cache. 

   

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

  No AWS Encryption SDK for C, você pode criar um CMM de cache a partir de um CMM subjacente, como o CMM padrão, ou de um chaveiro. Este exemplo cria o CMM de armazenamento em cache de um token de autenticação.

  Depois de criar o CMM de armazenamento em cache, você pode liberar suas referências para o token de autenticação e o cache. Para obter detalhes, consulte [Contagem de referências](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 ]

  O exemplo a seguir usa a versão 2. *x* do AWS Encryption SDK for Java. Versão 3. *x* of the AWS Encryption SDK for Java não oferece suporte ao cache de chaves de dados, mas suporta o [AWS KMS chaveiro hierárquico](use-hierarchical-keyring.md), uma solução alternativa de cache de materiais criptográficos.

  ```
  /*
   * 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
  )
  ```

------

Isso é tudo o que você precisa fazer. Em seguida, deixe que AWS Encryption SDK eles gerenciem o cache para você ou adicione sua própria lógica de gerenciamento de cache.

Quando desejar usar o armazenamento em cache de chaves de dados em uma chamada para criptografar ou descriptografar dados, especifique o CMM de armazenamento em cache em vez de especificar um provedor de chaves mestras ou outro CMM.

**nota**  
Se estiver criptografando streamings de dados ou quaisquer dados de tamanho desconhecido, certifique-se de especificar o tamanho dos dados na solicitação. O AWS Encryption SDK não usa cache de chave de dados ao criptografar dados de tamanho desconhecido.

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

No AWS Encryption SDK for C, você cria uma sessão com o CMM de cache e, em seguida, processa a sessão. 

Por padrão, quando o tamanho da mensagem é desconhecido e ilimitado, as chaves de dados AWS Encryption SDK não são armazenadas em cache. Para permitir o armazenamento em cache quando não se sabe o tamanho exato dos dados, use o método `aws_cryptosdk_session_set_message_bound` para definir o tamanho máximo da mensagem. Defina o vínculo maior do que o tamanho estimado da mensagem. Se o tamanho real da mensagem exceder o vínculo, ocorrerá uma falha na operação da criptografia.

```
/* 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 ]

O exemplo a seguir usa a versão 2. *x* do AWS Encryption SDK for Java. Versão 3. *x* do AWS Encryption SDK for Java desaprova o CMM de armazenamento em cache da chave de dados. Com a versão 3. *x*, você também pode usar o [AWS KMS chaveiro hierárquico](use-hierarchical-keyring.md), uma solução alternativa de cache de materiais criptográficos.

```
// 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 ]

Quando você usa o CMM de cache no AWS Encryption SDK para JavaScript for Node.js, o `encrypt` método requer o tamanho do texto simples. Se você não fornecer, a chave de dados não será armazenada em cache. Se você fornecer um tamanho, mas os dados de texto simples fornecidos excederem esse tamanho, a operação de criptografia falhará. Se você não souber o tamanho exato do texto simples, como quando estiver fazendo streaming de dados, forneça o maior valor esperado.

```
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
)
```

------

## Armazenamento em cache de chaves de dados de exemplo: criptografar uma string
<a name="caching-example-encrypt-string"></a>

Este código de exemplo simples usa o armazenamento em cache de chaves de dados ao criptografar uma string. Ele combina o código do [step-by-step procedimento](#implement-caching-steps) em um código de teste que você pode executar.

O exemplo cria um [cache local](data-caching-details.md#simplecache) e um [provedor de chave mestra](concepts.md#master-key-provider) ou [token de autenticação](concepts.md#keyring) para uma AWS KMS key. Em seguida, ele usa o cache local e o provedor de chaves mestras ou o token de autenticação para criar um CMM de armazenamento em cache com os [limites de segurança](thresholds.md) adequados. Em Java e em Python, a solicitação de criptografia especifica o CMM de armazenamento em cache, os dados de texto simples a serem criptografados e um [contexto de criptografia](data-caching-details.md#caching-encryption-context). Em C, o CMM de armazenamento em cache é especificado na sessão, e a sessão é fornecida para a solicitação de criptografia.

Para executar estes exemplos, você precisa fornecer o [nome do atributo da Amazon (ARN) de uma AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/viewing-keys.html). Verifique se você tem [permissão para usar a AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html#key-policy-default-allow-users) para gerar uma chave de dados.

Para obter exemplos reais mais detalhados de como criar e usar um cache de chave mestra, consulte [Exemplo de código de armazenamento em cache de chaves de dados](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 ]

O exemplo a seguir usa a versão 2. *x* do AWS Encryption SDK for Java. Versão 3. *x* do AWS Encryption SDK for Java desaprova o CMM de armazenamento em cache da chave de dados. Com a versão 3. *x*, você também pode usar o [AWS KMS chaveiro hierárquico](use-hierarchical-keyring.md), uma solução alternativa de cache de materiais criptográficos.

```
// 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
```

------

# Definir limites de segurança do cache
<a name="thresholds"></a>

Quando você implementa o armazenamento em cache de chave de dados, precisa configurar os limites de segurança impostos pelo [CMM de armazenamento em cache](data-caching-details.md#caching-cmm). 

Os limites de segurança ajudam a limitar duração do uso de cada chave de dados e o volume de dados protegido em cada chave de dados. O CMM de armazenamento em cache retorna as chaves de dados armazenadas em cache somente quando a entrada do cache estiver em conformidade com todos os limites de segurança. Se a entrada do cache exceder o limite, ela não será usada para a operação atual e será removida do cache assim que possível. O primeiro uso de cada chave de dados (antes do armazenamento em cache) é isento desses limites. 

Como regra, use a quantidade mínima de armazenamento em cache necessária para atender a suas metas de custos e de desempenho. 

O AWS Encryption SDK único armazena em cache as chaves de dados que são criptografadas usando uma função de [derivação de chave](https://en.wikipedia.org/wiki/Key_derivation_function). Além disso, ele estabelece limites máximos para alguns dos valores de limites. Essas restrições garantem que as chaves de dados não sejam reutilizadas além dos limites criptográficos. No entanto, como as chaves de dados de texto sem criptografia são armazenadas em cache (na memória, por padrão), tente minimizar o tempo em que as chaves são salvas. Além disso, tente limitar os dados que poderão ser expostos se uma chave estiver comprometida.

Para obter exemplos de como definir limites de segurança de cache, consulte [AWS Encryption SDK: Como decidir se o armazenamento em cache de chaves de dados é adequado para seu aplicativo](https://aws.amazon.com/blogs/security/aws-encryption-sdk-how-to-decide-if-data-key-caching-is-right-for-your-application/) no blog de AWS segurança.

**nota**  
O CMM do armazenamento em cache impõe todos os limites a seguir. Se você não especificar um valor opcional, o CMM de armazenamento em cache usará o valor padrão.  
Para desativar temporariamente o armazenamento em cache de chaves de dados, as implementações de Java e Python do AWS Encryption SDK fornecem um *cache de materiais criptográficos nulo * (cache nulo). O cache nulo retorna um erro para cada solicitação `GET` e não responde a solicitações `PUT`. Recomendamos usar o cache nulo em vez de definir a [capacidade do cache](data-caching-details.md#simplecache) ou os limites de segurança como 0. Para obter mais informações, consulte o cache nulo em [Java](https://aws.github.io/aws-encryption-sdk-java/com/amazonaws/encryptionsdk/caching/NullCryptoMaterialsCache.html) e [Python](https://aws-encryption-sdk-python.readthedocs.io/en/latest/generated/aws_encryption_sdk.caches.null.html).

**Idade máxima (obrigatório)**  
Determina por quanto tempo uma entrada armazenada em cache pode ser usada, a partir do momento em que foi adicionada. Este valor é obrigatório. Digite um valor maior que 0. AWS Encryption SDK Isso não limita o valor máximo de idade.  
Todas as implementações de linguagem do AWS Encryption SDK definem a idade máxima em segundos, exceto a AWS Encryption SDK para JavaScript, que usa milissegundos.  
Use o intervalo mais curto que ainda permita que seu aplicativo se beneficie do cache. Você pode usar o limite máximo de idade como uma política de rotação de chaves. Use-o para limitar a reutilização de chaves de dados, minimizar a exposição de material criptográfico e remover chaves de dados cujas políticas podem ter sido alteradas enquanto estavam armazenadas em cache.

**Número máximo de mensagens criptografadas (opcional)**  
Especifica o número máximo de mensagens que uma chave de dados armazenada em cache pode criptografar. Este valor é opcional. Digite um valor entre 1 e 2^32 mensagens. O valor padrão é 2^32 mensagens.  
Defina o número de mensagens protegidas por cada chave armazenada em cache para que seja grande o suficiente para obter o valor da reutilização, mas pequeno o suficiente para limitar o número de mensagens que podem ser expostas se uma chave for comprometida.

**Número máximo de bytes criptografados (opcional)**  
Especifica o número máximo de bytes que uma chave de dados armazenada em cache pode criptografar. Este valor é opcional. Digite um valor entre 0 e 2^63 - 1. O valor padrão é 2^63 - 1. Um valor de 0 permite usar armazenamento em cache de chaves de dados somente quando você está criptografando strings de mensagem vazias.  
Os bytes na solicitação atual são incluídos ao avaliar esse limite. Se os bytes processados, mais os bytes atuais, excederem o limite, a chave de dados armazenada em cache será removida do cache, mesmo que ela tenha sido usada em uma solicitação menor. 

# Detalhes do armazenamento em cache de chaves de dados
<a name="data-caching-details"></a>

A maioria dos aplicativos pode usar a implementação padrão do armazenamento em cache de chave de dados sem escrever código personalizado. Esta seção descreve a implementação padrão e alguns detalhes sobre as opções. 

**Topics**
+ [Como o armazenamento em cache de chaves de dados funciona](#how-caching-works)
+ [Criar um cache de material de criptografia](#simplecache)
+ [Criar um gerenciador de material de criptografia de armazenamento em cache](#caching-cmm)
+ [O que é uma entrada de chave de dados em cache?](#cache-entries)
+ [Contexto de criptografia: como selecionar entradas do cache](#caching-encryption-context)
+ [Meu aplicativo está usando chaves de dados armazenadas em cache?](#caching-effect)

## Como o armazenamento em cache de chaves de dados funciona
<a name="how-caching-works"></a>

Quando você usa o armazenamento em cache de chave de dados em uma solicitação para criptografar ou descriptografar dados, o AWS Encryption SDK primeiro pesquisa uma chave de dados no cache que corresponde à solicitação. Se localizar uma correspondência válida, ele usa a chave de dados armazenada em cache para criptografar os dados. Caso contrário, ele gerará uma nova chave de dados, da mesma forma como o faria sem o cache. 

O armazenamento em cache da chave de dados não é usado para dados de tamanho desconhecido, como streaming de dados. Isso permite que o CMM de armazenamento em cache imponha o [limite máximo de bytes](thresholds.md) corretamente. Para evitar esse comportamento, adicione o tamanho da mensagem à solicitação de criptografia. 

Além de um cache, o armazenamento em cache de chaves de dados usa [um gerenciador de armazenamento em cache de materiais criptográficos](#caching-cmm) (CMM de armazenamento em cache). O CMM de armazenamento em cache é um [ gerenciador de materiais criptográficos (CMM)](concepts.md#crypt-materials-manager) especializado que interage com um [cache](#simplecache) e um [CMM](concepts.md#crypt-materials-manager) subjacente. (Quando você especifica um [provedor de chaves mestra](concepts.md#master-key-provider) ou um token de autenticação, o AWS Encryption SDK cria um CMM padrão para você.) O CMM de armazenamento em cache armazena em cache as chaves de dados que seu CMM subjacente retorna. Também impõe limites de segurança de cache definidos por você. 

Para evitar que a chave de dados errada seja selecionada do cache, todo armazenamento em cache compatível CMMs exige que as seguintes propriedades dos materiais criptográficos em cache correspondam à solicitação de materiais.
+ [Pacote de algoritmos](concepts.md#crypto-algorithm)
+ [Contexto de criptografia](#caching-encryption-context) (mesmo quando vazio)
+ Nome da partição (uma string que identifica o CMM de armazenamento em cache)
+ (Somente descriptografia) chaves de dados criptografadas

**nota**  
O AWS Encryption SDK cache das chaves de dados somente quando o [conjunto de algoritmos](concepts.md#crypto-algorithm) usa uma função de [derivação de chave](https://en.wikipedia.org/wiki/Key_derivation_function).

Os seguintes fluxos de trabalho mostram como uma solicitação para criptografar dados é processada com e sem armazenamento em cache da chave de dados. Eles mostram como o armazenamento em cache de componentes que você cria, incluindo o cache e o CMM de armazenamento em cache, são usados no processo.

### Criptografar dados sem armazenamento em cache
<a name="workflow-wo-cache"></a>

Para obter materiais de criptografia sem armazenamento em cache:

1. Um aplicativo solicita que AWS Encryption SDK os dados sejam criptografados. 

   A solicitação especifica um provedor de chaves mestres ou um token de autenticação. O AWS Encryption SDK cria um CMM padrão que interage com a chave mestra ou com o token de autenticação.

1. Ele AWS Encryption SDK solicita ao CMM materiais de criptografia (obtenha materiais criptográficos).

1. O CMM solicita ao seu [chaveiro](concepts.md#keyring) (C e JavaScript) ou [provedor de chave mestra](concepts.md#master-key-provider) (Java e Python) materiais criptográficos. Isso pode envolver uma chamada para um serviço criptográfico, como AWS Key Management Service (AWS KMS). O CMM retorna os materiais de criptografia para o AWS Encryption SDK.

1. O AWS Encryption SDK usa a chave de dados em texto simples para criptografar os dados. Ele armazena os dados criptografados e as chaves de dados criptografadas em uma [mensagem criptografada](concepts.md#message), que ele retorna ao usuário.

![\[Criptografar dados sem armazenamento em cache\]](http://docs.aws.amazon.com/pt_br/encryption-sdk/latest/developer-guide/images/encrypt-workflow-no-cache.png)


### Criptografar dados com armazenamento em cache
<a name="workflow-with-cache"></a>

Para obter materiais de criptografia com armazenamento de chaves de dados em cache:

1. Um aplicativo solicita que AWS Encryption SDK os dados sejam criptografados. 

   A solicitação especifica um [gerenciador de armazenamento em cache materiais criptográficos (CMM de armazenamento em cache)](#caching-cmm) associado a um gerenciador de materiais criptográficos (CMM) subjacente. Quando você especifica um provedor de chaves mestras ou um token de autenticação, o AWS Encryption SDK cria um CMM padrão para você.

1. O SDK solicita ao CMM de armazenamento em cache especificado materiais de criptografia.

1. O CMM de armazenamento em cache solicita materiais de criptografia do cache.

   1. Se encontrar uma correspondência, o cache atualizará a idade e usará os valores da entrada do cache correspondente, retornando os materiais de criptografia armazenados em cache ao CMM de armazenamento em cache. 

      Se a entrada do cache estiver em conformidade com os [limites de segurança](thresholds.md), o CMM de armazenamento em cache a retorna ao SDK. Caso contrário, ele instruirá o cache a remover a entrada e prosseguir como se não houvesse correspondência.

   1. Se o cache não puder encontrar uma correspondência válida, o CMM de armazenamento em cache solicitará que CMM subjacente gere uma nova chave de dados. 

      O CMM subjacente obtém os materiais criptográficos de seu chaveiro (C e JavaScript) ou provedor de chave mestra (Java e Python). Isso pode envolver uma chamada a um serviço criptográfico, como o AWS Key Management Service. O CMM subjacente retorna o texto simples e cópias criptografadas da chave de dados ao CMM de armazenamento em cache. 

      O CMM de armazenamento em cache salva os novos materiais de criptografia no cache.

1. O CMM de armazenamento em cache retorna os materiais de criptografia para o AWS Encryption SDK.

1. O AWS Encryption SDK usa a chave de dados em texto simples para criptografar os dados. Ele armazena os dados criptografados e as chaves de dados criptografadas em uma [mensagem criptografada](concepts.md#message), que ele retorna ao usuário.

![\[Criptografar dados com a chave de dados armazenada em cache\]](http://docs.aws.amazon.com/pt_br/encryption-sdk/latest/developer-guide/images/encrypt-workflow-with-cache.png)


## Criar um cache de material de criptografia
<a name="simplecache"></a>

 AWS Encryption SDK Define os requisitos para um cache de materiais criptográficos usado no cache de chaves de dados. Também fornece um cache local, que é um [cache least recently used (LRU - menos usado recentemente)](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_Recently_Used_.28LRU.29) configurável e na memória. Para criar uma instância do cache local, use o `LocalCryptoMaterialsCache` construtor em Java e Python, getLocalCryptographic MaterialsCache a função JavaScript em ou `aws_cryptosdk_materials_cache_local_new` o construtor em C.

O cache local contém lógica para gerenciamento básico do cache, incluindo adição, remoção e correspondência de entradas armazenadas em cache e manutenção do cache. Você não precisa escrever nenhuma lógica de gerenciamento de cache personalizado. O cache local pode ser usado como está, ser personalizado ou substituído por cache compatível. 

Quando cria um cache local, você define sua *capacidade*, isto é, o número máximo de entradas que o cache pode conter. Essa configuração ajuda a criar um cache eficiente com reutilização limitada de chaves de dados.

O AWS Encryption SDK for Java e o AWS Encryption SDK for Python também fornecem um *cache de materiais criptográficos nulo* ()NullCryptoMaterialsCache. O NullCryptoMaterialsCache retorna um erro para todas `GET` as operações e não responde às `PUT` operações. Você pode usar o NullCryptoMaterialsCache em testes ou para desativar temporariamente o armazenamento em cache em um aplicativo que inclui código de armazenamento em cache. 

No AWS Encryption SDK, cada cache de materiais criptográficos é associado a um [gerenciador de materiais criptográficos em cache](#caching-cmm) (CMM). O CMM de armazenamento em cache obtém chaves de dados do cache, coloca chaves de dados no cache e impõe os [limites de segurança](thresholds.md) que você define. Ao criar umCMM de armazenamento em cache, você especifica o cache que ele usa e o CMM subjacente ou o provedor de chaves mestras que gera as chaves de dados que ele armazena em cache.

## Criar um gerenciador de material de criptografia de armazenamento em cache
<a name="caching-cmm"></a>

Para habilitar o armazenamento em cache da chave de dados, você cria um [cache](#simplecache) e um *gerenciador de armazenamento em cache* (CMM de armazenamento em cache). Em seguida, em suas solicitações para criptografar ou descriptografar dados, você especifica um CMM de armazenamento em cache em vez de um [gerenciador de materiais criptográficos (CMM)](concepts.md#crypt-materials-manager) pardão, um [provedor de chaves mestras](concepts.md#master-key-provider) ou um [token de autenticação](concepts.md#keyring).

Existem dois tipos de CMMs. Os dois obtêm chaves de dados (e o material criptográfico relacionado), mas de diferentes maneiras, da seguinte forma:
+ Uma CMM está associada a um chaveiro (C ou JavaScript) ou a um provedor de chave mestra (Java e Python). Quando o SDK solicita ao CMM materiais de criptografia ou descriptografia, o CMM obtém os materiais de seu token de autenticação ou do provedor de chaves mestras. Em Java e Python, o CMM usa as chaves mestras para gerar, criptografar ou descriptografar as chaves de dados. Em C e JavaScript, o chaveiro gera, criptografa e retorna os materiais criptográficos.
+ Um CMM de armazenamento em cache está associado a um cache, como um [cache local](#simplecache) e a um CMM subjacente. Quando o SDK solicita materiais criptográficos ao CMM de armazenamento em cache, o CMM de armazenamento em cache tenta obtê-los do cache. Se não conseguir encontrar uma correspondência, o CMM de armazenamento em cache solicitará os materiais ao seu CMM subjacente. Depois, ele armazenará os novos materiais criptográficos antes de retorná-los ao chamador. 

O CMM de armazenamento em cache também impõe [limites de segurança](thresholds.md) que você define para cada entrada do cache. Como os limites de segurança são definidos e impostos pelo CMM de armazenamento em cache, você pode usar qualquer cache compatível, mesmo que o cache não esteja projetado para material confidencial.

## O que é uma entrada de chave de dados em cache?
<a name="cache-entries"></a>

O cache de chaves de dados armazena chaves de dados e o material criptográfico relacionado em um cache. Cada entrada inclui os elementos listados a seguir. Você pode considerar essas informações úteis ao decidir se deseja usar o atributo de armazenamento em cache de chave de dados e ao configurar os limites de segurança em um gerenciador de armazenamento em cache de materiais criptográficos (CMM de armazenamento em cache).

**Entradas armazenadas em cache para solicitações de criptografia**  
As entradas adicionadas a um cache de chave de dados como resultado de uma operação de criptografia incluem os seguintes elementos:
+ Chave de dados de texto não criptografado
+ Chaves de dados criptografadas (uma ou mais)
+ [Contexto de criptografia](#caching-encryption-context) 
+ Chave de assinatura de mensagem (se uma for usada)
+ [Pacote de algoritmos](concepts.md#crypto-algorithm)
+ Metadados, incluindo contadores de uso para impor limites de segurança

**Entradas armazenadas em cache para solicitações de descriptografia**  
As entradas adicionadas a um cache de chave de dados como resultado de uma operação de descriptografia incluem os seguintes elementos:
+ Chave de dados de texto não criptografado
+ Chave de verificação de assinatura (se uma for usada)
+ Metadados, incluindo contadores de uso para impor limites de segurança

## Contexto de criptografia: como selecionar entradas do cache
<a name="caching-encryption-context"></a>

Você pode especificar um contexto de criptografia em qualquer solicitação para criptografar dados. No entanto, o contexto de criptografia desempenha uma função especial no armazenamento em cache de chaves de dados. Ele permite criar subgrupos de chaves de dados em seu cache, mesmo quando as chaves de dados forem originárias do mesmo CMM de armazenamento em cache.

Um [contexto de criptografia](concepts.md#encryption-context) é um conjunto de pares de chave-valor que contêm dados arbitrários não secretos. Durante a criptografia, o contexto de criptografia é associado de maneira criptográfica aos dados criptografados de forma que o mesmo contexto de criptografia é necessário para descriptografar os dados. No AWS Encryption SDK, o contexto de criptografia é armazenado na [mensagem criptografada](concepts.md#message) com os dados criptografados e as chaves de dados. 

Ao usar um cache de chave de dados, você também pode usar o contexto de criptografia para selecionar chaves de dados armazenadas em cache específicas para suas operações de criptografia. O contexto de criptografia é salvo na entrada do cache com a chave de dados (ele faz parte do ID de entrada do cache). As chaves de dados armazenadas em cache só são reutilizadas quando os contextos de criptografia correspondem. Se desejar reutilizar determinadas chaves de dados para uma solicitação de criptografia, especifique o mesmo contexto de criptografia. Para evitar essas chaves de dados, especifique outro contexto de criptografia. 

O contexto de criptografia é sempre opcional, mas é recomendado. Se você não especificar um contexto de criptografia na solicitação, um contexto de criptografia vazio será incluído no identificador de entrada do cache e correspondido a cada solicitação.

## Meu aplicativo está usando chaves de dados armazenadas em cache?
<a name="caching-effect"></a>

O armazenamento em cache de chaves de dados é uma estratégia de otimização muito eficaz para determinados aplicativos e cargas de trabalho. No entanto, como isso implica algum risco, é importante determinar o quão eficaz é provável que seja para a sua situação e decidir se os benefícios superam os riscos.

Como o armazenamento em cache de chaves de dados reutiliza chaves de dados, o efeito mais óbvio é a redução do número de chamadas para gerar novas chaves de dados. Quando o armazenamento em cache da chave de dados é implementado, ele AWS Encryption SDK chama a AWS KMS `GenerateDataKey` operação somente para criar a chave de dados inicial e quando o cache falha. Mas, o armazenamento em cache melhora o desempenho de forma perceptível somente em aplicativos que geram várias chaves de dados com as mesmas características, incluindo o mesmo contexto de criptografia e pacote de algoritmos.

Para determinar se sua implementação do AWS Encryption SDK está realmente usando chaves de dados do cache, experimente as técnicas a seguir.
+ Nos logs da infraestrutura de sua chave mestra, verifique a frequência de chamadas para criar novas chaves de dados. Quando o armazenamento em cache de chaves de dados está efetivo, o número de chamadas para criar novas chaves deve cair de forma perceptível. Por exemplo, se você estiver usando um provedor de chave AWS KMS mestra ou um chaveiro, pesquise [GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)chamadas nos CloudTrail registros. 
+ Compare as [mensagens criptografadas](concepts.md#message) que o AWS Encryption SDK retorna em resposta a diferentes solicitações de criptografia. Por exemplo, se você estiver usando o AWS Encryption SDK for Java, compare o [ParsedCiphertext](https://aws.github.io/aws-encryption-sdk-java/com/amazonaws/encryptionsdk/ParsedCiphertext.html)objeto de diferentes chamadas de criptografia. No AWS Encryption SDK para JavaScript, compare o conteúdo da `encryptedDataKeys` propriedade do [MessageHeader](https://github.com/aws/aws-encryption-sdk-javascript/blob/master/modules/serialize/src/types.ts#L21). Quando as chaves de dados são reutilizadas, as chaves de dados criptografadas na mensagem criptografada são idênticas.

# Exemplo de armazenamento em cache de chaves de dados
<a name="sample-cache-example"></a>

Este exemplo usa [armazenamento em cache de chaves de dados](data-key-caching.md) com um [cache local](data-caching-details.md#simplecache) para acelerar uma aplicação em que os dados gerados por vários dispositivos são criptografados e armazenados em diferentes regiões.

Nesse cenário, vários produtores de dados geram, criptografam e gravam dados em um [stream do Kinesis](https://aws.amazon.com/kinesis/streams/) em cada região. As funções do [AWS Lambda](https://aws.amazon.com/lambda/) (consumidoras) descriptografam os streams e gravam dados de texto simples em uma tabela do DynamoDB na região. Os produtores e os consumidores de dados usam o AWS Encryption SDK e um [AWS KMS provedor de chaves mestras do ](concepts.md#master-key-provider). Para reduzir as chamadas ao KMS, cada produtor e consumidor tem seu próprio armazenamento em cache local.

Você pode encontrar o código-fonte desses exemplos em [Java e Python](sample-cache-example-code.md). A amostra também inclui um CloudFormation modelo que define os recursos para as amostras.

![\[Este diagrama mostra como produtores e consumidores de dados usam o AWS KMS Amazon Kinesis Data Streams e o Amazon DynamoDB.\]](http://docs.aws.amazon.com/pt_br/encryption-sdk/latest/developer-guide/images/simplecache-example.png)


## Resultados do cache local
<a name="caching-example-impact"></a>

A tabela a seguir mostra que um armazenamento em cache local reduz o total de chamadas ao KMS (por segundo por região) neste exemplo em 1% de seu valor original.


**Solicitações de produtores**  
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/encryption-sdk/latest/developer-guide/sample-cache-example.html)


**Solicitações de consumidor**  
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/encryption-sdk/latest/developer-guide/sample-cache-example.html)

# Exemplo de código de armazenamento em cache de chaves de dados
<a name="sample-cache-example-code"></a>

Este exemplo de código cria uma implementação básica do armazenamento em cache de chaves de dados com um [cache local](data-caching-details.md#simplecache) em Java e Python. O código cria duas instâncias de um cache local: uma para [produtores de dados](#caching-producer) que estão criptografando dados e outra para [consumidores de dados](#caching-consumer) (AWS Lambda funções) que estão descriptografando dados. Para obter detalhes sobre a implementação do armazenamento em cache de chaves de dados em cada linguagem, consulte a documentação de [Javadoc](https://aws.github.io/aws-encryption-sdk-java/) e [Python](https://aws-encryption-sdk-python.readthedocs.io/en/latest/) para o AWS Encryption SDK.

O armazenamento em cache de chaves de dados está disponível para todas as [linguagens de programação](programming-languages.md) suportadas AWS Encryption SDK . 

Para obter exemplos completos e testados do uso do armazenamento em cache de chaves de dados no AWS Encryption SDK, consulte:
+ 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 Navegador: [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)

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

[O produtor obtém um mapa, o converte em JSON, usa o AWS Encryption SDK para criptografá-lo e envia o registro de texto cifrado para um stream do Kinesis em cada um.](https://aws.amazon.com/kinesis/streams/) Região da AWS

O código define um [gerenciador de materiais criptográficos de armazenamento em cache](data-caching-details.md#caching-cmm) (CMM de armazenamento em cache) e o associa a um [cache local](data-caching-details.md#simplecache) e a um [provedor de chave mestrado AWS KMS](concepts.md#master-key-provider) subjacente. O CMM de amazenamento em cache armazena em cache as chaves de dados (e o [material criptográfico relacionado](data-caching-details.md#cache-entries)) do provedor de chaves mestras. Ele também interage com o cache em nome do SDK e impõe os limites de segurança que você define. 

Como a chamada para o método de criptografia especifica um CMM de armazenamento em cache, em vez de um [gerenciador de materiais criptográficos (CMM)](concepts.md#crypt-materials-manager) ou provedor de chave mestra comum, a criptografia usará o cache de chave de dados.

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

O exemplo a seguir usa a versão 2. *x* do AWS Encryption SDK for Java. Versão 3. *x* do AWS Encryption SDK for Java desaprova o CMM de armazenamento em cache da chave de dados. Com a versão 3. *x*, você também pode usar o [AWS KMS chaveiro hierárquico](use-hierarchical-keyring.md), uma solução alternativa de cache de materiais criptográficos.

```
/*
 * 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
            )
```

------

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

O consumidor de dados é uma função do [AWS Lambda](https://aws.amazon.com/lambda/) acionada por eventos do [Kinesis](https://aws.amazon.com/kinesis/). Ele descriptografa e desserializa cada registro e grava o registro de texto simples em uma tabela do [Amazon DynamoDB](https://aws.amazon.com/dynamodb/) na mesma região.

Como o código do produtor, o código do consumidor habilita o armazenamento em cache da chave de dados usando um gerenciador de materiais criptográficos de cache (caching CMM) em chamadas para o método de descriptografia. 

O código Java cria um provedor de chave mestra no *modo estrito* com um especificado AWS KMS key. O modo estrito não é necessário ao descriptografar, mas é uma [prática recomendada.](best-practices.md#strict-discovery-mode) O código Python usa o *modo de descoberta*, que permite AWS Encryption SDK usar qualquer chave de empacotamento que criptografe uma chave de dados para descriptografá-la.

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

O exemplo a seguir usa a versão 2. *x* do AWS Encryption SDK for Java. Versão 3. *x* do AWS Encryption SDK for Java desaprova o CMM de armazenamento em cache da chave de dados. Com a versão 3. *x*, você também pode usar o [AWS KMS chaveiro hierárquico](use-hierarchical-keyring.md), uma solução alternativa de cache de materiais criptográficos.

Esse código cria um provedor de chave mestra para descriptografia no modo estrito. O AWS Encryption SDK pode usar somente o AWS KMS keys que você especificar para descriptografar sua mensagem.

```
/*
 * 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 ]

Esse código Python é descriptografado com um provedor de chave mestra no modo de descoberta. Ele permite ao AWS Encryption SDK usar qualquer chave de encapsulamento que criptografe uma chave de dados para descriptografá-la. O modo estrito, no qual você especifica as chaves de encapsulamento que podem ser usadas para decodificação, é uma [prática recomendada.](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)
```

------

# Exemplo de armazenamento em cache de chave de dados: modelo CloudFormation
<a name="sample-cache-example-cloudformation"></a>

Esse CloudFormation modelo configura todos os AWS recursos necessários para reproduzir o exemplo de armazenamento em [cache da chave de dados](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
```

------