ECC-ключи в SJCL представляют собой объекты над эллиптическими кривыми, где основная криптографическая сущность разделяется на публичную и приватную части. Публичная часть описывает точку на кривой (x, y), приватная — скаляр (экспоненту), используемый для генерации этой точки. При переносе ключей между сессиями, хранилищами или сервисами возникает задача их сериализации и последующей десериализации.
В Stanford JavaScript Crypto Library ключи ECC реализованы через
модуль sjcl.ecc. Чаще всего используется схема ElGamal:
sjcl.ecc.elGamal.publicKey — публичный ключsjcl.ecc.elGamal.secretKey — приватный ключsjcl.ecc.curves — набор параметров кривых (например,
c256)Публичный ключ содержит точку на кривой:
Приватный ключ хранит:
Сериализация необходима для:
localStorage или
IndexedDBSJCL не навязывает единого формата хранения, поэтому разработчик выбирает структуру самостоятельно.
ECC-ключ нельзя сохранять напрямую как объект JavaScript. Он содержит
сложные типы (sjcl.bn, точки кривой), которые не
сериализуются через JSON.stringify.
Поэтому используется промежуточное представление:
Публичный ключ состоит из координат точки:
function serializePublicKey(pub) {
return {
curve: pub._curve.name,
x: pub._point.x.toString(),
y: pub._point.y.toString()
};
}
В некоторых реализациях SJCL доступ к точке осуществляется через
методы get():
const point = pub.get();
Тогда сериализация выглядит так:
function serializePublicKey(pub) {
const point = pub.get();
return {
curve: pub._curve.name,
x: point.x.toString(16),
y: point.y.toString(16)
};
}
Использование hex-формата предпочтительно для компактности и совместимости.
Приватный ключ содержит секретный экспонент:
function serializeSecretKey(sec) {
return {
curve: sec._curve.name,
exponent: sec._exponent.toString(16),
pub: serializePublicKey(sec._k.pub)
};
}
Важно сохранять публичную часть внутри приватного ключа, так как она используется при восстановлении объекта.
Часто ключи сохраняются вместе:
function serializeKeyPair(pair) {
return JSON.stringify({
pub: serializePublicKey(pair.pub),
sec: serializeSecretKey(pair.sec)
});
}
На практике результат дополнительно кодируют в base64:
function encodeKeyPair(pair) {
return btoa(serializeKeyPair(pair));
}
Для восстановления ключа необходимо заново создать точку на кривой:
function deserializePublicKey(data) {
const curve = sjcl.ecc.curves[data.curve];
const point = new sjcl.ecc.point(
curve,
sjcl.bn.fromBits(sjcl.codec.hex.toBits(data.x)),
sjcl.bn.fromBits(sjcl.codec.hex.toBits(data.y))
);
return new sjcl.ecc.elGamal.publicKey(curve, point);
}
Если используется строковое представление без bitArray:
const x = new sjcl.bn(data.x, 16);
const y = new sjcl.bn(data.y, 16);
Приватный ключ требует восстановления скаляра и привязки к публичному ключу:
function deserializeSecretKey(data) {
const curve = sjcl.ecc.curves[data.curve];
const exponent = new sjcl.bn(data.exponent, 16);
const pub = deserializePublicKey(data.pub);
return new sjcl.ecc.elGamal.secretKey(curve, exponent, pub);
}
SJCL активно использует bitArray и
codec:
sjcl.codec.hexsjcl.codec.base64sjcl.codec.bytesАльтернативный подход — хранить значения через bitArray:
const xBits = sjcl.codec.hex.toBits(xHex);
const x = sjcl.bn.fromBits(xBits);
Base64 используется при передаче через сеть:
const encoded = sjcl.codec.base64.fromBits(bits);
const decoded = sjcl.codec.base64.toBits(encoded);
Тип sjcl.bn не является примитивом. Его свойства:
.toString(radix)Ошибка, которая часто возникает:
JSON.stringify(bn) // => {}
Поэтому всегда требуется явное преобразование.
Кривая является критически важным параметром:
c192c224c256c384c521Без точного совпадения кривой восстановление ключа невозможно:
const curve = sjcl.ecc.curves["c256"];
Любое несоответствие приводит к ошибкам при криптографических операциях или некорректной проверке подписи.
При хранении сериализованных данных необходимо учитывать:
Типичный подход:
sjcl.encryptНа практике встречаются следующие проблемы:
Использование Number вместо bn приводит к
разрушению ключа.
Попытка интерпретировать base64 как hex приводит к неверным координатам.
Создание точки без привязки к curve делает ключ
некорректным.
ECC точка должна быть строго валидна для заданной кривой.
Для продакшн-систем часто используют компактный формат:
{
c: "c256",
x: "a91f...",
y: "02bc...",
d: "ff01..."
}
Где:
c — криваяx, y — публичная точкаd — приватный скалярТакой формат легко сериализуется, минимален по размеру и удобен для передачи.
В системах с сессиями или токенами восстановление ключей происходит на этапе инициализации криптографического контекста:
publicKey и
secretKeyПосле этого ключи становятся пригодными для: