Управление открытыми ключами получателей

Открытые ключи получателей используются для шифрования данных таким образом, чтобы расшифровка была возможна только соответствующим закрытым ключом. В контексте SJCL управление такими ключами не предоставляется «из коробки» как полноценная инфраструктура (PKI), однако библиотека предоставляет низкоуровневые примитивы, на основе которых строятся безопасные механизмы обмена.

Основные задачи управления открытыми ключами:

  • генерация и хранение ключевых пар
  • безопасная передача открытых ключей
  • проверка подлинности ключа
  • обновление и отзыв ключей

Генерация ключевой пары

SJCL поддерживает асимметричную криптографию через эллиптические кривые (ECC). Для генерации пары ключей используется модуль sjcl.ecc.

const keys = sjcl.ecc.elGamal.generateKeys(256);

const publicKey = keys.pub;
const privateKey = keys.sec;
  • 256 — размер кривой (например, secp256k1)
  • pub — открытый ключ
  • sec — закрытый ключ

Открытый ключ предназначен для распространения, закрытый — должен храниться строго конфиденциально.


Представление и сериализация ключей

Для передачи или хранения ключей требуется их сериализация. SJCL предоставляет методы для преобразования ключей в JSON-совместимый формат.

const pubKeySerialized = publicKey.serialize();
const secKeySerialized = privateKey.serialize();

Сериализованный открытый ключ может быть безопасно передан получателю через:

  • API
  • файл конфигурации
  • базу данных
  • протокол обмена (например, HTTPS)

Десериализация ключей

Полученный открытый ключ должен быть восстановлен в объект SJCL:

const receivedPubKey = sjcl.ecc.elGamal.publicKey(
    sjcl.ecc.curves.c256,
    pubKeySerialized.point
);

Важно использовать ту же кривую, что и при генерации ключа.


Проверка подлинности открытого ключа

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

1. Хэш-проверка (fingerprint):

const fingerprint = sjcl.codec.hex.fromBits(
    sjcl.hash.sha256.hash(JSON.stringify(pubKeySerialized))
);

Сравнение отпечатка с заранее известным значением.

2. Подпись ключа доверенной стороной: Открытый ключ подписывается приватным ключом центра доверия:

const signature = trustedPrivateKey.sign(
    sjcl.hash.sha256.hash(JSON.stringify(pubKeySerialized))
);

Проверка подписи:

trustedPublicKey.verify(hash, signature);

3. TLS/HTTPS канал: Передача ключа через защищённое соединение снижает риск подмены.


Хранение открытых ключей

Открытые ключи могут храниться:

  • в localStorage
  • в IndexedDB
  • на сервере
  • в кэше приложения

Пример хранения:

localStorage.setItem("recipientPubKey", JSON.stringify(pubKeySerialized));

Извлечение:

const storedKey = JSON.parse(localStorage.getItem("recipientPubKey"));

Обновление ключей

Ключи должны периодически обновляться для повышения безопасности.

Практики:

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

Пример структуры:

{
  "version": 3,
  "createdAt": 1710000000,
  "expiresAt": 1720000000,
  "publicKey": { ... }
}

При шифровании используется последний действующий ключ.


Отзыв ключей

Если ключ скомпрометирован, он должен быть немедленно отозван.

Механизмы:

  • список отозванных ключей (CRL)
  • серверная проверка статуса
  • флаг компрометации

Пример:

const revokedKeys = ["fingerprint1", "fingerprint2"];

if (revokedKeys.includes(fingerprint)) {
    throw new Error("Ключ отозван");
}

Использование открытого ключа для шифрования

После проверки и загрузки ключа:

const plaintext = "секретное сообщение";

const encrypted = publicKey.kem();

const symmetricKey = encrypted.key;
const tag = encrypted.tag;

Затем симметричный ключ используется с AES:

const ciphertext = sjcl.encrypt(symmetricKey, plaintext);

Передаются:

  • ciphertext
  • tag

Архитектура распределения ключей

Возможные схемы:

1. Централизованная:

  • сервер хранит все открытые ключи
  • клиенты получают ключи через API

2. Децентрализованная:

  • пользователи обмениваются ключами напрямую
  • используется WebRTC, QR-коды, файлы

3. Гибридная:

  • ключи публикуются на сервере
  • подтверждаются вручную (fingerprint)

Безопасные практики

  • никогда не доверять открытым ключам без проверки
  • использовать HTTPS для передачи ключей
  • избегать хранения ключей в открытом виде без необходимости
  • логировать операции изменения ключей
  • использовать криптографически стойкие кривые (не менее 256 бит)

Ограничения SJCL

  • отсутствие встроенной PKI
  • нет автоматического управления сертификатами
  • разработчик отвечает за инфраструктуру доверия

Поэтому управление открытыми ключами требует дополнительной логики на уровне приложения.


Расширение функциональности

Для более сложных сценариев:

  • интеграция с WebCrypto API
  • использование сторонних PKI-сервисов
  • добавление цифровых сертификатов (X.509)
  • реализация протоколов обмена ключами (например, Diffie-Hellman поверх SJCL)

Типовой поток работы

  1. Генерация ключевой пары
  2. Публикация открытого ключа
  3. Получение и проверка ключа отправителем
  4. Шифрование данных
  5. Передача зашифрованного сообщения
  6. Расшифровка получателем

Каждый этап требует контроля целостности и подлинности ключей.