Основное расширение криптографии

Предупреждение

Типы, которые реализуют один из следующих интерфейсов, должны быть потоково безопасны для нескольких вызывающих элементов.

IAuthenticatedEncryptor

Интерфейс IAuthenticatedEncryptor является базовым строительным блоком криптографической системы. Для каждого ключа есть один IAuthenticatedEncryptor, и экземпляр IAuthenticatedEncryptor использует весь криптографический материал и алгоритмическую информацию, необходимые для выполнения криптографических операций.

Тип отвечает за предоставление аутентифицированных сервисов шифрования и дешифрования. У него есть два API.

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

Метод Encrypt возвращает элемент, который включает в себя зашифрованный текст и тег аутентификации. Тег аутентификации должен включать в себя дополнительные данные аутентификации (AAD), хотя сами по себе AAD не извлекаются из конечных данных. Метод Decrypt валидирует тег аутентификации и возвращает расшифрованные данные. Все сбои (кроме ArgumentNullException и похожих) должны быть связаны с CryptographicException.

Примечание

Сам по себе экземпляр IAuthenticatedEncryptor не должен содержать ключевой материал. Например, для всех операций реализация может делегировать полномочия HSM.

IAuthenticatedEncryptorDescriptor

Интерфейс IAuthenticatedEncryptorDescriptor представляет тип, который знает, как создать экземпляр IAuthenticatedEncryptor. Вот его API.

  • CreateEncryptorInstance() : IAuthenticatedEncryptor
  • ExportToXml() : XmlSerializedDescriptorInfo

Как и IAuthenticatedEncryptor, экземпляр IAuthenticatedEncryptorDescriptor работает с одним конкретным ключом. Это обозначает, что для любого заданного экземпляра IAuthenticatedEncryptorDescriptor все аутентифицированные шифраторы, созданные его методом CreateEncryptorInstance, должны считаться эквивалентными.

// we have an IAuthenticatedEncryptorDescriptor instance
IAuthenticatedEncryptorDescriptor descriptor = ...;

// 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 = descriptor.CreateEncryptorInstance();
byte[] ciphertext = encryptor1.Encrypt(plaintext, aad);

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


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

XML сериализация

Основное различие между IAuthenticatedEncryptor и IAuthenticatedEncryptorDescriptor состоит в том, что дескриптор знает, как создать механизм шифрования и передать ему валидные аргументы. Представьте себе IAuthenticatedEncryptor, чья реализация зависит от SymmetricAlgorithm и KeyedHashAlgorithm. Работа механизма шифрования состоит в том, чтобы использовать эти типы, но он не обязательно должен знать, откуда они происходят, так что он не знает, как переопределить себя, если приложение будет перезапущено. Дескриптор работает на самом высоком уровне всего этого. Поскольку дескриптор знает, как создать экземпляр механизма шифрования (то есть, он знает, как создать требуемые алгоритмы), он может сериализовать это знание в XML форму, так что экземпляр механизма шифрования будет пересоздан после перезапуска приложения.

Дескриптор можно сериализовать через ExportToXml. Он возвращает XmlSerializedDescriptorInfo, содержащий два свойства: представление дескриптора XElement и Type, который представляет IAuthenticatedEncryptorDescriptorDeserializer, который можно использовать для восстановления этого дескриптора, основываясь на соответствующем XElement.

Сериализованный дескриптор может содержать чувствительную информацию, например, криптографический материал. У системы защиты данных есть встроенная поддержка зашифрованной информации, прежде чем она отправляется в хранилище. Чтобы принять преимущества этого, дескриптор должен отметить элемент, который содержит чувствительную информацию, с помощью имени атрибута “requiresEncryption” (xmlns “http://schemas.asp.net/2015/03/dataProtection”) и значения “true”.

Совет

Существует вспомогательный API для настройки этого атрибута. Вызовите метод расширения XElement.MarkAsRequiresEncryption(), находящийся в пространстве имен Microsoft.AspNet.DataProtection.AuthenticatedEncryption.ConfigurationModel.

Иногда сериализованный дескриптор не содержит чувствительную информацию. Допустим, криптографический ключ хранится в HSM. Дескриптор не может записать ключевой материал при сериализации, пока HSM не раскроет материал в формате простого текста. Вместо этого дескриптор может записать “key-wrapped” версию ключа или уникальный идентификатор HSM для этого ключа.

IAuthenticatedEncryptorDescriptorDeserializer

Интерфейс IAuthenticatedEncryptorDescriptorDeserializer представляет тип, который знает, как десериализовать экземпляр IAuthenticatedEncryptorDescriptor из XElement. У него есть единственный метод:

  • ImportFromXml(XElement element) : IAuthenticatedEncryptorDescriptor

Метод ImportFromXml принимает XElement, который возвращается IAuthenticatedEncryptorDescriptor.ExportToXml, и создает эквивалент оригинального IAuthenticatedEncryptorDescriptor.

У типов, которые реализуют IAuthenticatedEncryptorDescriptorDeserializer, должен быть один из двух следующих открытых конструкторов:

  • .ctor(IServiceProvider)
  • .ctor()

Примечание

IServiceProvider, переданный конструктору, может быть null.

IAuthenticatedEncryptorConfiguration

Интерфейс IAuthenticatedEncryptorConfiguration представляет тип, который знает, как создать экземпляры IAuthenticatedEncryptorDescriptor. У него есть один API.

  • CreateNewDescriptor() : IAuthenticatedEncryptorDescriptor

Думайте об IAuthenticatedEncryptorConfiguration как о фабрике высокого уровня. Конфигурация выглядит в качестве шаблона. Она использует информацию алгоритма (например, эта конфигурация создает дескрипторы с помощью мастер ключа AES-128-GCM), но она все еще не связана с конкретным ключом.

Когда вызывается CreateNewDescriptor, создаются новые ключи, а также создается новый IAuthenticatedEncryptorDescriptor, который использует эти ключи и информацию по алгоритму, требующуюся для потребления этого материала. Ключевой материал можно создать в ПО (и хранить in-memory), его можно создавать и хранить внутри HSM и так далее. Суть в том, что любые два вызова CreateNewDescriptor никогда не создадут эквивалентные экземпляры IAuthenticatedEncryptorDescriptor.

Тип IAuthenticatedEncryptorConfiguration хранит точку входа при создании ключа, например, автоматическое создание ключа. Чтобы сменить реализацию для всех будущих ключей, зарегистрируйте в контейнере сервисов реализацию IAuthenticatedEncryptorConfiguration.

Поделись хорошей новостью с друзьями!
Следи за новостями!