Aes and rsa encryption
Содержание:
Downloads
AES-GCM-Test.zip — Demonstrates encryption and decryption using AES in GCM mode (confidentiality and authentication)
AES-CCM-Test.zip — Demonstrates encryption and decryption using AES in CCM mode (confidentiality and authentication)
AES-EAX-Test.zip — Demonstrates encryption and decryption using AES in EAX mode (confidentiality and authentication)
AES-ECB-Filter.zip — Demonstrates encryption and decryption using AES in ECB mode with filters (confidentiality only)
AES-CBC-Filter.zip — Demonstrates encryption and decryption using AES in CBC mode with filters (confidentiality only)
AES-CFB-Filter.zip — Demonstrates encryption and decryption using AES in CFB mode with filters (confidentiality only)
AES-OFB-Filter.zip — Demonstrates encryption and decryption using AES in OFB mode with filters (confidentiality only)
Дешифрация из файла в память
Функцию дешифрации из файла в память мы, к сожалению, тоже не можем привести полностью, и в листинге опять будет опущена алгоритмическая часть. Прототип дешифрации выглядит так:
Содержимое файла fileName расшифровывается ключом secretKey и помещается в участок памяти, на который ссылается переменная buffer. Код этой функции практически идентичен коду в листинге 3, но есть и небольшие отличия. Во-первых, мы открываем лишь один файл, а во-вторых, мы определяем размер файла и автоматически выделяем требуемый объем памяти для расшифрованной информации.
Последнее, что нам остается сделать, – это реализовать функцию расшифровки одного файла в другой. Ее прототип выглядит так:
Содержимое inFileName расшифровывается ключом key и записывается в файл outFileName. Полный код этой функции можно увидеть в листинге.
int CAes::DecryptToFile(std::string inFileName, std::string outFileName, std::string key)
{
unsigned char* buffer;
int decrypted = DecryptToMemory(inFileName, key, buffer);
if (decrypted > 0)
{
FILE* outFile = fopen(outFileName.c_str(), «wb»);
if (outFile)
{
fwrite(buffer, sizeof(unsigned char), decrypted, outFile);
fclose(outFile);
}
delete buffer;
}
return decrypted;
}
Для начала мы объявляем указатель на unsigned char. Затем с помощью реализованной выше функции DecryptToMemory расшифровываем содержимое файла в память. Если все прошло успешно, то записываем участок памяти, на который ссылается переменная buffer, в файл outFileName и удаляем память, выделенную функцей
DecryptToMemory.
Расширение ключа
AES использует ключи шифрования трех фиксированных размеров: 128, 192, и 256 бит. В зависимости от размера ключа, конкретный вариант алгоритма AES может обозначаться как AES-128, AES-192 и AES-256 соответственно .
Задача процедуры расширения ключа состоит в формировании нужного количество слов расширенного ключа для их использования в операции AddRoundKey. Как было сказано выше, под «словом» здесь понимается 4-байтный фрагмент расширенного ключа, один из которых используется в первичном наложении материала ключа и по одному – в каждом раунде алгоритма. Таким образом, в процессе расширения ключа формируется 4∗(R+1){\displaystyle 4*(R+1) \,\!} слов.
Расширение ключа выполняется в два этапа, на первом из которых производится инициализация слов расширенного ключа (обозначаемых как Wi{\displaystyle W_i \,\!}): первые Nk{\displaystyle N_k \,\!} (Nk{\displaystyle N_k \,\!} – размер исходного ключа шифрования K{\displaystyle K\,\!} в словах, т.е. 4, 6 или 8) слов Wi{\displaystyle W_i \,\!} (т.е. i=…Nk−1{\displaystyle i = 0 … N_{k-1} \,\!}) формируются их последовательным заполнением байтами ключа (см. рис. 7).

