Криптографическая подпись в SJCL строится на алгоритме ECDSA
(Elliptic Curve Digital Signature Algorithm), который используется для
подтверждения целостности и подлинности сообщения без раскрытия
приватного ключа. В библиотеке Stanford JS Crypto Library подписи
реализуются через модуль sjcl.ecc, работающий с
эллиптическими кривыми и объектами ключей.
Криптографическая подпись решает две задачи:
В SJCL подпись формируется не напрямую от строки, а от криптографического хеша сообщения. Это критически важно: ECDSA работает с фиксированной длиной входа.
Типичный поток выглядит так:
SJCL предоставляет встроенные хеш-функции, например SHA-256:
var msg = "Сообщение для подписи";
var hashBits = sjcl.hash.sha256.hash(msg);
Внутренний формат SJCL — это массив 32-битных слов
(bitArray). Именно он используется всеми криптографическими
примитивами библиотеки.
Для работы с подписями используется модуль
sjcl.ecc.ecdsa.
var curve = sjcl.ecc.curves.k256;
var keys = sjcl.ecc.ecdsa.generateKeys(curve, 0);
Структура результата:
keys.sec — приватный ключkeys.pub — публичный ключПриватный ключ используется только для подписи, публичный — для проверки.
Подпись формируется на основе хеша:
var signature = keys.sec.sign(hashBits);
signature — это объект, содержащий координаты подписи
(обычно r и s), закодированные в формате
bitArray.
Для сериализации в строку часто используется кодек Base64:
var sigString = sjcl.codec.base64.fromBits(signature);
Проверка выполняется публичным ключом:
var isValid = keys.pub.verify(hashBits, signature);
Результат:
true — подпись корректнаfalse — сообщение или подпись измененыvar msg = "Данные, требующие подписи";
// 1. Хеширование
var hash = sjcl.hash.sha256.hash(msg);
// 2. Генерация ключей
var keys = sjcl.ecc.ecdsa.generateKeys(sjcl.ecc.curves.k256, 0);
// 3. Подпись
var sig = keys.sec.sign(hash);
// 4. Проверка
var valid = keys.pub.verify(hash, sig);
SJCL использует внутренний формат bitArray, который
неудобен для передачи по сети. Обычно применяется кодирование:
var encodedSig = sjcl.codec.base64.fromBits(sig);
var decodedSig = sjcl.codec.base64.toBits(encodedSig);
Для хранения часто разделяют компоненты подписи:
var sigObj = {
r: sjcl.codec.base64.fromBits(sig[0]),
s: sjcl.codec.base64.fromBits(sig[1])
};
И восстановление:
var sig = [
sjcl.codec.base64.toBits(sigObj.r),
sjcl.codec.base64.toBits(sigObj.s)
];
ECDSA чувствителен к тому, что именно подписывается. Любое изменение строки даёт другой хеш, а значит и другую подпись.
sjcl.hash.sha256.hash("A") !== sjcl.hash.sha256.hash("a");
Поэтому в протоколах важно нормализовать данные перед подписью:
При работе с объектами JavaScript данные сначала сериализуются:
var data = {
user: "alice",
role: "admin"
};
var serialized = JSON.stringify(data);
var hash = sjcl.hash.sha256.hash(serialized);
var sig = keys.sec.sign(hash);
Без детерминированной сериализации возможны несовпадения подписи при повторном вычислении.
function verifyMessage(msg, sig, pubKey) {
var hash = sjcl.hash.sha256.hash(msg);
return pubKey.verify(hash, sig);
}
Если сообщение изменено хотя бы на один символ, проверка провалится.
1. Подпись не от хеша
Неправильный подход:
keys.sec.sign(msg); // ошибка логики
Правильный:
keys.sec.sign(sjcl.hash.sha256.hash(msg));
2. Несовпадение сериализации
JSON без строгого порядка полей приводит к разным хешам:
JSON.stringify({a:1, b:2}) !== JSON.stringify({b:2, a:1})
3. Повторное использование nonce (критическая ошибка ECDSA)
Хотя SJCL управляет этим внутри реализации, в ручных схемах повтор nonce приводит к утечке приватного ключа.
SJCL поддерживает кривую k256, которая эквивалентна
secp256k1 (используется в Bitcoin и многих криптосистемах):
sjcl.ecc.curves.k256
Это делает подписи совместимыми с внешними системами при правильной упаковке форматов.
Типичный протокол выглядит так:
{ message, signature }SJCL позволяет работать с экспортируемыми ключами:
var pubBits = keys.pub.serialize();
var pubKey = sjcl.ecc.deserialize(pubBits);
После чего:
pubKey.verify(hash, signature);
ECDSA в SJCL хранит подпись как пару значений:
r — первая компонентаs — вторая компонентаОбе величины являются числами в поле эллиптической кривой и
кодируются в bitArray.
ECDSA в SJCL обеспечивает:
Критическая безопасность зависит не только от алгоритма, но и от:
В реальных приложениях подпись используется вместе с:
SJCL позволяет комбинировать эти примитивы в единую криптосистему без внешних зависимостей.