Гибридное шифрование сочетает в себе два подхода:
Такая схема устраняет основные недостатки каждого подхода:
В библиотеке SJCL отсутствует «готовый» API для гибридного шифрования, но все необходимые primitives присутствуют.
Ключевые модули библиотеки:
sjcl.cipher.aes — симметричное шифрованиеsjcl.mode.gcm / sjcl.mode.ccm — режимы
шифрованияsjcl.ecc — эллиптическая криптографияsjcl.hash.sha256 — хешированиеsjcl.misc.hkdf — генерация ключейsjcl.random — криптографически стойкий генераторГенерация случайного симметричного ключа
Шифрование данных симметричным алгоритмом
Генерация временной ECC-пары ключей
Вычисление общего секрета через ECDH
Производный ключ используется для шифрования симметричного ключа
Передача:
const aesKey = sjcl.random.randomWords(8, 0); // 256 бит
Используется массив слов (bitArray), являющийся базовым
форматом данных в SJCL.
const iv = sjcl.random.randomWords(3, 0); // 96 бит
const aes = new sjcl.cipher.aes(aesKey);
const plaintext = sjcl.codec.utf8String.toBits("Секретные данные");
const ciphertext = sjcl.mode.gcm.encrypt(
aes,
plaintext,
iv
);
Особенности:
const curve = sjcl.ecc.curves.c256;
const senderKeys = sjcl.ecc.elGamal.generateKeys(curve, 0);
const recipientKeys = sjcl.ecc.elGamal.generateKeys(curve, 0);
В реальной системе:
const sharedSecret = senderKeys.sec.dh(recipientKeys.pub);
На стороне получателя:
const sharedSecretReceiver = recipientKeys.sec.dh(senderKeys.pub);
Оба значения идентичны.
Общий секрет не используется напрямую — он пропускается через функцию вывода ключей:
const derivedKey = sjcl.misc.hkdf(
sharedSecret,
256,
null,
"hybrid encryption"
);
Результат — криптографически устойчивый ключ длиной 256 бит.
const aesKeyBits = aesKey;
const wrapIv = sjcl.random.randomWords(3, 0);
const wrapCipher = new sjcl.cipher.aes(derivedKey);
const encryptedAesKey = sjcl.mode.gcm.encrypt(
wrapCipher,
aesKeyBits,
wrapIv
);
Передаваемый объект должен содержать:
const payload = {
ciphertext: sjcl.codec.base64.fromBits(ciphertext),
iv: sjcl.codec.base64.fromBits(iv),
encryptedKey: sjcl.codec.base64.fromBits(encryptedAesKey),
wrapIv: sjcl.codec.base64.fromBits(wrapIv),
senderPubKey: senderKeys.pub.get()
};
Публичный ключ отправителя сериализуется в JSON-совместимую структуру.
const senderPub = new sjcl.ecc.elGamal.publicKey(
curve,
payload.senderPubKey
);
const sharedSecret = recipientKeys.sec.dh(senderPub);
const derivedKey = sjcl.misc.hkdf(
sharedSecret,
256,
null,
"hybrid encryption"
);
const wrapCipher = new sjcl.cipher.aes(derivedKey);
const decryptedAesKey = sjcl.mode.gcm.decrypt(
wrapCipher,
sjcl.codec.base64.toBits(payload.encryptedKey),
sjcl.codec.base64.toBits(payload.wrapIv)
);
const aes = new sjcl.cipher.aes(decryptedAesKey);
const plaintextBits = sjcl.mode.gcm.decrypt(
aes,
sjcl.codec.base64.toBits(payload.ciphertext),
sjcl.codec.base64.toBits(payload.iv)
);
const plaintext = sjcl.codec.utf8String.fromBits(plaintextBits);
Перед использованием sjcl.random требуется накопление
энтропии:
sjcl.random.startCollectors();
В браузере энтропия поступает из:
Проверка готовности:
sjcl.random.isReady();
1. Эфемерные ключи
2. Уникальность IV
3. Проверка аутентичности
4. Контекст HKDF
"hybrid encryption" должна быть фиксированной и
согласованной5. Размеры ключей
Аутентификация отправителя
Добавление цифровой подписи:
const signature = senderSigningKey.sign(hash);
Проверка:
senderPubKey.verify(hash, signature);
Дополнительные данные (AAD)
GCM поддерживает аутентифицированные данные:
sjcl.mode.gcm.encrypt(aes, data, iv, aad);
Используется для защиты метаданных.
Сжатие перед шифрованием
Позволяет:
Гибридное шифрование на базе SJCL применяется в:
Реализация требует строгого контроля всех этапов: от генерации случайности до управления ключами и формата сообщений.