Рис. 7 Инициализация расширенного ключа
Последующие слова Wi{\displaystyle W_i \,\!} формируются следующей последовательностью операций для каждого i=Nk…4∗(R+1)−1{\displaystyle i = N_k … 4*(R+1)-1 \,\!}:Шаг 1. Инициализируется временная переменная T{\displaystyle T\,\!} :
T=Wi−1{\displaystyle T=W_{i-1} \,\!}.
Шаг 2. Данная переменная модифицируется следующим образом:a. если i{\displaystyle i\,\!} кратно Nk{\displaystyle N_k \,\!}, то:T=SubWord(RotWord(T))ÅRCëiNkû{\displaystyle T = SubWord(RotWord(T)) Å RCëi/Nkû \,\!};
константы RCn{\displaystyle RC_n \,\!} представляют собой слова, в которых все байты, кроме первого являются нулевыми, а первый байт имеет значение 2n−1mod256{\displaystyle 2^{n-1} mod 256 \,\!};
b. если Nk=8{\displaystyle N_k = 8 \,\!} и imodNk=4{\displaystyle i mod N_k = 4 \,\!}, то:
T=SubWord(T){\displaystyle T = SubWord(T) \,\!};
c. в остальных случаях модификация переменной T{\displaystyle T\,\!} не выполняется.
Шаг 3. Формируется i{\displaystyle i\,\!}-е слово расширенного ключа:
Wi=Wi−NkÅT{\displaystyle W_i = W_{i-N_k} Å T \,\!}.
Операция SubWord выполняет над каждым байтом входного значения табличную замену, которая была описана выше – см. операцию SubBytes.
Операция RotWord побайтно вращает входное слово на 1 байт влево.
Как видно, процедура расширения ключа является достаточно простой по сравнению со многими другими современными алгоритмами шифрования. Процедура расширения ключа имеет также несомненное достоинство в том, что расширение ключа может быть выполнено «на лету» (on-the-fly), т.е. параллельно с зашифрованием данных.
История AES
В далеком 1998 году NIST объявил конкурс на создание алгоритма, удовлетворяющего выдвинутым институтом требованиям. Он опубликовал все несекретные данные о тестировании кандидатов на роль AES и потребовал от авторов алгоритмов сообщить о базовых принципах построения используемых в них констант. В отличие от ситуации с DES, NIST при выборе AES не стал опираться на секретные и, как следствие, запрещенные к публикации данные об исследовании алгоритмов-кандидатов.
Чтобы быть утвержденным в качестве стандарта, алгоритм должен был:
- реализовать шифрование частным ключом;
- представлять собой блочный шифр;
- работать со 128-разрядными блоками данных и ключами трех размеров (128, 192 и 256 разрядов).
Дополнительно кандидатам рекомендовалось:
- использовать операции, легко реализуемые как аппаратно (в микрочипах), так и программно (на персональных компьютерах и серверах);
- ориентироваться на 32-разрядные процессоры;
- не усложнять без необходимости структуру шифра для того, чтобы все заинтересованные стороны были в состоянии самостоятельно провести независимый криптоанализ алгоритма и убедиться, что в нем не заложено каких-либо недокументированных возможностей.
Кроме того, алгоритм, претендующий на роль стандарта, должен распространяться по всему миру на неэксклюзивных условиях и без платы за пользование патентом.
Перед первым туром конкурса в NIST поступило 21 предложение, 15 из которых соответствовали выдвинутым критериям. Затем были проведены исследования этих решений, в том числе связанные с дешифровкой и проверкой производительности, и получены экспертные оценки специалистов по криптографии. В августе 1999 года NIST объявил пять финалистов, которые получили право на участие во втором этапе обсуждений.
2 октября 2000 года NIST сообщил о своем выборе – победителем конкурса стал алгоритм RIJNDAEL (произносится как «райндол») бельгийских криптографов Винсента Раймана и Йоана Дамана, который зарегистрирован в качестве официального федерального стандарта как FIPS 197 (Federal Information Processing Standard).
Для меня остается загадкой, зачем в российском вузе преподают стандарты иностранных государств. Видимо, исходят из принципа, что врага надо знать в лицо :). Ладно, в общем-то, это не наше дело. Нам надо просто программно реализовать основу национальной безопасности США.
Алгоритм обработки ключа
Алгоритм обработки ключа состоит из двух процедур:
- Алгоритм генерации раундовых ключей (алгоритм расширения ключа)
- Алгоритм выбора раундового ключа (ключа итерации)
Алгоритм генерации раундовых ключей
Алгоритм AES, используя процедуру KeyExpansion() и подавая в неё Cipher Key, K, получает ключи для всех раундов. Всего получается Nb*(Nr + 1) слов: изначально для алгоритма требуется набор из Nb слов, и каждому из Nr раундов требуется Nb ключевых набора данных. Полученный массив ключей для раундов обозначается как wi{\displaystyle w\left}, ≤i<Nb∗(Nr+1){\displaystyle 0\leq i<Nb*(Nr+1)}. Алгоритм KeyExpansion() показан в псевдокоде ниже.
Функция SubWord() берёт четырёхбайтовое входное слово и применяет S-box к каждому из четырёх байтов. То, что получилось, подаётся на выход. На вход RotWord() подаётся слово a,a1,a2,a3{\displaystyle }, которое она циклически переставляет и возвращает a1,a2,a3,a{\displaystyle }. Массив слов, постоянный для данного раунда, Rconi{\displaystyle Rcon\left}, содержит значения xi−1,00,00,00{\displaystyle }, где x = {02}, а xi−1{\displaystyle x^{i-1}} является степенью x{\displaystyle x} в GF(28){\displaystyle GF\left(2^{8}\right)} (i{\displaystyle i} начинается с 1).
Из рисунка можно видеть, что первые Nk{\displaystyle Nk} слов расширенного ключа заполнены Cipher Key. В каждое последующее слово, wi{\displaystyle w}, кладётся значение, полученное при операции XOR wi−1{\displaystyle w} и wi−Nk{\displaystyle w\left}, те XOR’а предыдущего и на Nk позиций раньше слов. Для слов, позиция которых кратна Nk, перед XOR’ом к w применяется трансформация, за которой следует XOR с константой раунда Rcon. Указанная выше трансформация состоит из циклического сдвига байтов в слове (RotWord()), за которой следует процедура SubWord() — то же самое, что и SubBytes(), только входные и выходные данные будут размером в слово.
Важно заметить, что процедура KeyExpansion() для 256-битного Cipher Key немного отличается от тех, которые применяются для 128- и 192- битных шифроключей. Если Nk=8{\displaystyle Nk=8} и i−4{\displaystyle i-4} кратно Nk{\displaystyle Nk}, то SubWord() применяется к wi−1{\displaystyle w} до XOR’а.
Алгоритм выбора раундового ключа
На каждой итерации i{\displaystyle i} раундовый ключ для операции AddRoundKey выбирается из массива wi{\displaystyle w\left},начиная с элемента wNb∗i{\displaystyle w\left} до wNb∗(i+1){\displaystyle w\left}.