понедельник, 11 апреля 2011 г.

Проблемы сертификации: Эпизод III - Такой маленький ключ

Проблема, о которой я рассказывал в прошлый раз, возникает исключительно при попытке расшифровать сообщение. На этот раз речь пойдёт об ошибке шифрования алгоритмом RSA, а именно: "Key not valid for use in specified state".


Key not valid for use in specified state
Не знаю, какие ещё состояния ключа имели в виду разработчики CryptoAPI, все те разы, когда с ней сталкивался я, она означала следующее: ключ RSA слишком мал, чтобы зашифровать предоставленный блок данных.

Алгоритм RSA относится к блочным алгоритмам шифрования. Это означает, что он может быть применён только к блокам данных фиксированного размера. Размер шифруемого блока в алгоритме RSA равен размеру ключа. Так для 1024 битного ключа размер блока равен 128 байтам (1024 бит / 8 = 128 байт). Причина этого ограничения лежит в особенностях алгоритма: уменьшение объёма шифруемых данных приводит к падению стойкости шифра. Поэтому, чтобы не уменьшать надёжность, размер блока данных строго фиксирован.

На практике полезный объём шифруемых данных оказывается и того меньше. Чтобы предотвратить атаки по словарю, атаки с применением известного исходного текста, шифруемые данные всегда дополняются произвольным сальтом. Если шифруемых данных недостаточно для заполнения целого блока, то они дополняются до полного блока произвольными данными. Это означает, что блок должен содержать ещё и информацию о размере реальных данных, чтобы при расшифровке их можно было отделить от дополнения. Таким образом, шифруемый блок всегда будет содержать следующую информацию: размер полезных данных (заголовок), полезные данные, сальт и данные дополнения.

Применение алгоритма RSA регламентировано стандартом PKCS#1. На текущий момент актуальны 3 версии этого стандарта: 1.5, 2.0 и 2.1. Более подробно можно прочитать на оффициальном сайте стандарта. Класс RSACryptoServiceProvider из пространства имён System.Security.Cryptography .NET Framework`а предоставляет возможность шифрования данных алгоритмом RSA по стандарту PKCS#1 версий 1.5 и 2.0.

PKCS#1 v. 1.5 отводит на сальт и заголовок 11 байт. Таким образом, максимальный объём данных, которые могут поместиться в одном блоке, вычисляется следующим образом:
(размер ключа в битах / 8) - 11 байт
Для ключа в 1024 бита это будет: 1024 / 8 - 11 = 117 байт.

Для того, чтобы зашифровать данные с применением этой версии стандарта, необходимо вызвать метод Encrypt класса RSACryptoServiceProvider, передав ему false в качестве второго параметра:
byte[] cipheredData = rsaCryptoProviderObj.Encrypt(data, false);

PKCS#1 v. 2.0 чуть сложнее. Он подразумевает использование Optimal Asymmetric Encryption Padding - особую схему шифрования, увеличивающую стойкость шифра. Максимальный размер полезных данных для него вычисляется следующим образом:
(размер ключа в битах / 8) - 2 - 2 * (размер хэша, используемого для вычисления OAEP дополнения)
Как правило, в OAEP схеме используется алгоритм SHA1 с длинной хэша 20 байт. Таким образом, для ключа длиной 1024 бита имеем: 1024 / 8 - 2 - 2 * 20 = 86 байт.

Чтобы применить эту схему шифрования, нужно передать true в качестве значения 2-ого параметра при вызове метода Encrypt класса RSACryptoServiceProvider:
byte[] cipheredData = rsaCryptoProviderObj.Encrypt(data, true);

Таким образом, чтобы получить вышеозначенную ошибку, достаточно передать на вход методу RSACryptoServiceProvider.Encrypt больше 117 байт в первом случае и больше 86 байт во втором, что не так уж и много.

Комментариев нет:

Отправить комментарий