Общие сведения о шифровании, цифровых подписях и хэш-алгоритмах в .NET

В этой статье представлен обзор методов шифрования и методик, поддерживаемых .NET, включая манифесты ClickOnce.

Общие сведения о криптографии

Общедоступные сети, такие как Интернет, не предоставляют средства безопасного взаимодействия между сущностями. При взаимодействии через такие сети может происходить чтение или даже изменение передаваемой информации неправомочными третьими лицами. Использование криптографии обеспечивает защиту данных от просмотра, обнаружение изменения данных и безопасный обмен данными на основе незащищенных каналов. Например, данные могут быть зашифрованы с помощью некоторого криптографического алгоритма, переданы в зашифрованном виде, а затем расшифрованы лицом, которому они предназначались. Если зашифрованные данные будут перехвачены третьим лицом, расшифровать их будет трудно.

В .NET классы в System.Security.Cryptography пространстве имен управляют множеством сведений о шифровании. Некоторые из них являются оболочками для реализации операционной системы, а другие — чисто управляемыми реализациями. При использовании этих классов вам вовсе не обязательно быть экспертом в криптографии. При создании экземпляра одного из классов, реализующих алгоритмы шифрования, ключи создаются автоматически с целью удобства использования, а принятые по умолчанию значения свойств призваны обеспечить максимальную защищенность.

Криптографические примитивы

В типичной ситуации, когда используется криптография, две стороны (Анна и Виктор) осуществляют связь по незащищенному каналу. Анна и Виктор хотят быть уверены в том, что передаваемые ими данные не могут быть прочитаны даже в случае возможного перехвата. Более того, так как Анна и Виктор находятся в удаленных друг от друга местах, Анна должна быть уверена, что информация, которую она получает от Виктора, не подвергается изменению во время передачи. Также она должна быть уверена в том, что получаемые ею данные действительно исходят от Виктора, а не от кого-то, выдающего себя за него.

Криптография используется для достижения следующих целей:

  • конфиденциальность: защита данных или личной информации пользователя от несанкционированного просмотра;

  • целостность данных: защита данных от несанкционированного изменения;

  • аутентификация: проверка того, что данные исходят действительно от определенного лица;

  • неотрекаемость: ни одна сторона не должна иметь возможность отрицать факт отправки сообщения.

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

Криптографический примитив Использование
Шифрование с закрытым ключом (симметричное шифрование) Осуществляет преобразование данных с целью предотвращения их просмотра третьей стороной. При таком способе шифрования для шифрования и расшифровки данных используется один общий закрытый ключ.
Шифрование с открытым ключом (асимметричное шифрование) Осуществляет преобразование данных с целью предотвращения их просмотра третьей стороной. При таком способе шифрования для шифрования и расшифровки данных используется набор, состоящий из открытого и закрытого ключей.
Создание криптографической подписи Позволяет проверить, действительно ли данные исходят от конкретного лица, с помощью уникальной цифровой подписи этого лица. Этот процесс также использует хэш-функции.
Криптографическое хэширование Отображает данные любого размера в байтовую последовательность фиксированной длины. Результаты хэширования статистически уникальны; отличающаяся хотя бы одним байтом последовательность не будет преобразована в то же самое значение.

Шифрование с закрытым ключом

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

Шифрование с закрытым ключом называют также симметричным шифрованием, так как для шифрования и расшифровки используется один и тот же ключ. Алгоритмы шифрования с закрытым ключом являются очень быстрыми (по сравнению с алгоритмами шифрования с открытым ключом) и хорошо подходят для осуществления криптографических преобразований больших массивов данных. Асимметричные алгоритмы шифрования, такие как RSA, имеют математические ограничения на объем шифруемых данных. Для симметричных алгоритмов шифрования подобные проблемы обычно не возникают.

