ECIES (Elliptic Curve Integrated Encryption Scheme) — гибридная криптографическая схема, сочетающая преимущества асимметричного шифрования на эллиптических кривых и симметричных алгоритмов. Основная цель — обеспечить конфиденциальность, целостность и аутентичность передаваемых данных.
Ключевая идея:
Структура ECIES:
В библиотеке SJCL отсутствует прямой «высокоуровневый» API ECIES, однако все необходимые примитивы присутствуют:
sjcl.eccsjcl.misc.hkdf или PBKDF2Это требует ручной сборки схемы ECIES.
Используется стандартная генерация ключей на эллиптической кривой:
var keys = sjcl.ecc.elGamal.generateKeys(256);
var publicKey = keys.pub;
var privateKey = keys.sec;
Поддерживаемые кривые:
Для каждого шифрования создаётся временная пара ключей:
var ephemeral = sjcl.ecc.elGamal.generateKeys(256);
Это обеспечивает:
Общий секрет формируется с использованием приватного ключа отправителя и публичного ключа получателя:
var sharedSecret = ephemeral.sec.dh(publicKey);
Результат — битовый массив (bitArray), который нельзя
использовать напрямую.
Общий секрет преобразуется в ключи шифрования и MAC:
var derivedKey = sjcl.misc.hkdf(sharedSecret, 256);
Разделение ключей:
var encryptionKey = sjcl.bitArray.bitSlice(derivedKey, 0, 128);
var macKey = sjcl.bitArray.bitSlice(derivedKey, 128, 256);
Используется AES (обычно в режиме CCM или GCM):
var iv = sjcl.random.randomWords(4);
var plaintext = sjcl.codec.utf8String.toBits("secret message");
var ciphertext = sjcl.mode.ccm.encrypt(
new sjcl.cipher.aes(encryptionKey),
plaintext,
iv
);
Для защиты целостности:
var mac = new sjcl.misc.hmac(macKey).encrypt(ciphertext);
Шифротекст состоит из:
Пример структуры:
{
ephemeralPub: ephemeral.pub.get(),
iv: iv,
ciphertext: ciphertext,
mac: mac
}
var ephemeralPub = new sjcl.ecc.elGamal.publicKey(
sjcl.ecc.curves.c256,
received.ephemeralPub
);
var sharedSecret = privateKey.dh(ephemeralPub);
var derivedKey = sjcl.misc.hkdf(sharedSecret, 256);
var encryptionKey = sjcl.bitArray.bitSlice(derivedKey, 0, 128);
var macKey = sjcl.bitArray.bitSlice(derivedKey, 128, 256);
var computedMac = new sjcl.misc.hmac(macKey).encrypt(received.ciphertext);
if (!sjcl.bitArray.equal(computedMac, received.mac)) {
throw new Error("MAC verification failed");
}
var plaintext = sjcl.mode.ccm.decrypt(
new sjcl.cipher.aes(encryptionKey),
received.ciphertext,
received.iv
);
var message = sjcl.codec.utf8String.fromBits(plaintext);
Использование одного ключа для шифрования и MAC недопустимо. ECIES строго требует разделения.
Каждая операция шифрования должна использовать новый ключ.
Это защищает от атак типа padding oracle и модификации данных.
Используется:
sjcl.random.randomWords(...)
Перед использованием необходимо инициализировать энтропию.
Все данные представлены в формате sjcl.bitArray. Для
конверсии:
sjcl.codec.utf8String.toBits(str);
sjcl.codec.hex.fromBits(bits);
В отличие от некоторых библиотек, SJCL предоставляет только примитивы, что:
Рекомендуется:
Позволяет аутентифицировать дополнительные данные:
sjcl.mode.ccm.encrypt(cipher, data, iv, aad);
KDF может включать:
Можно выбирать разные уровни безопасности:
sjcl.ecc.curves.c384
sjcl.ecc.curves.c521
Сводный алгоритм:
Расшифрование:
function eciesEncrypt(pubKey, message) {
var eph = sjcl.ecc.elGamal.generateKeys(256);
var secret = eph.sec.dh(pubKey);
var key = sjcl.misc.hkdf(secret, 256);
var encKey = sjcl.bitArray.bitSlice(key, 0, 128);
var macKey = sjcl.bitArray.bitSlice(key, 128, 256);
var iv = sjcl.random.randomWords(4);
var pt = sjcl.codec.utf8String.toBits(message);
var ct = sjcl.mode.ccm.encrypt(new sjcl.cipher.aes(encKey), pt, iv);
var mac = new sjcl.misc.hmac(macKey).encrypt(ct);
return {
eph: eph.pub.get(),
iv: iv,
ct: ct,
mac: mac
};
}
Такой подход формирует полноценную реализацию ECIES на основе примитивов SJCL.