Пам'ятка по створенню безпечного каналу зв'язку, записки програміста

1. Постановка завдання

Є користувачі А і Б, які обмінюються повідомленнями. Вони можуть використовувати протокол TCP, UDP, електронну пошту або чат - зараз це не має значення. Є зловмисник Е, який може перехоплювати, підміняти і переставляти ці повідомлення, змушувати їх безслідно зникнути, а також надсилати повідомлення від імені А і Б. Завдання - допомогти А і Б обмінюватися повідомленнями таким чином, щоб Е не міг дізнатися їх вмісту. Позбутися від Е ніяк не можна.

2. Шифрування даних

В якості алгоритму шифрування Шнайер і Фергюсон рекомендують використовувати AES (Rijndael з розміром блоку 128 біт) з довжиною ключа 256 біт в режимі CTR. В цьому режимі максимальний розмір одного повідомлення становить 16 · 2 32 байт. Навряд чи когось гнобити це обмеження. В крайньому випадку можна розбити повідомлення на частини.

Для шифрування повідомлення з номером i, що має розмір L біт, необхідно обчислити L біт наступним способом:

де функція EK (128 біт на виході) - алгоритм шифрування, K (256 біт) - ключ шифрування, аргумент функції (128 біт) - шіфруемие дані, а оператор || означає конкатенацію даних. Після обчислення бітів b1 ... bL складаємо їх по Жегалкина (виключає АБО, операція XOR, ⊕) з бітами повідомлення, в результаті отримуємо зашифрований текст. Для розшифровки потрібно виконати точно таку ж послідовність дій над шіфротекста.

Тут важливо звернути увагу на два моменти. По-перше, ключі шифрування при посилці даних від А до Б і від Б до А повинні бути різними. По-друге, необхідно узгодити сукупність електронних даних в аргументі функції EK. Порядок байт в 32-х розрядних числах може змінюватися в залежності від архітектури використовуваного процесора. Традиційно в мережевих протоколах і форматах файлів використовується порядок байт від старшого до молодшого.

3. Функція хешування

Припустимо, ми успішно встановили сеансовий ключ за допомогою алгоритму Діффі-Хеллмана. в результаті А і Б отримали загальний ключ К. Потім проводиться наступна послідовність дій:

// Позбавляємося від алгебраїчної структури ключа
K = SHAd -256 (K)
// Будуємо 4 дочірніх ключа:
// 1. Шифрування від А до Б
key_send_enc = SHAd -256 (K || «Enc from A to B»)
// 2. Шифрування від Б до А
key_recv_enc = SHAd -256 (K || «Enc from B to A»)
// 3. Аутентифікація від А до Б
key_send_auth = SHAd -256 (K || «Auth from A to B»)
// 4. Аутентификация від Б до А
key_recv_auth = SHAd -256 (K || «Auth from B to A»)

4. Коди аутентифікації повідомлень

Кожне повідомлення має супроводжуватися імітовставки (MAC). В якості опції MAC Шнайер і Фергюсон рекомендують використовувати HMAC-SHA-256:

Тут ai - код аутентифікації i-го повідомлення mi. HMACK (m) являє собою хеш-функцію, значення якої залежить не тільки від повідомлення m, а й від ключа K. Як і у випадку з шифруванням, в MAC має використовуватися два незалежних ключа для А і Б. Як ми вже відзначали, ⊕ - це операція побітового виключає АБО (вона ж XOR).

У «Практичної криптографії» робиться особливий акцент на тому, як важливо проводити аутентифікацію не тільки повідомлення mi. що є звичайною послідовністю байт, а й його сенсу. Нехай mi = a || b || c, тобто складається з декількох полів певної довжини. Уявімо, що після чергового оновлення протоколу розміри полів змінилося. Тоді, якщо зловмисник Е зможе підмінити версію протоколу, повідомлення буде інтерпретовано невірно. Притому неважливо як зловмисникові вдасться це зробити - безпека однієї частини системи не повинна залежати від безпеки інших.

Ось для чого потрібна додаткова інформація xi. що включає в себе id протоколу (сигнатуру, IP: порт одержувача і відправника), версію протоколу, id повідомлення, розмір і імена полів повідомлення. Притому інформація xi повинна бути закодована таким чином, щоб її можна було однозначно декодувати. L (xi) в нашій формулі - це, очевидно, довжина xi. На щастя, всього цього гемора можна уникнути, просто передаючи повідомлення в XML-подібному форматі даних, тобто такому, де додаткова інформація про сенс повідомлення вже включена в повідомлення електронної пошти. Тут важливо не забути включити в кожне повідомлення всю додаткову інформацію, перераховану вище.