Разновидность алгоритмов шифрования с закрытым ключом, называемая блочным шифром, используется для шифрования целого блока данных за один раз. Блочные шифры (такие как DES, TrippleDES и AES) преобразуют входной блок данных длиной в n байтов в выходной блок зашифрованных данных. Если необходимо зашифровать или расшифровать последовательность байтов, следует делать это блок за блоком. Так как значение n достаточно мало (8 байт для DES и TripleDES; 16 байт (по умолчанию), 24 или 32 байта для AES), данные большей длины, чем n , должны шифроваться блоками, по одному за раз. Блоки данных размером менее n байт должны быть увеличены до n байт перед обработкой.

Одна из простейших форм блочного шифра называется режимом электронной кодовой книги (ECB). Режим ECB не считается безопасным, так как в нем не используется вектор инициализации для инициализации первого текстового блока. Для заданного закрытого ключа kпростой блочный шифр, не использующий вектор инициализации, зашифрует одинаковые входные блоки текста в одинаковые выходные блоки зашифрованного текста. Поэтому, если во входном текстовом потоке есть одинаковые блоки, в зашифрованном потоке также будут одинаковые блоки. Такие повторяющиеся выходные блоки сообщают неправомочным пользователям о ненадежных алгоритмах шифрования, которыми можно воспользоваться, и о возможных типах атак. Шифр ECB поэтому очень уязвим для анализа и, в конечном итоге, для взлома ключа.

Классы блочных шифров, предоставляемые библиотекой базовых классов, используют режим сцепления, называемый сцеплением шифровальных блоков (CBC), хотя эту настройку по умолчанию можно изменить.

Шифры CBC решают проблемы, связанные с использованием шифров ECB, благодаря использованию вектора инициализации (IV) для шифрования первого текстового блока. Перед шифрованием каждого блока открытого текста он объединяется с зашифрованным текстом предыдущего блока с помощью поразрядной исключающей операции OR (XOR). Поэтому каждый блок зашифрованного текста зависит от всех предыдущих блоков. При использовании этой системы шифрования стандартные заголовки сообщений, которые могут быть известны неправомочному пользователю, не могут быть использованы им для восстановления закрытого ключа.

Одним из способов раскрытия данных, зашифрованных с помощью шифра CBC, является подбор ключа методом полного перебора возможных ключей. В зависимости от длины использованного для шифрования ключа такой подбор занимает очень много времени даже на самых быстрых компьютерах, поэтому он является практически неосуществимым. Шифры с большей длиной ключа труднее взломать. Несмотря на то что использование шифрования не гарантирует теоретическую невозможность раскрытия зашифрованных данных неправомочным лицом, стоимость такого взлома становится чрезвычайно высокой. Если процесс подбора ключа и раскрытия зашифрованных данных занимает три месяца, в то время как сами данные актуальны в течение всего нескольких дней, подбор ключа методом полного перебора не представляет практической ценности.

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

Предположим, что Анна и Виктор являются двумя сторонами, которые хотят осуществлять связь по незащищенному каналу. Они могли бы воспользоваться шифрованием с закрытым ключом следующим образом. Анна и Виктор соглашаются использовать некоторый определенный алгоритм (например, AES) с определенным ключом и вектором инициализации. Алиса создает сообщение и создает сетевой поток (возможно, именованный канал или сетевую электронную почту), по которому отправляется сообщение. Затем она шифрует текст с помощью ключа и вектора инициализации и по интрасети пересылает зашифрованное сообщение и вектор инициализации Виктору. Виктор принимает зашифрованный текст и осуществляет расшифровку, используя ранее согласованные ключ и вектор инициализации. Если передача перехватывается, перехватчик не может восстановить исходное сообщение, так как они не знают ключ. В этой ситуации в секрете должен сохраняться только ключ. В более реалистичном случае либо Анна, либо Виктор создает закрытый ключ и использует шифрование с открытым ключом (асимметричное) для передачи другой стороне закрытого (симметричного) ключа. Подробнее о шифровании с открытым ключом читайте в следующем разделе.

.NET предоставляет следующие классы, реализующие алгоритмы шифрования секретного ключа:

  • Aes

  • HMACSHA256, HMACSHA384 и HMACSHA512. (Это технически секретные алгоритмы ключа, так как они представляют коды проверки подлинности сообщений, вычисляемые с помощью функции криптографического хэша в сочетании с секретным ключом. См . хэш-значения далее в этой статье.)

