Перейти к содержанию

Основы криптографии

Симметричное шифрование

Симметричное шифрование подразумевает использование одинакового ключа как для шифрования так и для дешифрования информации.

Существующие современные алгоритмы шифрования надёжны, однако проблемой их эксплуатации является безопасная передача ключа шифрования на расстоянии. Проблема генерации и передачи ключей быстро растёт по отношению к числу участников взаимодействия: Общение между 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.

Зашифровать файл message.txt в GPG
gpg --symmetric --cipher-algo CIPHER message.txt
Здесь CIPHER - алгоритм шифрования. Поддерживаемые алгоритмы можно посмотреть следующей командой

gpg --version
Расшифровать файл message.txt в GPG
gpg --output original_message.txt --decrypt message.gpg

OpenSSL Project

Зашифровать файл message.txt в OpenSSL алгоритмом AES-256
openssl aes-256-cbc -e -in message.txt -out encrypted_message
Расшифровать файл message.txt в OpenSSL
openssl aes-256-cbc -d -in encrypted_message -out original_message.txt

Для увеличения стойкости шифра, имеет смысл шифровать сообщение с использованием алгоритма pbkdf2:

Зашифровать файл message.txt в OpenSSL алгоритмом AES-256 с pbkdf2
openssl aes-256-cbc -pbkdf2 -iter 10000 -e -in message.txt -out encrypted_message
Расшифровать файл message.txt в OpenSSL алгоритмом AES-256 с pbkdf2
openssl aes-256-cbc -pbkdf2 -iter 10000 -d -in encrypted_message -out original_message.txt

Ассиметричное шифрование

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

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

  • приватный - ключ который должен оставаться в тайне

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

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

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

Обеспечение конфиденциальности

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

Обеспечение целостности, Аутентичности и Неотказуемости

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

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

RSA

Rivest, Shamir, Adleman - фамилии людей создавших криптографический алгоритм с открытым ключом известный как RSA.

Работает следующим образом:

  1. Выбираются 2 простых числа p и q. Вычисляется N, как N = p * q

  2. Выбираются два числа e и d таких, что e * d = 1 mod f(N), где f(N) = N - p - q + 1. На этом шаге генерируются публичный ключ (N, e) и приватный ключ (N, d). Здесь f(N) - функция Эйлера

  3. Отправитель зашифровывает значение x путём вычисления y = x^e mod N (x^e mod N - Модуль)

  4. Получатель расшифровывает y путём вычисления x = y^d mod N

Безопасность RSA основана на проблеме факторизации простых чисел: легко посчитать значение N = p * q, однако для вычисления p или q по заданному N требуется очень много времени. Больше того, для того чтобы система была безопасной выбираются поистине гигантские простые числа p и q, для примера числа размером 1024 бита, в десятичном представлении будут выглядить как число с более чем 300 нулями!

Корректная генерация больших простых чисел является краеугольным камнем безопасности RSA. Если противник сможет догадаться о том, какие числа p и q были использованны - система будет скомпроментирована.

Практический пример алгоритма:

  1. Боб выбирает два простых числа p = 157 и q = 199 и вычисляет N = p * q = 31243

  2. Вычисляется функция Эйлера 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).

  3. Алиса шифрует значение x = 13 публичным ключом Боба: y = x^e mod N = 13^163 mod 31243 = 16342

  4. Боб расшифровывает значение x своим приватным ключом: x = y^d mod N = 16341^379 mod 31243 = 13

Для генерации ключевой пары средствами openssl:

Генерация ключевой пары средствами openssl
openssl genrsa -out private-key.pem 2048

openssl rsa -in private-key.pem -pubout -out public-key.pem
writing RSA key

OpenSSL предоставляет возможность посмотреть на реальные значения составляющих алгоритма:

Отображение реальных значений параметров генерации ключей RSA
$ 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

Имея на руках ключи, можно зашифровать:

openssl pkeyutl -encrypt -in plaintext.txt -out ciphertext -inkey public-key.pem -pubin

и расшифровать сообщение:

openssl pkeyutl -decrypt -in ciphertext -inkey private-key.pem -out decrypted.txt

Протокол Diffie-Hellman

Еще один популярный алгоритм ассиметричного шифрования который позволяет двум участникам взаимодействия обмениваться общим секретом по незащищенному каналу связи.

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

Пример работы алгоритма.

Пусть Алиса и Боб хотят обменятся общим секретом через незащищенный канал связи.

  1. Алиса и Боб через незащищенный канал связи выбирают 2 простых числа q и g, такие что g < q и соответствует некоторым условиям. Пусть q = 29, а g = 3

  2. Алиса выбирает случайное число a < q. Вычисляет A = (g)^a mod q. a - Алиса держит в секрете, A - передаёт Бобу. Пусть a = 13, тогда A = 3^13 mod 29 = 19

  3. Боб выбирает случайное число b < q. Вычисляет B = (g)^b mod q. b - Боб держит в секрете, B - передаёт Алисе. Пусть b = 15, тогда B = 3^15 mod 29 = 26

  4. Алиса получает B и вычисляет ключ = B^a mod q: ключ = 26^13 mod 29 = 10

  5. Боб получает A и вычисляет ключ = A^b mod q: ключ = 19^15 mod 29 = 10

Зная значения q, g, A, B для вычисления значения секретных ключей Алисы и Боба потребуется невероятное количество времени.

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

Пример обмена общим секретом по Diffie-Hellman с помощью openssl:

Обмен секретом по Diffie-Hellman
# 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