在 ASP.NET Core中的核心加密可扩展性Core cryptography extensibility in ASP.NET Core

本文内容

警告

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

IAuthenticatedEncryptorIAuthenticatedEncryptor

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

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

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

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

加密方法返回包含到加密纯文本和身份验证标记的 blob。身份验证标记必须包含其他经过身份验证的数据(AAD),尽管 AAD 本身无需从最终有效负载中恢复。解密方法验证身份验证标记并返回已解码的有效负载。所有失败(除了 System.argumentnullexception 和类似)都应该 homogenized 为 System.security.cryptography.cryptographicexception。

备注

IAuthenticatedEncryptor 实例本身实际上不需要包含密钥材料。例如,实现可能会委托给所有操作的 HSM。

如何创建 IAuthenticatedEncryptorHow to create an IAuthenticatedEncryptor

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

  • CreateEncryptorInstance (IKey 键): IAuthenticatedEncryptor

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

  1. // we have an IAuthenticatedEncryptorFactory instance and an IKey instance
  2. IAuthenticatedEncryptorFactory factory = ...;
  3. IKey key = ...;
  4. // get an encryptor instance and perform an authenticated encryption operation
  5. ArraySegment<byte> plaintext = new ArraySegment<byte>(Encoding.UTF8.GetBytes("plaintext"));
  6. ArraySegment<byte> aad = new ArraySegment<byte>(Encoding.UTF8.GetBytes("AAD"));
  7. var encryptor1 = factory.CreateEncryptorInstance(key);
  8. byte[] ciphertext = encryptor1.Encrypt(plaintext, aad);
  9. // get another encryptor instance and perform an authenticated decryption operation
  10. var encryptor2 = factory.CreateEncryptorInstance(key);
  11. byte[] roundTripped = encryptor2.Decrypt(new ArraySegment<byte>(ciphertext), aad);
  12. // the 'roundTripped' and 'plaintext' buffers should be equivalent

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

  • CreateEncryptorInstance() : IAuthenticatedEncryptor

  • ExportToXml() : XmlSerializedDescriptorInfo

与 IAuthenticatedEncryptor 一样,假定 IAuthenticatedEncryptorDescriptor 的实例包装一个特定键。这意味着,对于任何给定的 IAuthenticatedEncryptorDescriptor 实例,由其 CreateEncryptorInstance 方法创建的任何经过身份验证的加密程序都应视为等效,如以下代码示例中所示。

  1. // we have an IAuthenticatedEncryptorDescriptor instance
  2. IAuthenticatedEncryptorDescriptor descriptor = ...;
  3. // get an encryptor instance and perform an authenticated encryption operation
  4. ArraySegment<byte> plaintext = new ArraySegment<byte>(Encoding.UTF8.GetBytes("plaintext"));
  5. ArraySegment<byte> aad = new ArraySegment<byte>(Encoding.UTF8.GetBytes("AAD"));
  6. var encryptor1 = descriptor.CreateEncryptorInstance();
  7. byte[] ciphertext = encryptor1.Encrypt(plaintext, aad);
  8. // get another encryptor instance and perform an authenticated decryption operation
  9. var encryptor2 = descriptor.CreateEncryptorInstance();
  10. byte[] roundTripped = encryptor2.Decrypt(new ArraySegment<byte>(ciphertext), aad);
  11. // the 'roundTripped' and 'plaintext' buffers should be equivalent

IAuthenticatedEncryptorDescriptor (ASP.NET Core 2.x 仅)IAuthenticatedEncryptorDescriptor (ASP.NET Core 2.x only)

IAuthenticatedEncryptorDescriptor接口表示一种类型,该类型知道如何将自身导出到 XML。其 API 如下所示。

  • ExportToXml() : XmlSerializedDescriptorInfo

XML 序列化XML Serialization

IAuthenticatedEncryptor 和 IAuthenticatedEncryptorDescriptor 之间的主要区别在于,描述符知道如何创建加密程序并为其提供有效的参数。假设其实现依赖于 System.security.cryptography.symmetricalgorithm 和 KeyedHashAlgorithm 的 IAuthenticatedEncryptor。加密程序的工作就是使用这些类型,但不一定知道这些类型来自何处,因此,如果应用程序重启,则无法真正地写出如何重新创建其自身的正确说明。描述符在此基础上充当更高的级别。由于描述符知道如何创建加密程序实例(例如,它知道如何创建所需的算法),因此它可以将 XML 格式的知识序列化,以便可以在应用程序重置后重新创建加密程序实例。

描述符可以通过其 ExportToXml 例程进行序列化。此例程返回一个 XmlSerializedDescriptorInfo,其中包含两个属性:描述符的 System.xml.linq.xelement> 表示形式和表示IAuthenticatedEncryptorDescriptorDeserializer的类型,该类型可用于在给定相应 system.xml.linq.xelement> 的情况下恢复此描述符。

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

提示

有一个用于设置此属性的帮助器 API。调用 System.xml.linq.xelement> MarkAsRequiresEncryption (),该扩展方法位于命名空间 AspNetCore。

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

IAuthenticatedEncryptorDescriptorDeserializerIAuthenticatedEncryptorDescriptorDeserializer

IAuthenticatedEncryptorDescriptorDeserializer接口表示知道如何从 system.xml.linq.xelement> 反序列化 IAuthenticatedEncryptorDescriptor 实例的类型。它公开了单一方法:

  • ImportFromXml (System.xml.linq.xelement> 元素): IAuthenticatedEncryptorDescriptor

ImportFromXml 方法采用IAuthenticatedEncryptorDescriptor返回的 system.xml.linq.xelement>,并创建原始 IAuthenticatedEncryptorDescriptor 的等效项。

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

  • .ctor(IServiceProvider)

  • .ctor()

备注

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

顶级工厂The top-level factory

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

  • CreateNewDescriptor() : IAuthenticatedEncryptorDescriptor

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

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

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

IAuthenticatedEncryptorConfiguration接口表示知道如何创建IAuthenticatedEncryptorDescriptor实例的类型。它公开一个 API。

  • CreateNewDescriptor() : IAuthenticatedEncryptorDescriptor

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

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

IAuthenticatedEncryptorConfiguration 类型用作密钥创建例程(如自动密钥滚动)的入口点。若要更改所有将来键的实现,请在服务容器中注册单一实例 IAuthenticatedEncryptorConfiguration。