Шифрование с открытым ключом

При шифровании с открытым ключом используются закрытый ключ, который должен храниться в секрете от неправомочных пользователей, а также открытый ключ, который может предоставляться кому угодно. Открытый и закрытый ключи математически взаимосвязаны. Данные, зашифрованные с помощью открытого ключа, можно расшифровать исключительно с помощью соответствующего закрытого ключа, а цифровая подпись данных, подписанных с помощью закрытого ключа, может быть проверена только с помощью соответствующего открытого ключа. Открытый ключ можно предоставить любому лицу; он используется для шифрования данных, которые должны быть отправлены хранителю закрытого ключа. Алгоритмы шифрования с открытым ключом также известны как асимметричные алгоритмы, потому что для шифрования данных требуется один ключ, а для расшифровки — другой. Основное правило шифрования запрещает повторное использование ключа; оба ключа в каждом сеансе шифрования должны быть уникальными. Однако на практике асимметричные ключи обычно используются подолгу.

Две стороны (Анна и Виктор) могут использовать шифрование с открытым ключом следующим образом. Сначала Анна создает набор, состоящий из открытого и закрытого ключей. Если Виктор хочет послать Анне зашифрованное сообщение, он запрашивает у нее ее открытый ключ. Анна высылает Виктору свой открытый ключ через незащищенную сеть, и Виктор использует полученный ключ для шифрования своего сообщения. Виктор пересылает зашифрованное сообщение Анне, а она расшифровывает его с помощью своего закрытого ключа. Если Виктор получил ключ Анны по незащищенному каналу, например через открытую сеть, он оказывается уязвимым для атак типа «злоумышленник в середине». Поэтому Виктору необходимо убедиться в том, что Анна имеет правильную копию открытого ключа.

Во время передачи Виктору открытого ключа Анны может произойти несанкционированный перехват ключа третьим лицом. Более того, возможна ситуация, что то же самое лицо перехватит зашифрованное сообщение Виктора. Тем не менее неправомочная сторона не может расшифровать сообщение с помощью открытого ключа. Сообщение можно расшифровать только с помощью закрытого ключа Анны, который не передавался через какие-либо системы связи. Анна не использует свой закрытый ключ для шифрования ответного сообщения Виктору, потому что любое лицо может расшифровать это сообщение с помощью открытого ключа. Если Анна желает послать Виктору ответное сообщение, она запрашивает у Виктора его открытый ключ и шифрует свое сообщение, используя его. Затем Виктор расшифровывает сообщение с помощью своего соответствующего закрытого ключа.

В этом случае Анна и Виктор используют шифрование с открытым ключом (асимметричное) для передачи закрытого (симметричного) ключа, а затем пользуются шифрованием с этим закрытым ключом в течение сеанса связи.

В списке ниже сравниваются алгоритмы шифрования с открытым и закрытым ключом.

  • Алгоритмы шифрования с открытым ключом используют буфер фиксированного размера, в то время как алгоритмы шифрования с закрытым ключом могут использовать буфер переменного размера.

  • Алгоритмы шифрования с открытым ключом нельзя использовать для сцепления блоков данных в потоки тем же образом, как в алгоритмах шифрования с закрытым ключом, потому что можно шифровать только маленькие порции данных. Поэтому асимметричные операции не используют такую же потоковую модель, как симметричные операции.

  • Шифрование с открытым ключом имеет намного большее пространство ключей (диапазон возможных значений ключа), чем шифрование с закрытым ключом. Поэтому такое шифрование менее уязвимо к атакам полного перебора, когда проверяются все возможные значения ключа.

  • Открытые ключи можно легко распространять, так как они не требуют особой защиты при условии, что существует некий способ установления подлинности источника.

  • Некоторые алгоритмы шифрования с открытым ключом (такие как RSA и DSA, но не Диффи-Хелмана) можно использовать для создания цифровых подписей, служащих для подтверждения подлинности лица, от которого исходят данные.

  • Алгоритмы шифрования с открытым ключом являются весьма медленными по сравнению с алгоритмами шифрования с закрытым ключом и не предназначены для шифрования больших объемов данных. Использование шифрования с открытым ключом имеет смысл только при передаче очень малых массивов данных. Обычно шифрование с открытым ключом применяется для того, чтобы зашифровать ключ и вектор инициализации, которые будут использоваться при шифровании с закрытым ключом. После передачи ключа и вектора инициализации используется уже шифрование с закрытым ключом.

