h0rr0rr_drag0n 12.08.2009 18:24
Я рекомендую — Использование библиотеки OpenSSL для (де)шифрования массива данных по алгоритму RSA.
Как-то, в целях выполнения универской практики, мне понадобилось разобраться в шифровании, а именно при помощи метода шифрования с открытым ключом зашифровывать и расшифровывать некий массив данных.В процессе поиска примеров шифрования блока данных, при помощи RSA и OpenSSL я столкнулся с тем, что таких примеров нет (ну может быть я плохо искал :-)). Поэтому я решил написать и выложить свой пример.
В качестве метода шифрования я выбрал RSA, используемой библиотекой стала OpenSSL (API в man 3 crypto - исчерпывающая информация по используемым в посте функциям). Язык программирования естественно C.
Для начала надо сгенерировать открытый и закрытый ключи, которыми мы будем шифровать\дешифровать наш массив данных. Для создания закрытого ключа дадим команду:
openssl genrsa -out privkey.pem 2048
где 2048 – это размер ключа в битах, privkey.pem – имя файла, в который будет помещен закрытый ключ. Наш ключ не защищен паролем, но это поведение можно исправить, передав утилите опцию -des3.
В создании открытого ключа есть один нюанс – в официальной документации сказано, что закрытые ключи также включают в себя и информацию об открытых ключах, но ИМХО ненормально раздавать файл с закрытым ключом только ради использования открытого. Создадим отдельный файл с открытым ключом, используя наш закрытый ключ privkey.pem:
openssl rsa -in privkey.pem -out pubkey.pem -pubout
Чтение файлов ключей в структуру RSA, используемую библиотекой, производится при помощи функций
для публичного ключа:
1 |
|
для закрытого ключа:
1 |
|
Первым параметром эти функции принимают указатель типа FILE * на открытый файл ключа. Остальные параметры отвечают за чтение ключа защищенного паролем и поэтому я их не использую.
Функция PEM_read_RSAPublicKey() не используется, потому что она по так и не установленной причине не читает ключ из файла, а возвращает NULL.
Шифрование данных будет производится функцией RSA_public_encrypt(), которая объявлена так:
1 |
|
где flen – размер шифруемых данных, from – указатель на шифруемые данные, to – указатель на зашифрованные данные, rsa – указатель на наш публичный RSA ключ. Параметр padding позволяет нам выбрать режим выравнивания данных; у нас используется значение RSA_PKCS1_PADDING. Размер буфера from должен быть не больше чем RSA_size(rsa) – 11, размер буфера to всегда будет равен RSA_size(rsa).
Поскольку размер зашифровываемых данных может быть больше чем RSA_size(rsa) – 11, используем функцию-обертку, которая разделяет данные на блоки соответствующего размера, шифрует их и склеивает обратно. Привожу ее код:
Дешифрование данных производится функцией:
1 |
|
Ее параметры аналогичны параметрам функции для шифрования данных.
Размер блока для расшифровки всегда кратен RSA_size(our_key), а размер дешифрованного блока данных возвращается функцией RSA_private_decrypt(), поэтому код функции-обертки для расшифровки произвольного по размеру массива данных довольно прост:
В процессе написания и отлаживания кода можно столкнуться с тем, что функции библиотеки OpenSSL возвращают некоторые коды ошибок. Для их обработки у библиотеки OpenSSL есть свои методы:
1 |
|
Если произойдет ошибка, то этот код в обработчике ошибок выведет на STDOUT строку вида:
Error: error:0407006A:lib(4):func(112):reason(106)
Чтобы получить детальное описание ошибки, передадим полученный error code утилите openssl:
$ openssl errstr 0407006A
error:0407006A:rsa routines:RSA_padding_check_PKCS1_type_1:block type is not 01
Ну а далее в гугл или в ман-страницы разбираться в причинах возникновения ошибки.
Привожу полный исходный код программы, шифрующей при помощи открытого и дешифрующей при помощи закрытого ключей строку символов по алгоритму RSA.
rsafuncstest.c:
Makefile для сборки проекта:
По материалам блока Дракон-линуксоид
Небольшое дополнение к статье.
По правде говоря чтобы использовать RSA не нужна специализированная библиотека, этот повсеместно используемый алгоритм прост как 2 копейки.
Основная проблема это генерация устойчивых к взлому ключей, но если они есть, все очень просто.
Открытый ключ соостоит из 2х чисел e и n
а закрытый из d и n
e всегда равно 65537
Таким образом n открытый ключ, а d закрытый, все это обычные Числа и достаточно большие.
Теперь расмотрим процесс шифрования с помощью открытого ключа
У нас есть сообщение m его преобразуютв число но не большее чем наш ключ, иначе делаят на части и шифруют по отдельности.
Итак у нас есть m в числовом виде
Процес шифрования c=(m^e)%n вот такое вотсложное шифрование :)))
Расшифровываем приватным ключем m=(c^d)%n - тоже все предельно просто
Я редко пишу на си поэтому не очень хорошо знаю библиотеки, но например в питоне есть стандартная функция pow(x,y,n) которая возводит очень польшие числа x в степень y с остатком n, думаю чтото подобное есть и на C.
Питон поддерживает работу с числами любой длинны, в С прийдется искать опять же библиотеку.
Собственно вот и весь алгоритм.
По правде говоря чтобы использовать RSA не нужна специализированная библиотека, этот повсеместно используемый алгоритм прост как 2 копейки.
Основная проблема это генерация устойчивых к взлому ключей, но если они есть, все очень просто.
Открытый ключ соостоит из 2х чисел e и n
а закрытый из d и n
e всегда равно 65537
Таким образом n открытый ключ, а d закрытый, все это обычные Числа и достаточно большие.
Теперь расмотрим процесс шифрования с помощью открытого ключа
У нас есть сообщение m его преобразуютв число но не большее чем наш ключ, иначе делаят на части и шифруют по отдельности.
Итак у нас есть m в числовом виде
Процес шифрования c=(m^e)%n вот такое вот
Расшифровываем приватным ключем m=(c^d)%n - тоже все предельно просто
Я редко пишу на си поэтому не очень хорошо знаю библиотеки, но например в питоне есть стандартная функция pow(x,y,n) которая возводит очень польшие числа x в степень y с остатком n, думаю чтото подобное есть и на C.
Питон поддерживает работу с числами любой длинны, в С прийдется искать опять же библиотеку.
Собственно вот и весь алгоритм.
После общения с челом, который работает в жутко секретной организации, понял что ломаются все сертифицированные и допущенные для использования алгоритмы шифрования:) Потому в шифровании вообще смысла не вижу:(
В молодости занимался вопросами безопасности и доводилось мне тогда писать несколько разных модулей шифрования/дешифрования данных на ассемблере. Помнится, не ощутил тогда проблем с информацией по алгоритмам и примерами на Цэ :)
А вообще, в мемориз, чтобы когда еще раз приспичит не искать в гугле :)