Інженерний дизайн та аналіз
Створення протоколу безпечного зв'язку в C
Table of Contents
Передумови побудови протоколу безпечного зв'язку в С
Перед тим як перезбавити в реалізацію, забезпечити середовище розробки включає в себе компілятор C (GCC або Clang), базові знання програмування розетки, і встановлена бібліотека OpenSSL. OpenSSL забезпечує надійні виконання криптографічних алгоритмів, що робить його стандартним вибором для безпечного зв'язку в C. На Linux, встановити OpenSSL через ваш менеджер пакетів (наприклад, ). На Windows, використовують попередньо підготовлені бункери або будувати з джерела. Допускається також сімейство з розетками TCP / IP і модель клієнтського сервера.
Розуміння блоків Cryptoграфічного будівництва
Забезпечити протокол зв'язку переходить на три стовпи: конфіденційність, цілісність та автентифікація. Конфіденційність досягається за допомогою шифрування, що тільки призначений одержувач може прочитати повідомлення. Інтегрність гарантує, що дані не були змінені в транзиті. Ауттентифікація перевіряє ідентичності сторін спілкування. У користувальницькому протоколі ви зазвичай поєднує симетричне шифрування, що має повідомлення автентичні коди (HMAC), і ключовий механізм обміну, такі як Дифуй-Хеллман.
Симетричне шифрування з AES
Розширений стандарт шифрування (AES) є найбільш широко використовуваним симетричним cipher. Він працює на 128-бітних блоках і підтримує ключові розміри 128, 192 або 256 біт. Для захищених комунікацій воліють AES в Galois / Counter Mode (GCM), що забезпечує як конфіденційність і цілісність в одній операції. Інтерфейс OpenSSL робить його прямим для шифрування та розшифрування даних з AES‐GCM. Уникайте старих режимів, таких як ECB або CBC, якщо об'єднані з обережним наповнювачем і автентифікацією.
Обмін з дифузі-Хеллман
Щоб безпечно погодитися на загальний секрет над непрокурним каналом, скористайтеся Diffie-Hellman (DH) ключовим обміном. Обидві сторони генерують приватні ключі та обмінюються публічними параметрами, потім компралюють загальний секрет. Diffie-Hellman] вразливий до манітерно-середні атаки, якщо не автентифікований, тому ви можете пізніше продовжити це цифровими підписами або передовим поголені ключі. Для використання виробництва розглянемо використання ефемерного дифу - Хеллман (DHE) для забезпечення ідеальної передньої секреції.
Інтеграція з HMAC
Для перевірки, що повідомлення не було трамперовано, застосуньте Hash‐based Code Authentication (HMAC) до кожного зашифрованого ciphertext. HMAC використовує спільний секретний ключ і функцію криптографічного хешу (наприклад, SHA‐256). Ресівер переходить на HMAC на отриманих даних і порівнює його до перезавантаження. Цей крок запобігає релей і тампераційних атак. Крім того, AES‐GCM включає в себе автентифікаційний тег, який служить тим самим, що спрощення протоколу.
Налаштування OpenSSL в проекті C
OpenSSL вимагає ретельної ініціалізації. Включаючи необхідні заголовки і виклик і ] на старті вашої програми. Для обробки помилок використовуйте і . При зв'язку додайте до ваших прапорів компілятора. Мінімальне налаштування виглядає так:
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/err.h>
// Initialize OpenSSL
void init_openssl() {
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
}
Будівництво шарів TCP Socket
Основний транспорт для вашого протоколу буде TCP, який забезпечує надійну, замовлену доставку. Створіть сервер, який слухає для вхідних підключень і клієнта, який ініціює за допомогою запікання. Використовуйте стандартні розетки POSIX з , , , ] на серверній стороні, а , ]] на стороні клієнта. Пам'ятайте, що обробляти помилки витончено і закривають декриптори файлів після використання.
Приклад сервера Skeleton
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);
bind(server_fd, (struct sockaddr*)&address, sizeof(address));
listen(server_fd, 3);
int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &addr_len);
Приклад клієнта Скелет
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);
connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
Реалізація дифузі-Hellman Key Exchange
Після встановлення підключення TCP клієнт і сервер виконує DH-ключну обмін. Кожна сторона генерує DH-ключну пару за допомогою API OpenSSL . Публічний ключ надсилається над розеткою, а обидві сторони дерують загальний секрет за допомогою . Для простоти використовуйте фіксовану групу (наприклад, ] з параметрами з ). У реальному протоколі ви будете переговори групи або використовувати заздалегідь визначені параметри.
// Generate DH parameters
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DH, NULL);
EVP_PKEY_paramgen_init(pctx);
EVP_PKEY_CTX_set_dh_paramgen_prime_len(pctx, 2048);
EVP_PKEY *params = NULL;
EVP_PKEY_paramgen(pctx, ¶ms);
// Generate key pair
EVP_PKEY_CTX *kctx = EVP_PKEY_CTX_new(params, NULL);
EVP_PKEY_keygen_init(kctx);
EVP_PKEY *my_key = NULL;
EVP_PKEY_keygen(kctx, &my_key);
// Export public key to send
unsigned char *pub_key_der = NULL;
int pub_len = i2d_PUBKEY(my_key, &pub_key_der);
send(sock, pub_key_der, pub_len, 0);
Наприкінці прийому, однолітків імпортує публічний ключ за допомогою , а потім лікує загальний секрет. Отриманий секрет може бути захоплений (наприклад, з SHA‐256) для отримання однорідного ключа для AES і HMAC.
Сшифрування та розшифрування повідомлень з AES‐GCM
AES‐GCM є кращим режимом, оскільки він забезпечує як шифрування, так і автентифікаційний тег в одній операції. Використовуйте OpenSSL з . Вам потрібно 12‐byte notce (IV) і 256-bit ключ, отриманий від DH загальний секрет. Тефтекст виробляється в шматках, і після остаточного оновлення ви отримуєте 16-байт тег. Відправте несуть, ciphertext і tag разом. Ресивер виконує , встановлює тег, і розшифровує. Якщо тег не вдається, повідомлення відхилено.
// Encryption
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, key, nonce);
unsigned char ciphertext[1024];
int outlen;
EVP_EncryptUpdate(ctx, ciphertext, &outlen, plaintext, len);
int tmplen;
EVP_EncryptFinal_ex(ctx, ciphertext + outlen, &tmplen);
unsigned char tag[16];
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag);
Додавання доброчесності з HMAC (або Leveraging GCM тег)
Якщо ви не можете використовувати AES‐GCM, ви можете зашифрувати AES‐CBC, а потім компute HMAC над ciphertext. Використовуйте від OpenSSL з SHA‐256. Застосуйте HMAC після ciphertext. Ресивер рекалькулює і порівнює. Цей підхід вимагає двох ключових ключів: один для шифрування, один для HMAC. Вигідний як з спільного секрету за допомогою функції ключового видалення (KDF) як HKDF. Однак AES‐GCM усуває необхідність окремого HMAC, зменшення складності та потенційних помилок.
Поставляючи його разом: повний робочий процес
- Створення підключення ТCP між клієнтом та сервером.
- Обидві сторони генерують ефемеральні дифузі-Hellman ключові пари.
- Обмін публічними ключами та складанням спільного секрету.
- Видаляє ключ 256-бітних AES і 256-бітний ключ HMAC (або використовувати той же ключ для GCM).
- Клієнт надсилає нецей (12 байт випадковим) і потім зашифроване повідомлення AES‐GCM плюс тег. Сервер розшифровує і виправляє.
- Сервер надішле відповідь за допомогою нових нездійснених (необхідних випадків повторного використання з тим же ключем).
- Обидві сторони можуть продовжувати обмін повідомленнями; для довгих сеансів, під ключ періодично використовують той же механізм DH руки, що робить або ратичним механізмом.
Найкращі практики безпеки
- Використовувати потужні генератори випадкових чисел ] з OpenSSL для створення ключів, некції та DH приватних ключів. Ніколи не використовуйте або для криптографічних цілей.
- Валістан усіх отриманих даних] Перевірити довжини, параметри публічного ключа (наприклад, забезпечити р-н - прайм, г - генератор), а теги HMAC перед обробкою.
- Avoid hardcoded keys або за замовчуванням Завжди веде переговори ключів свіжої за сеанс, щоб забезпечити ідеальний передній секрецію.
- Попередження помилок Якщо розшифрування не вдалося або не вдається верифікації HMAC, закривши з'єднання і ввійти захід. Не розкрийте, чому збоїлася невдача.
- Keep залежності оновлений Регулярно оновлення OpenSSL для патч відомих вразливостей. OpenSSL документація забезпечує керівництво по депрокації та кращих практик.
- Consider using TLS, а не користувацький протокол Для виробничих систем, спираючись на добре перевірені протоколи, такі як TLS 1.3. Побудова користувацького протоколу з нуля є помилкою і не рекомендується, якщо у вас є глибока криптографічна експертиза.
Тестування протоколу
Тестуйте свою реалізацію, використовуючи запущений клієнт і сервер на одному машині (localhost) і перевірте, що повідомлення розшифровувати правильно. Введення помилок, таких як tampered ciphertext або невірні невірні не означає, що протокол відхиляє їх. Використовуйте інструменти, такі як Wireshark для перевірки ринку сировини і підтвердити, що звичайний текст не видно. Для тестування блоку, змусити шар розетки і тестувати криптографічні примітиви окремо. OpenSSL можна відхилити проміжні значення, що відповідають очікуваним виходом.
Висновок
Створення захищеного протоколу зв'язку в C є відмінним навчальним вправою, але це вимагає безглуздої уваги до деталей. За допомогою важеліювання перевірених імплементацій OpenSSL Diffie‐Hellman, AES‐GCM, і HMAC ви можете створити систему, яка забезпечує конфіденційність, цілісність і автентифікацію. Завжди слідувати криптографічним кращим практикам: використання сильної випадковості, деревої сесії ключі з KDF, ніколи не повторювати неправдиві дані, а також ретельно перевіряти ваші дані. Для будь-якого за межами проекту, розглянемо отримання стандартного протоколу, наприклад TLS 1.3, який був суворим чином, що було розширено оновлений огляд і повністю оновлений огляд