.NET предоставляет следующие классы, реализующие алгоритмы открытого ключа:

RSA разрешает шифрование и подписывание, но DSA можно использовать только для подписывания. DSA не так безопасна, как RSA, и мы рекомендуем RSA. Diffie-Hellman можно использовать только для создания ключей. В целом, алгоритмы с открытым ключом имеют более ограниченную сферу применения, чем алгоритмы с закрытым ключом.

цифровые подписи.

Алгоритмы шифрования с открытым ключом также можно использовать для создания цифровых подписей. Цифровые подписи удостоверяют подлинность источника данных (если вы доверяете открытому ключу источника) и защищают целостность данных. С помощью открытого ключа, созданного Анной, получатель отправленных ею данных может проверить, что их источником действительно является Анна, сравнив цифровую подпись полученных данных с открытым ключом Анны.

Чтобы использовать шифрование с открытым ключом для создания цифровой подписи сообщения, Анна сначала применяет к этому сообщению хэш-алгоритм, который создает хэш сообщения. Хэш сообщения является компактным и уникальным представлением данных. Для создания своей личной цифровой подписи Анна шифрует хэш сообщения с помощью своего закрытого ключа. При получении сообщения и цифровой подписи Виктор расшифровывает подпись с помощью открытого ключа Анны, восстанавливая хэш сообщения, а затем хэширует сообщение с помощью того же алгоритма, который использовала Анна. Если вычисленный Виктором хэш в точности совпадает с хэшем, полученным от Анны, Виктор может быть уверен в том, что сообщение пришло действительно от владельца закрытого ключа и что данные в нем не были изменены. Если Виктор уверен, что именно Анна владеет закрытым ключом, он удостоверяется в том, что сообщение пришло от нее.

Примечание.

Цифровая подпись может быть проверена любым лицом, потому что открытый ключ отправителя является общедоступным и обычно включается в формат цифровой подписи. Рассматриваемый метод не обеспечивает секретности сообщения; для обеспечения секретности его следует еще и зашифровать.

.NET предоставляет следующие классы, реализующие алгоритмы цифровой подписи:

Хэш-значения

Хэш-алгоритмы преобразуют двоичные последовательности произвольной длины в двоичные последовательности фиксированного меньшего размера, известные как хэш-значения. Хэш-значение является числовым представлением порции данных. Если в хэшированном абзаце текста изменяется хотя бы одна буква, результат хэширования также меняется. Если хэш является криптостойким, его значение значительно изменится. Например, если изменяется один бит сообщения, результат выполнения криптостойкой хэш-функции может отличаться на 50 %. Несколько входных значений могут преобразовываться в один хэш-код. Однако в вычислительном плане немыслимо найти два разных входных набора данных, результаты хэширования которых полностью совпадают.

