Открытые ключи получателей используются для шифрования данных таким образом, чтобы расшифровка была возможна только соответствующим закрытым ключом. В контексте 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();
Сериализованный открытый ключ может быть безопасно передан получателю через:
Полученный открытый ключ должен быть восстановлен в объект 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Пример хранения:
localStorage.setItem("recipientPubKey", JSON.stringify(pubKeySerialized));
Извлечение:
const storedKey = JSON.parse(localStorage.getItem("recipientPubKey"));
Ключи должны периодически обновляться для повышения безопасности.
Практики:
Пример структуры:
{
"version": 3,
"createdAt": 1710000000,
"expiresAt": 1720000000,
"publicKey": { ... }
}
При шифровании используется последний действующий ключ.
Если ключ скомпрометирован, он должен быть немедленно отозван.
Механизмы:
Пример:
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);
Передаются:
ciphertexttagВозможные схемы:
1. Централизованная:
2. Децентрализованная:
3. Гибридная:
Поэтому управление открытыми ключами требует дополнительной логики на уровне приложения.
Для более сложных сценариев:
Каждый этап требует контроля целостности и подлинности ключей.