Що ще варто знати про MAC?

  • Можна обрізати значення HMAC-SHA-256 до 16-ї байт. Робити це не бажано, але таке рішення краще, ніж використання HMAC-MD5 з метою зменшити обсяг переданих даних.
  • Рекомендується спочатку обчислювати MAC, а потім виробляти шифрування повідомлення разом з MAC. а не навпаки.

5. Опис обміну повідомленнями

Будемо вважати, що користувачі А і Б вже справили узгодження сеансового ключа і вирахували дочірні ключі, як це було описано в пункті 3.

Важливо! Для кожного нового сеансу зв'язку необхідно генерувати нові ключі шифрування і аутентифікації.

Угода щодо ключів заслуговує на написання окремого поста, якщо не двох, тому зараз ми його не розглядаємо.

Тепер А і Б обмінюються повідомленнями в форматі, подібному XML (або дотримуються інструкцій, які передбачені для іншої ситуації, см пункт 4). Кожному повідомленню присвоюється унікальний 32-х бітний номер. Нумерація повідомлень починається з одиниці - так простіше відстежити момент, коли номери закінчаться. Коли це станеться, необхідно заново провести узгодження ключів. Можна використовувати і 64-х бітні номери повідомлень, але тоді кожне повідомлення стане на 4 байта довше. До того ж, час від часу слід проводити оновлення ключів, так що 32 біта - в самий раз.

Якщо для передачі даних використовується протокол UDP, слід проводити повторне посилку повідомлення по деякому таймаут в разі, якщо інша сторона на нього не реагує. При використанні TCP цього не потрібно - транспортний рівень подбати про гарантовану поставку пакетів. Зловмисник Е може порушити сеанс зв'язку між А і Б, зіпсувавши одне з повідомлень або переставивши пару повідомлень місцями. Але раз у нас є «людина посередині», то він в будь-якому випадку може порушити зв'язок між А і Б. Звідси висновок:

Не варто витрачати час на написання «свого TCP» поверх іншого протоколу - просто використовуйте протокол TCP. Якщо, звичайно, у вашому додатку це можливо.

Коли користувач А хоче послати повідомлення mi. він обчислює MAC цього повідомлення ai згідно з пунктом 4. Потім він шифрує повідомлення mi || ai. як це описано в пункті 2 і посилає користувачеві Б наступне: i || m'i || a'i. Після цього А збільшує значення лічильника відправлених повідомлень i на одиницю.

Коли користувач Б отримує i || m'i || a'i. він розшифровує mi і ai. перевіряє код аутентифікації. Повідомлення з невірним MAC ігноруються (їх міг відправити зловмисник Е). Потім проводиться перевірка значення i - якщо воно менше очікуваного номера повідомлення, для визначеності назвемо його j, повідомлення відкидається. В іншому випадку (i> = j) присвоюємо j значення i + 1 і обробляємо повідомлення mi.

Тут є кілька моментів, на які варто загострити увагу. По-перше, як вже зазначалося в пункті 2, номера повідомлень слід передавати в порядку байт від старшого до молодшого. По-друге, перевірку номера повідомлення можна було б проводити і до розшифровки. Але в цьому випадку, якщо повідомлення з невірним номером пошле зловмисник Е, буде виявлена ​​(а потім записана в логи) помилка «невірний номер повідомлення», коли насправді сталася помилка «невірний код аутентифікації повідомлення». Криптографи в першу чергу турбуються про безпеку та коректній роботі додатків, а не про продуктивність. Деяким програмістам є чому у них повчитися.

На жаль, в разі активного втручання зловмисника Е в передачу даних, користувач Б може отримати лише підмножина повідомлень, відправлених А. Якщо виявлена ​​пропажа повідомлень, то поведінка користувачів має залежати від типу інформації, якою вони обмінюються. В одних випадках пропажа частини повідомлень може бути не критичною, в іншій - вимагати припинення сеансу зв'язку.

6. Висновок

Дуже багато моментів не були розглянуті в цій статті. Як А і Б узгодять сеансові ключі зв'язку? Звідки під час узгодження ключів користувачеві А відомо, що він спілкується з Б, якщо за умовами задачі Е може видавати себе за кого завгодно?

Не менш цікаві питання - як правильно генерувати псевдовипадкові числа? Як протидіяти таймінг-атак? Що робити, якщо операційна система помістить запущене застосування зі всіма ключами в файл підкачки? Як безслідно видалити файл із застарілою парою RSA-ключів? Зловмисник Е хоч і не знає вмісту повідомлень, але знає їх розмір і час відправлення - небезпечно це і як цьому протистояти?

Сподобався пост? Поділися з іншими: