Глава 2. Аппаратный ключ: Криптография на кончиках пальцев
2026-02-23
Аннотация
В этой главе мы погружаемся в прошивку (main.cpp) аппаратного ключа GuardianT. Мы разберем, почему программное шифрование на смартфонах — это иллюзия безопасности, и покажем, как реализовать криптостойкий алгоритм AES-256 на микроконтроллере ESP8266 с ограниченными ресурсами.
2.1. Проблема доверия к кремнию
Современный смартфон — это "черный ящик" с миллионами строк закрытого кода. Даже если вы используете мессенджер с End-to-End шифрованием, ключи генерируются и хранятся в операционной системе (Android/iOS), которая имеет к ним доступ.
Решение GuardianT: Вынести криптографию в отдельное устройство, которое физически не способно "слить" данные, так как не имеет прямого доступа в Интернет для передачи ключей.
Мы используем ESP8266 в качестве криптопроцессора. Это решение продиктовано философией "Low Tech": чем проще устройство, тем меньше в нем скрытых уязвимостей (Backdoors).
2.2. Разбор main.cpp: Архитектура прошивки
Прошивка написана на C++ с использованием фреймворка Arduino. Основной цикл loop() работает как конечный автомат (State Machine), ожидая команды через Serial-порт (USB) от смартфона.
2.2.1. Выбор алгоритма: Классический AES-256
В данной реализации мы используем проверенный временем стандарт AES-256 в режиме CBC (Cipher Block Chaining).
- Совместимость: AES является промышленным стандартом, для которого существуют оптимизированные библиотеки (AESLib) даже для 8-битных архитектур.
- Надежность: Использование 256-битного ключа обеспечивает защиту от перебора на десятилетия вперед.
Вот как выглядит функция шифрования в коде:
/* Фрагмент main.cpp */
#include <AESLib.h> // Библиотека для AES шифрования
String encryptMessage(String plainText, uint8_t* key) {
AESLib aesLib;
// 1. Генерация случайного вектора инициализации (IV)
uint8_t iv[16];
for (int i = 0; i < 16; i++) iv[i] = (uint8_t)random(256);
// 2. PKCS7 Padding (выравнивание блока до 16 байт)
int textLen = plainText.length();
int paddedLen = (textLen / 16 + 1) * 16;
uint8_t *input = new uint8_t[paddedLen];
// ... код заполнения паддингом ...
// 3. Шифрование AES-256
// key - 32 байта (256 бит)
aesLib.encrypt(input, paddedLen, output, key, 256, ivWorking);
// 4. Упаковка: IV + Шифротекст -> Base64
// IV необходим получателю для расшифровки первого блока
int totalLen = 16 + paddedLen;
memcpy(combined, iv, 16);
memcpy(combined + 16, output, paddedLen);
return base64::encode(combined, totalLen);
}
2.3. Аппаратное шифрование (Crypto Core)
ESP32 имеет встроенный криптографический ускоритель. Мы используем библиотеку mbedtls, оптимизированную под архитектуру Xtensa.
Ключевой момент: Приватный ключ никогда не покидает переменную ctx внутри функции.
// Firmware/Core/Crypto.cpp
#include "mbedtls/chacha20.h"
// Секретный ключ хранится в защищенной области памяти (NVS)
// и загружается только в момент шифрования.
static uint8_t device_private_key[32];
void encrypt_packet(const uint8_t* plaintext, size_t len, uint8_t* output, uint8_t* nonce) {
mbedtls_chacha20_context ctx;
mbedtls_chacha20_init(&ctx);
// 1. Инициализация контекста с ключом и одноразовым номером (Nonce)
mbedtls_chacha20_setup(&ctx, device_private_key);
mbedtls_chacha20_starts(&ctx, nonce, 0);
// 2. Шифрование потока
// Данные шифруются "на лету", не создавая копий в куче (Heap)
mbedtls_chacha20_update(&ctx, len, plaintext, output);
// 3. Очистка контекста (Zeroization)
// Критически важно удалить следы ключа из RAM сразу после операции
mbedtls_chacha20_free(&ctx);
}
2.4. Защита от физического взлома
Что если устройство украдут?
- Flash Encryption: Мы активируем шифрование флеш-памяти ESP32. Без ключа, который "зашит" в eFuse предохранители процессора, прошивку невозможно считать.
- Secure Boot: Устройство загружает только подписанную нами прошивку. Залить вредоносный код невозможно.
«Безопасность — это не только код, это физика».