ASP.NET Core 中的核心加密扩展性

警告

对于多个调用方,实现以下任何接口的类型应该是线程安全的。

IAuthenticatedEncryptor

IAuthenticatedEncryptor 接口是加密子系统的基本构造块。 每个密钥通常有一个 IAuthenticatedEncryptor,并且 IAuthenticatedEncryptor 实例包装了执行加密操作所需的所有加密密钥材料和算法信息。

顾名思义,该类型负责提供经过身份验证的加密和解密服务。 它公开以下两个 API。

  • Decrypt(ArraySegment<byte> ciphertext, ArraySegment<byte> additionalAuthenticatedData) : byte[]

  • Encrypt(ArraySegment<byte> plaintext, ArraySegment<byte> additionalAuthenticatedData) : byte[]

Encrypt 方法返回一个包含加密明文和身份验证标记的 blob。 身份验证标签必须包含附加的身份验证数据 (AAD),尽管 AAD 本身不需要从最终有效负载中恢复。 Decrypt 方法验证身份验证标签并返回已解密的有效负载。 所有失败(ArgumentNullException 和类似的除外)都应同质化为 CryptographicException。

注意

IAuthenticatedEncryptor 实例本身实际上并不需要包含密钥材料。 例如,实现可以将所有操作委派给 HSM。

如何创建 IAuthenticatedEncryptor

IAuthenticatedEncryptorFactory 接口表示知道如何创建 IAuthenticatedEncryptor 实例的类型。 它的 API 如下所示。

  • CreateEncryptorInstance(IKey 密钥):IAuthenticatedEncryptor

对于任何给定的 IKey 实例,由其 CreateEncryptorInstance 方法创建的任何经过身份验证的加密器都应被视为等效的,如下面的代码示例所示。

// we have an IAuthenticatedEncryptorFactory instance and an IKey instance
IAuthenticatedEncryptorFactory factory = ...;
IKey key = ...;

// get an encryptor instance and perform an authenticated encryption operation
ArraySegment<byte> plaintext = new ArraySegment<byte>(Encoding.UTF8.GetBytes("plaintext"));
ArraySegment<byte> aad = new ArraySegment<byte>(Encoding.UTF8.GetBytes("AAD"));
var encryptor1 = factory.CreateEncryptorInstance(key);
byte[] ciphertext = encryptor1.Encrypt(plaintext, aad);

// get another encryptor instance and perform an authenticated decryption operation
var encryptor2 = factory.CreateEncryptorInstance(key);
byte[] roundTripped = encryptor2.Decrypt(new ArraySegment<byte>(ciphertext), aad);


// the 'roundTripped' and 'plaintext' buffers should be equivalent

IAuthenticatedEncryptorDescriptor(仅 ASP.NET Core 2.x)

IAuthenticatedEncryptorDescriptor 接口表示知道如何将自身导出到 XML 的类型。 它的 API 如下所示。

  • ExportToXml() : XmlSerializedDescriptorInfo

XML 序列化

IAuthenticatedEncryptor 和 IAuthenticatedEncryptorDescriptor 之间的主要区别在于描述符知道如何创建加密器并为其提供有效参数。 考虑一个 IAuthenticatedEncryptor,它的实现依赖于 SymmetricAlgorithm 和 KeyedHashAlgorithm。 加密器的工作是使用这些类型,但它不一定知道这些类型来自哪里,因此它无法真正地写出正确的描述,来说明如果应用程序重新启动,应如何创建其本身。 此外,描述符还可充当更高的级别。 由于描述符知道如何创建加密器实例(例如,它知道如何创建所需的算法),因此它能够以 XML 形式序列化该知识,以便在应用程序重置后可以重新创建加密器实例。

描述符可通过其 ExportToXml 例程进行序列化。 此例程返回 XmlSerializedDescriptorInfo,其中包含两个属性:描述符的 XElement 表示形式和表示 IAuthenticatedEncryptorDescriptorDeserializer 的类型,在给定相应的 XElement 时,可用于重新生成此描述符。

序列化的描述符可能包含敏感信息,例如加密密钥材料。 数据保护系统具有对加密信息持久保存到存储之前的内置支持。 为了利用这一点,描述符应使用属性名“requiresEncryption”(xmlns "<http://schemas.asp.net/2015/03/dataProtection>") 和值“true”标记包含敏感信息的元素。

提示

有一个用于设置此属性的帮助程序 API。 调用位于命名空间 Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel 中的扩展方法 XElement.MarkAsRequiresEncryption()。

序列化描述符不包含敏感信息的情况也可能存在。 再次考虑加密密钥存储在 HSM 中的情况。 描述符在序列化自身时无法写出密钥材料,因为 HSM 不会以明文形式公开材料。 相反,描述符可能会写出密钥的密钥包装版本(如果 HSM 允许以这种方式导出)或 HSM 自身的密钥唯一标识符。

IAuthenticatedEncryptorDescriptorDeserializer

IAuthenticatedEncryptorDescriptorDeserializer 接口表示一种类型,该类型知道如何从 XElement 反初始化 IAuthenticatedEncryptorDescriptor 实例。 它公开单一方法:

  • ImportFromXml(XElement 元素):IAuthenticatedEncryptorDescriptor

ImportFromXml 方法采用 IAuthenticatedEncryptorDescriptor.ExportToXml 返回的 XElement,并创建原始 IAuthenticatedEncryptorDescriptor 的等效项。

实现 IAuthenticatedEncryptorDescriptorDeserializer 的类型应具有以下两个公共构造函数之一:

  • .ctor(IServiceProvider)

  • .ctor()

注意

传递给构造函数的 IServiceProvider 可能为 NULL。

顶级工厂

AlgorithmConfiguration 类表示知道如何创建 IAuthenticatedEncryptorDescriptor 实例的类型。 它公开单个 API。

  • CreateNewDescriptor() : IAuthenticatedEncryptorDescriptor

将 AlgorithmConfiguration 视为顶级工厂。 该配置用作模板。 它包装算法信息(例如,此配置使用 AES-128-GCM 主密钥生成描述符),但它尚未与特定密钥关联。

当调用 CreateNewDescriptor 时,将仅为此调用创建新的密钥材料,并生成一个新的 IAuthenticatedEncryptorDescriptor 来包装此密钥材料和使用该材料所需的算法信息。 密钥材料可以在软件中创建(并保存在内存中),也可在 HSM 中创建和保存等。 关键点是对 CreateNewDescriptor 的任何两次调用都不应创建等效的 IAuthenticatedEncryptorDescriptor 实例。

AlgorithmConfiguration 类型充当密钥创建例程(如自动滚动密钥)的入口点。 要更改所有未来密钥的实现,请在 KeyManagementOptions 中设置 AuthenticatedEncryptorConfiguration 属性。