Основы криптографии
Симметричное шифрование
Симметричное шифрование подразумевает использование одинакового ключа как для шифрования так и для дешифрования информации.
Существующие современные алгоритмы шифрования надёжны, однако проблемой их эксплуатации является безопасная передача ключа шифрования на расстоянии. Проблема генерации и передачи ключей быстро растёт по отношению к числу участников взаимодействия: Общение между 5000 участниками потребует создание почти 5000 различных ключей (99 + 98 + 97 + ... + 1 = 4950). Кроме того, компроментация одного ключа потребует генерации 99 ключей
Как следует из Википедии, в настоящее время симметричные шифры — это:
-
Блочные шифры. Обрабатывают информацию блоками определённой длины (обычно 64, 128 бит), применяя к блоку ключ в установленном порядке, как правило, несколькими циклами перемешивания и подстановки, называемыми раундами. Результатом повторения раундов является лавинный эффект — нарастающая потеря соответствия битов между блоками открытых и зашифрованных данных.
-
Поточные шифры. Проводят шифрование над каждым битом либо байтом исходного (открытого) текста с использованием гаммирования. Поточный шифр может быть легко создан на основе блочного (например, ГОСТ 28147-89 в режиме гаммирования), запущенного в специальном режиме.
Сущесвует множество различного ПО для симметричного шифрования данных. Говоря об Open Source решениях, нельзя не упомянуть про:
-
GNU Privacy Guard
-
OpenSSL Project
GNU Privacy Guard
GNU Privacy Guard также известный как GnuPG или GPG - программное обеспечение реализующее стандарт OpenPGP.
ЗдесьCIPHER
- алгоритм шифрования. Поддерживаемые алгоритмы можно посмотреть следующей командой
OpenSSL Project
openssl aes-256-cbc -e -in message.txt -out encrypted_message
openssl aes-256-cbc -d -in encrypted_message -out original_message.txt
Для увеличения стойкости шифра, имеет смысл шифровать сообщение с использованием алгоритма pbkdf2
:
openssl aes-256-cbc -pbkdf2 -iter 10000 -e -in message.txt -out encrypted_message
openssl aes-256-cbc -pbkdf2 -iter 10000 -d -in encrypted_message -out original_message.txt
Ассиметричное шифрование
Ассиметричное шифрование в первую очередь решает проблему обмена обшим секретом между участниками взаимодействия. Ключами можно обмениваться по открытому каналу, главное, чтобы он был надёжным.
Достигается это благодарая тому, что в шифровании и расшифровании участвуют разные ключи, которые образуют ключевую пару:
-
приватный - ключ который должен оставаться в тайне
-
публичный - ключ который может направлятся участникам взаимодействия.
Сообщение зашифрованное приватным ключом, может быть расшифрованно с помощью публичного ключа и наоборот.
Ассиметричное шифрование способно обеспечить конфиденциальность, целостность, аутентичность и неотказуемость информации, однако оно работает гораздо медленнее симметричного шифрования в случае необходимости шифрования большого объема данных.
Обеспечение конфиденциальности
Зашифровывая сообщение с помощью публичного ключа участника взаимодействия - достигается конфиденциальность информации, так как расшифровать такое сообщение сможет только конкретный участник взаимодействия с помощью своего приватного ключа, который известен только ему.
Обеспечение целостности, Аутентичности и Неотказуемости
Наравне с конфиденциальностью, ассиметричное шифрование может обеспечить состояния информации указанные в подзаголовке.
Для этого, участнику взаимодействия нужно всего лишь зашифровать сообщение с помощью своего приватного ключа. Расшифрование такого сообщения с помощью публичного ключа будет означать то, что оно было зашифровано с использованием конкретного приватного ключа, а значит сделал это конкретный участник взаимодействия.
RSA
Rivest, Shamir, Adleman - фамилии людей создавших криптографический алгоритм с открытым ключом известный как RSA.
-
Выбираются 2 простых числа
p
иq
. ВычисляетсяN
, какN = p * q
-
Выбираются два числа
e
иd
таких, чтоe * d = 1 mod f(N)
, гдеf(N) = N - p - q + 1
. На этом шаге генерируются публичный ключ(N, e)
и приватный ключ(N, d)
. Здесьf(N)
- функция Эйлера -
Отправитель зашифровывает значение
x
путём вычисленияy = x^e mod N
(x^e mod N
-Модуль
) -
Получатель расшифровывает
y
путём вычисленияx = y^d mod N
Безопасность RSA основана на проблеме факторизации простых чисел: легко посчитать значение N = p * q
, однако для вычисления p
или q
по заданному N
требуется очень много времени. Больше того, для того чтобы система была безопасной выбираются поистине гигантские простые числа p
и q
, для примера числа размером 1024 бита, в десятичном представлении будут выглядить как число с более чем 300 нулями!
Корректная генерация больших простых чисел является краеугольным камнем безопасности RSA. Если противник сможет догадаться о том, какие числа p
и q
были использованны - система будет скомпроментирована.
Практический пример алгоритма:
-
Боб выбирает два простых числа
p = 157
иq = 199
и вычисляетN = p * q = 31243
-
Вычисляется функция Эйлера
f(N) = N - p - q + 1 = 31423 - 157 - 199 + 1 = 3088
. Выбираютсяe = 163
d = 379
такие, чтоe * d = 163 * 379 = 61777
и61777 mod 3088 = 1
. Публичным ключом будет пара(31243б 163)
, приватным -(31243, 379)
. -
Алиса шифрует значение
x = 13
публичным ключом Боба:y = x^e mod N = 13^163 mod 31243 = 16342
-
Боб расшифровывает значение
x
своим приватным ключом:x = y^d mod N = 16341^379 mod 31243 = 13
Для генерации ключевой пары средствами openssl
:
openssl genrsa -out private-key.pem 2048
openssl rsa -in private-key.pem -pubout -out public-key.pem
writing RSA key
OpenSSL предоставляет возможность посмотреть на реальные значения составляющих алгоритма:
$ openssl rsa -in private-key.pem -text -noout
>
Private-Key: (2048 bit, 2 primes)
modulus:
00:ca:67:00:79:88:35:a2:13:d0:2c:7b:bb:bb:d9:
75:52:eb:4d:f1:b0:8f:ee:be:9c:cd:15:f6:ce:b4:
[...]
publicExponent: 65537 (0x10001)
privateExponent:
10:fe:00:be:33:3f:3d:72:28:61:f3:a9:59:25:f2:
81:99:9b:9b:94:d5:20:98:04:15:fb:a8:12:c6:71:
[...]
prime1:
00:e0:3d:87:b3:d3:1f:d2:c6:66:23:83:a5:95:d5:
20:35:f8:d8:c0:94:cf:cc:d2:04:d4:e4:ef:cf:c2:
[...]
prime2:
00:e7:11:ac:50:f5:dc:16:cf:20:46:77:5d:ca:16:
29:36:35:89:95:c0:f8:4b:42:ef:03:a0:f1:ce:2e:
[...]
-
prime1
-p
-
prime2
-q
-
modulus
-N
-
publicExponent
-e
-
privateExponent
-d
Имея на руках ключи, можно зашифровать:
и расшифровать сообщение:
Протокол Diffie-Hellman
Еще один популярный алгоритм ассиметричного шифрования который позволяет двум участникам взаимодействия обмениваться общим секретом по незащищенному каналу связи.
Основу алгоритма, так же как и в RSA, составляют операции возведения в степень и вычисления модуля чисел.
Пример работы алгоритма.
Пусть Алиса и Боб хотят обменятся общим секретом через незащищенный канал связи.
-
Алиса и Боб через незащищенный канал связи выбирают 2 простых числа
q
иg
, такие чтоg
<q
и соответствует некоторым условиям. Пустьq
= 29, аg
= 3 -
Алиса выбирает случайное число
a
<q
. ВычисляетA
=(g)^a mod q
.a
- Алиса держит в секрете,A
- передаёт Бобу. Пустьa
= 13, тогдаA
= 3^13 mod 29 = 19 -
Боб выбирает случайное число
b
<q
. ВычисляетB
=(g)^b mod q
.b
- Боб держит в секрете,B
- передаёт Алисе. Пустьb
= 15, тогдаB
= 3^15 mod 29 = 26 -
Алиса получает
B
и вычисляетключ
=B^a mod q
:ключ
= 26^13 mod 29 = 10 -
Боб получает
A
и вычисляетключ
=A^b mod q
:ключ
= 19^15 mod 29 = 10
Зная значения q
, g
, A
, B
для вычисления значения секретных ключей Алисы и Боба потребуется невероятное количество времени.
В реальной жизни, алгоритм оперирует числами размером от 256 бит, которые являются гигантскими в десятичном представлении.
Пример обмена общим секретом по Diffie-Hellman с помощью openssl
:
# 1. Генерируется общая база (размером 2048 бит) для вычисления ключей, которая передаётся участникам по открытому каналу:
openssl dhparam -out dhparams.pem 2048
#2. Участники генерируют собственные приватные ключи с помощью файла с параметрами:
openssl genpkey -paramfile dhparams.pem -out alice_private.pem
openssl genpkey -paramfile dhparams.pem -out bob_private.pem
#3. Участники генерируют публичные ключи из своих приватных ключей:
openssl pkey -in alice_private.pem -pubout -out alice_public.pem
openssl pkey -in bob_private.pem -pubout -out bob_public.pem
#4. Участники обмениваются публичными ключами, а затем каждый вычисляет общий секрет
openssl pkeyutl -derive -inkey alice_private.pem -peerkey bob_public.pem -out shared_secret.bin
openssl pkeyutl -derive -inkey bob_private.pem -peerkey alice_public.pem -out shared_secret.bin
Имея на руках общий секрет, можно использовать его в качестве ключа для какого-нибудь алгоритма симметичного шифрования. Например, зашифруем файл message.txt
с помошью алгоритма AES-256-cbc
и вновь созданного ключа:
openssl enc -aes-256-cbc -pass file:shared_secret.bin -in message.txt -out encrypted_message.enc
Для расшифровки, следующая команда:
openssl aes-256-cbc -d -in encrypted_message.enc -pass file:shared_secret.bin -out message.txt
Алгоритм остается уязвимым для атак типа MitM
, который может выдать за одного из участников взаимодействия. Для устранения такого типа атак, к обмену привлекается третья, доверенная, сторона (читай про PKI - далее на этой же странице)
Хэширование
Криптографическая хэш функция - алгоритм принимающий данные произвольной длины на вход и возвращающий значение фиксированной длины которое называют чексуммой или дайджестом сообщения.
К примеру алгоритм хэширования SHA-256
возвращает дайджест сообщения длиной 256 бит (32 байта) который принято записывать в виде 64 шестнадцатиричных значений.
Область применения хэширования довольно широка, основные из них:
-
Хранение паролей. Часто хранится не чистый хэш, а обработанный "солью"
-
Обеспечение целостности информации
HMAC
Hash Based Message Auythentication Code (HMAC) - Код проверки подлинности сообщений использующий симметричный ключ которым зашифрован хэш сообщения.
По сути является дополнением к MAC
В соответствии с RFC2104 HMAC формируется следующим образом:
HMAC = HASH((Ключ XOR '0х5С' x B) + HASH((Ключ XOR '0х36' x B) + Сообщение))
где B количество повторений. Зависит от выбранной хэш функции.
Механизм похож на электронную подпись сообшения, однако в отличии от неё, HMAC использует симметричные ключи.
PKI
Public Key Infastructure - механизм дополняющий алгоритмы обмена ассиметричными ключами направленный на противодействие MitM атакам.
Суть сводится к добавлению в процесс обмена ключами третьй, доверенной, стороны которая с помощью своего публичного ключа подтверждает достоверность конкретного публичного ключа конкректного участника взаимодействия.
Совокупность публичного ключа участника взаимодействия, публичного ключа доверенной стороны и различной дополнительной информации называется сертификатом ключа проверки электронной подписи.
Сертификаты ключа проверки электронной подписи могут собираться в цепочки сертификатов, корневым значением в которой будет сертификат одного из доверенных корневых центров сертификации, который, в свою очередь будет подписан самим собой.
Для того, чтобы цепочка сертификатов функционировала должным образом, в ОС имеется хранилище сертификатов, в которое должны помещаться как корневые так и промежуточные центры сертификации. К редактированию хранилища сертификатов нужно подходить с должной осмотрительностью, так как хранящиеся в нём сертификаты считаются доверенными по умолчанию.
Для получения сертификата проверки публичного ключа (или проверки электронной подписи, что в принципе одно и то же) нужно сформировать запрос на получение сертификата и отправить его в центр сертификации.
В OpenSSL это можно сделать например следующим образом:
openssl req -new -nodes -newkey rsa:4096 -keyout key.pem -out cert.csr
# где
req -new | Новый запрос на сертификат
-nodes | Сохранение приватного ключа без пароля
-newkey | Генерация нового приватного ключа...
rsa:4096 | ... типа RSA, размером 4096 бит
-keyout | место хранения ключа
-out | место сохранения запроса на сертификацию
.csr
файл отправляется в УЦ.
Для генерации самоподписанного сертификата можно воспользоваться следующей командой:
openssl req -x509 -newkey -nodes rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365
Парольная аутентификация
Криптография принимает непосредсвенное участие в обеспечении аутентификации с помощью паролей, хранение хэшей от паролей - минимальная мера обеспечивающая защиту аутентификационных данных.
Однако, хранение только хэшей паролей не оберегает их от брутфорс атак с использованием радужных таблиц - плоских таблиц с сопоставленными хэшами и их значениями. Для решения этой проблемы применяется salt
- случайно значение которое добавляется к паролю: либо так: hash(password + salt)
, либо так hash(hash(password, salt))
.
Современные алгоритмы хэширования, такие как
Argon2id
,bcrypt
,PBKDF2
автоматически солят пароли.
Для случая, если в модели угроз имеется угроза компроментации БД с хэшами и солью сушествует технология peppering
- которая заключается в применении HMAC к уже посоленному хэшу. Естественно, что ключ для HMAC хранится отдельно от БД с хэшей с солью.
Warning
Следует понимать и помнить, что использование "перчения" без "посолки" теряет смысл, так именно соль делает каждый хэш пароля уникальным.
Хорошо о паролях написано на owasp cheatsheets