

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 数据密钥缓存详细信息
<a name="data-caching-details"></a>

大多数应用程序可以使用默认数据密钥缓存实施，而无需编写自定义代码。本节介绍了默认实施以及有关选项的一些详细信息。

**Topics**
+ [数据密钥缓存的工作方式](#how-caching-works)
+ [创建加密材料缓存](#simplecache)
+ [创建缓存加密材料管理器](#caching-cmm)
+ [在数据密钥缓存条目中包含哪些内容？](#cache-entries)
+ [加密上下文：如何选择缓存条目](#caching-encryption-context)
+ [我的应用程序是否使用缓存的数据密钥？](#caching-effect)

## 数据密钥缓存的工作方式
<a name="how-caching-works"></a>

在加密或解密数据的请求中使用数据密钥缓存时， AWS Encryption SDK 先在缓存中搜索与请求匹配的数据密钥。如果找到有效的匹配项，它使用缓存的数据密钥加密数据。否则，它生成新的数据密钥，就像没有缓存一样。

不会在未知大小的数据中使用数据密钥缓存，如流式数据。这样缓存 CMM 就可以正确强制执行[最大字节数阈值](thresholds.md)。为了避免该行为，请将消息大小添加到加密请求中。

除缓存外，数据密钥缓存还使用[缓存加密材料管理器](#caching-cmm)（缓存 CMM）。缓存 CMM 是一种专用的[加密材料管理器（CMM）](concepts.md#crypt-materials-manager)，该管理器与[缓存](#simplecache)和基础 [CMM](concepts.md#crypt-materials-manager) 进行交互。（在指定[主密钥提供程序](concepts.md#master-key-provider)或密钥环时， AWS Encryption SDK 将创建一个默认 CMM。） 缓存 CMM 缓存其基础 CMM 返回的数据密钥。缓存 CMM 还强制执行您设置的缓存安全阈值。

为了防止从缓存中选择错误的数据密钥，所有兼容的缓存都 CMMs 要求缓存的加密材料的以下属性与材料请求相匹配。
+ [算法套件](concepts.md#crypto-algorithm)
+ [加密上下文](#caching-encryption-context)（甚至为空时）
+ 分区名称（用于标识缓存 CMM 的字符串）
+ （仅解密）加密数据密钥

**注意**  
仅当[算法套件](concepts.md#crypto-algorithm)使用密钥[派生函数时，才会 AWS Encryption SDK 缓存数据密钥](https://en.wikipedia.org/wiki/Key_derivation_function)。

以下工作流介绍了如何在缓存和不缓存数据密钥的情况下处理数据加密请求。这些工作流说明了如何在该过程中使用您创建的缓存组件，包括缓存和缓存 CMM。

### 加密数据而不进行缓存
<a name="workflow-wo-cache"></a>

获取加密材料而不缓存：

1. 应用程序要求对数据 AWS Encryption SDK 进行加密。

   该请求指定一个主密钥提供程序或密钥环。 AWS Encryption SDK 创建一个与主密钥提供程序或密钥环交互的默认 CMM。

1. 向 CMM AWS Encryption SDK 索要加密材料（获取加密材料）。

1. CMM 要求其[密钥环](concepts.md#keyring)（C 和 JavaScript）或[主密钥提供者](concepts.md#master-key-provider)（Java 和 Python）提供加密材料。这可能涉及调用加密服务，例如 AWS Key Management Service (AWS KMS)。CMM 将加密材料返回给 AWS Encryption SDK。

1.  AWS Encryption SDK 使用纯文本数据密钥对数据进行加密。它在返回给用户的[加密消息](concepts.md#message)中存储加密数据和加密数据密钥。

![\[加密数据而不进行缓存\]](http://docs.aws.amazon.com/zh_cn/encryption-sdk/latest/developer-guide/images/encrypt-workflow-no-cache.png)


### 使用缓存加密数据
<a name="workflow-with-cache"></a>

获取加密材料并且缓存数据密钥：

1. 应用程序要求对数据 AWS Encryption SDK 进行加密。

   该请求指定了与底层加密材料管理器（CMM）关联的[缓存加密材料管理器（缓存 CMM）](#caching-cmm)。如果您指定主密钥提供程序或密钥环， AWS Encryption SDK 将创建默认的 CMM。

1. 该开发工具包要求指定的缓存 CMM 提供加密材料。

1. 缓存 CMM 从缓存中请求加密材料。

   1. 如果缓存找到匹配项，将更新匹配的缓存条目的期限和使用值，并将缓存的加密材料返回给缓存 CMM。

      如果缓存条目符合其[安全阈值](thresholds.md)，则缓存 CMM 将此条目返回到该开发工具包。否则，它通知缓存逐出该条目并继续操作，就好像没有匹配项一样。

   1. 如果缓存找不到有效的匹配项，缓存 CMM 将请求其基础 CMM 生成新的数据密钥。

      底层 CMM 从其密钥环（C 和 JavaScript）或主密钥提供程序（Java 和 Python）获取加密材料。这可能涉及调用一个服务，如 AWS Key Management Service。基础 CMM 将数据密钥的明文和加密副本返回给缓存 CMM。

      缓存 CMM 在缓存中保存新的加密材料。

1. 缓存 CMM 将加密材料返回给 AWS Encryption SDK。

1.  AWS Encryption SDK 使用纯文本数据密钥对数据进行加密。它在返回给用户的[加密消息](concepts.md#message)中存储加密数据和加密数据密钥。

![\[加密数据并缓存数据密钥\]](http://docs.aws.amazon.com/zh_cn/encryption-sdk/latest/developer-guide/images/encrypt-workflow-with-cache.png)


## 创建加密材料缓存
<a name="simplecache"></a>

 AWS Encryption SDK 定义了数据密钥缓存中使用的加密材料缓存的要求。此外，缓存 CMM 还提供本地缓存，即可在内存中配置的[最近最少使用（LRU）缓存](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_Recently_Used_.28LRU.29)。要创建本地缓存的实例，请使用 Java 和 Python 中的`LocalCryptoMaterialsCache`构造函数 JavaScript、中的 getLocalCryptographicMaterialsCache 函数或 C 中的`aws_cryptosdk_materials_cache_local_new`构造函数

本地缓存包含基本缓存管理逻辑，包括添加、驱逐和匹配缓存的条目以及维护缓存。您无需编写任何自定义缓存管理逻辑。您可以按原样使用本地缓存，对其进行自定义或替换任何兼容的缓存。

在创建本地缓存时，您可以设置其*容量*，即，该缓存可以保存的最大条目数。该设置有助于设计具有有限数据密钥重用次数的高效缓存。

 AWS Encryption SDK for Java 和 AWS Encryption SDK for Python 还提供了一个*空的加密材料缓存* (NullCryptoMaterialsCache)。 NullCryptoMaterialsCache 返回所有`GET`操作的失误，并且不对`PUT`操作做出响应。可以在测试 NullCryptoMaterialsCache 中使用，也可以在包含缓存代码的应用程序中暂时禁用缓存。

在中 AWS Encryption SDK，每个加密材料缓存都与缓存[加密材料管理器（缓存](#caching-cmm) CMM）相关联。缓存 CMM 从缓存中获取数据密钥，将数据密钥放在缓存中，然后强制执行您设置的[安全阈值](thresholds.md)。在创建缓存 CMM 时，您可以指定其使用的缓存以及生成其缓存的数据密钥的基础 CMM 或主密钥提供程序。

## 创建缓存加密材料管理器
<a name="caching-cmm"></a>

要启用数据密钥缓存，您需要创建[缓存](#simplecache)和*缓存加密材料管理器*（缓存 CMM）。然后，在加密或解密数据的请求中指定缓存 CMM，而不是标准[加密材料管理器（CMM）](concepts.md#crypt-materials-manager)或[主密钥提供程序](concepts.md#master-key-provider)或[密钥环](concepts.md#keyring)。

有两种类型 CMMs。它们均获取数据密钥（和相关的加密材料），但使用不同的方法，如下所示：
+ CMM 与密钥环（C 或 JavaScript）或主密钥提供程序（Java 和 Python）相关联。当开发工具包要求 CMM 提供加密或解密材料时，CMM 从其密钥环或主密钥提供程序获取材料。在 Java 和 Python 中，CMM 使用主密钥生成、加密或解密数据密钥。在 C 和中 JavaScript，密钥环生成、加密和返回加密材料。
+ 缓存 CMM 与一个缓存（例如[本地缓存](#simplecache)）和基础 CMM 相关联。在该开发工具包请求缓存 CMM 提供加密材料时，缓存 CMM 尝试从缓存中获取这些材料。如果找不到匹配项，缓存 CMM 将请求其基础 CMM 提供材料。然后，它在向调用方返回新的加密材料之前将其缓存。

缓存 CMM 还强制执行您为每个缓存条目设置的[安全阈值](thresholds.md)。由于安全阈值是在缓存 CMM 中设置并由其强制执行的，所以您可以使用任何兼容的缓存，即使该缓存不是为敏感材料设计的。

## 在数据密钥缓存条目中包含哪些内容？
<a name="cache-entries"></a>

数据密钥缓存将数据密钥和相关的加密材料存储在缓存中。每个条目包含下面列出的元素。在决定是否使用数据密钥缓存功能以及在缓存加密材料管理器（缓存 CMM）上设置安全阈值时，您可能会发现该信息非常有用。

**为加密请求缓存的条目**  
由于加密操作而添加到数据密钥缓存的条目包括以下元素：
+ 明文数据密钥
+ 加密的数据密钥（一个或多个）
+ [加密上下文](#caching-encryption-context) 
+ 消息签名密钥（如果使用）
+ [算法套件](concepts.md#crypto-algorithm)
+ 元数据，包括用于实施安全阈值的使用计数器

**为解密请求缓存的条目**  
由于解密操作而添加到数据密钥缓存的条目包括以下元素：
+ 明文数据密钥
+ 签名验证密钥（如果使用）
+ 元数据，包括用于实施安全阈值的使用计数器

## 加密上下文：如何选择缓存条目
<a name="caching-encryption-context"></a>

您可以在任何加密数据的请求中指定加密上下文。不过，加密上下文在数据密钥缓存中起到特殊的作用。该上下文允许在您的缓存中创建数据密钥子组，即使数据密钥来自于相同的缓存 CMM。

[加密上下文](concepts.md#encryption-context)是一组包含任意非机密数据的键值对。在加密期间，加密上下文以加密方式绑定到加密的数据，以便需要使用相同的加密上下文解密数据。在中 AWS Encryption SDK，加密上下文存储在带有[加密数据和数据密钥的加密消息](concepts.md#message)中。

在使用数据密钥缓存时，您还可以使用加密上下文为加密操作选择特定的缓存数据密钥。加密上下文与数据密钥一起保存在缓存条目中（它是缓存条目 ID 的一部分）。只有在加密上下文匹配时，才会重用缓存的数据密钥。如果要在加密请求中重用某些数据密钥，请指定相同的加密上下文。如果要避免使用这些数据密钥，请指定不同的加密上下文。

加密上下文始终是可选的，但建议使用。如果在请求中未指定加密上下文，则在缓存条目标识符中包含空加密上下文并与每个请求匹配。

## 我的应用程序是否使用缓存的数据密钥？
<a name="caching-effect"></a>

数据密钥缓存是一种优化策略，对于某些应用程序和工作负载是非常有效的。不过，由于它存在一些风险，请务必确定它对您的环境可能有多有效，然后确定收益是否大于风险。

由于数据密钥缓存重复使用数据密钥，因此，最明显的效果是减少了生成新数据密钥的调用次数。当实现数据密钥缓存时，仅在缓存丢失时才 AWS Encryption SDK 调用该 AWS KMS `GenerateDataKey`操作来创建初始数据密钥。但是，仅在生成大量具有相同特性（包括相同加密上下文和算法套件）的数据密钥的应用程序中，缓存才会显著提高性能。

要确定您的实现是否实际上 AWS Encryption SDK 是在使用缓存中的数据密钥，请尝试以下技术。
+ 在主密钥基础设施的日志中，检查创建新数据密钥的调用频率。在数据密钥缓存有效时，创建新密钥的调用次数应明显减少。例如，如果您使用的是 AWS KMS 主密钥提供程序或密钥环，请在 CloudTrail 日志中搜索[GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)呼叫。
+ 比较 AWS Encryption SDK 为响应不同的加密请求而返回的[加密消息](concepts.md#message)。例如，如果您使用的是 AWS Encryption SDK for Java，请比较来自不同加密调用的[ParsedCiphertext](https://aws.github.io/aws-encryption-sdk-java/com/amazonaws/encryptionsdk/ParsedCiphertext.html)对象。在中 AWS Encryption SDK for JavaScript，比较`encryptedDataKeys`属性的内容[MessageHeader](https://github.com/aws/aws-encryption-sdk-javascript/blob/master/modules/serialize/src/types.ts#L21)。在重复使用数据密钥时，加密消息中的加密数据密钥是完全相同的。