В основе большинства современных протоколов защищённого обмена ключами лежит задача получения общего секрета между двумя сторонами при наличии небезопасного канала связи. Библиотека SJCL реализует этот механизм через поддержку эллиптической криптографии и классического подхода Диффи–Хеллмана, адаптированного для JavaScript-окружения.
Вычисление общего секрета опирается на асимметричную криптографию:
Ключевое свойство: обе стороны получают одинаковое значение, не передавая его напрямую.
SJCL использует реализацию эллиптических кривых через модуль
sjcl.ecc. На практике применяется схема ElGamal и ECDH
(Elliptic Curve Diffie–Hellman).
Основные компоненты:
sjcl.ecc.curves.c256 — стандартная кривая (например,
256-битная)sjcl.ecc.elGamal — реализация ключевой парыgenerateKeys() и dh() для обмена
секретомКаждая сторона начинает с создания ключевой пары:
const keypairA = sjcl.ecc.elGamal.generateKeys(256);
const keypairB = sjcl.ecc.elGamal.generateKeys(256);
Внутренняя структура:
keypairA.sec — приватный ключkeypairA.pub — публичный ключПубличный ключ можно безопасно передавать другой стороне.
После генерации происходит обмен публичными компонентами:
const pubA = keypairA.pub;
const pubB = keypairB.pub;
Передача публичных ключей не требует шифрования, так как они не раскрывают приватную часть.
Ключевая операция выполняется через метод dh()
(Diffie–Hellman):
const secretA = keypairA.sec.dh(pubB);
const secretB = keypairB.sec.dh(pubA);
secretA и secretB будут идентичны, несмотря
на различие входных параметров.
Это значение представляет собой точку на эллиптической кривой или её внутреннее представление в виде большого числа.
Сырой общий секрет не используется напрямую для шифрования. Его необходимо преобразовать в симметричный ключ.
Обычно применяется хеширование:
const hashedSecretA = sjcl.hash.sha256.hash(secretA);
const hashedSecretB = sjcl.hash.sha256.hash(secretB);
Результат:
После хеширования ключ может быть использован в AES:
const key = new sjcl.cipher.aes(hashedSecretA);
Теперь возможно шифрование данных между сторонами, которые никогда напрямую не передавали ключ.
Типичный процесс обмена выглядит следующим образом:
SJCL оперирует несколькими уровнями абстракции:
sjcl.bn — большие числаОбщий секрет на низком уровне представляет собой результат скалярного умножения:
S = a * B = b * A
где:
a, b — приватные ключиA, B — публичные точкиМетод dh():
Пример:
const sharedPoint = keypairA.sec.dh(keypairB.pub);
Без дополнительной обработки общий секрет может:
Поэтому используется KDF-подход: хеширование или PBKDF2.
SJCL содержит реализацию PBKDF2:
const derivedKey = sjcl.misc.pbkdf2(secretA, "salt", 1000, 256);
Параметры:
salt — дополнительная энтропияМеханизм ECDH в SJCL используется как базовый строительный блок для:
Для передачи публичного ключа используется JSON-представление:
const exported = sjcl.ecc.elGamal.publicKey.prototype.toJSON.call(keypairA.pub);
И обратное восстановление:
const restored = new sjcl.ecc.elGamal.publicKey(256, exported);
Типичные проблемы:
Безопасность вычисления общего секрета в SJCL основана на:
При выполнении dh():
Это важно для понимания производительности в JavaScript-среде.
Общий секрет часто передаётся в:
sjcl.cipher.aessjcl.mode.gcmsjcl.codec для сериализацииТипичный поток:
ECDH → SHA256 → AES key → encryption
Полный криптографический конвейер в SJCL для общего секрета:
KeyGen → PublicKeyExchange → DH → KDF → SymmetricCrypto
Каждый этап снижает риск утечки информации и повышает стойкость всей схемы.