Две стороны (Анна и Виктор) могут использовать хэш-функцию для проверки целостности сообщений. Им нужно выбрать хэш-алгоритм для подписывания сообщений. Анна будет писать сообщение, а затем создавать его хэш с помощью выбранного алгоритма. Затем стороны могут применять один из указанных ниже вариантов дальнейших действий.

  • Анна отправляет Виктору сообщение с открытым текстом и хэш сообщения (цифровую подпись). Виктор получает сообщение, применяет к нему хэш-алгоритм и сравнивает свое значение хэша со значением, полученным от Анны. Если хэш-значения совпадают, значит, данные не изменялись. Если хэш-значения не совпадают, значит, данные изменялись после создания.

    К сожалению, этот способ не позволяет установить подлинность отправителя. Любой человек может выдавать себя за Анну и отправлять сообщения Виктору. Для этого достаточно подписывать сообщения с помощью такого же хэш-алгоритма, и Виктор сможет лишь проверить, соответствует ли сообщение подписи. Это одна из форм атаки «злоумышленник в середине». Дополнительные сведения см. в примере безопасной связи для шифрования следующего поколения (CNG).

  • Анна отправляет Виктору сообщение с открытым текстом по незащищенному открытому каналу. По защищенному закрытому каналу она оправляет Виктору хэш сообщения. Виктор получает сообщение с открытым текстом, хэширует его и сравнивает хэш со значением, полученным по закрытому каналу. Если хэши совпадают, Виктор может сделать два вывода:

    • сообщение не было изменено;

    • отправитель сообщения подлинный (Анна).

    Для того чтобы такая система работала, Анна должна скрывать оригинальное хэш-значение от всех, кроме Виктора.

  • Анна по незащищенному открытому каналу отправляет Виктору сообщение в виде открытого текста, а хэш сообщения помещает на свой общедоступный веб-сайт.

    Такой подход позволяет защититься от изменения хэша третьей стороной. Хотя сообщение и его хэш могут видеть все, изменить хэш может только Анна. Злоумышленнику, который хочет выдать себя за Анну, потребуется доступ к её веб-сайту.

Ни один из описанных выше способов не защищает Анну от чтения ее сообщений третьими лицами, так как сообщения передаются в виде открытого текста. Для обеспечения полной защиты обычно требуется использовать цифровые подписи и шифрование.

.NET предоставляет следующие классы, реализующие алгоритмы хэширования:

.NET также предоставляет MD5 и SHA1. Но алгоритмы MD5 и SHA-1 были обнаружены небезопасными, и теперь рекомендуется SHA-2. SHA-2 включает SHA256, SHA384 и SHA512.

генерация случайных чисел

Генерация случайных чисел является неотъемлемой частью многих криптографических операций. Например, криптографические ключи должны выбираться настолько случайно, насколько это возможно, чтобы было фактически невозможно воспроизвести их значения. Криптографические генераторы случайных чисел должны генерировать результат, который нельзя предсказать вычислительными методами с вероятностью хотя бы 50 %. Поэтому все методы предсказания очередного случайного бита не должны быть точнее, чем простое угадывание. Классы в .NET используют генераторы случайных чисел для создания криптографических ключей.

Класс RandomNumberGenerator является реализацией алгоритма генерации случайных чисел.

Манифесты ClickOnce

Следующие классы шифрования позволяют получать и проверять сведения о подписях манифестов для приложений, развернутых с помощью технологии ClickOnce:

Кроме того, перечисленные ниже классы предоставляют сведения о конкретных подписях.

  • StrongNameSignatureInformation содержит сведения о строгом имени подписи для манифеста.

  • AuthenticodeSignatureInformation представляет сведения о подписи Authenticode для манифеста.

  • TimestampInformation содержит сведения о метке времени в подписи Authenticode.

  • TrustStatus предоставляет простой способ проверить, является ли подпись Authenticode достоверной.

Классы криптографии следующего поколения (CNG)

Классы криптографии следующего поколения (CNG) предоставляют управляемую оболочку для собственных функций CNG. (CNG является заменой cryptoAPI.) Эти классы имеют "Cng" в составе их имен. Центральным в группе классов оболочек CNG является класс контейнера ключей CngKey , который абстрагирует хранение и использование ключей CNG. Этот класс позволяет безопасно хранить пару ключей или открытый ключ и ссылаться на него, используя простое строковое имя. Класс цифровых подписей ECDsaCng и класс шифрования ECDiffieHellmanCng на основе эллиптических кривых используют объекты CngKey .

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

.NET также включает различные вспомогательные классы CNG, например следующие:

  • CngProvider поддерживает поставщика хранилища ключей.

  • CngAlgorithm поддерживает алгоритм CNG.

  • CngProperty поддерживает часто используемые свойства ключей.

См. также