ECDSA (Elliptic Curve Digital Signature Algorithm) основан на алгебраической структуре эллиптических кривых над конечными полями. В отличие от классических схем RSA, безопасность здесь опирается не на факторизацию больших чисел, а на сложность задачи дискретного логарифмирования в группе точек эллиптической кривой.
Эллиптическая кривая задаётся уравнением вида:
над конечным полем ( _p ), где параметры ( a ) и ( b ) определяют конкретную кривую, а условие невырожденности гарантирует отсутствие сингулярностей:
Точки на кривой вместе с операцией сложения формируют абелеву группу. В этой группе и строится криптографическая конструкция.
ECDSA использует идею:
Обратное вычисление ( d ) из ( Q ) считается вычислительно невозможным при правильно выбранных параметрах кривой.
На практике применяются стандартизированные кривые:
Каждая кривая задаёт:
В Jsrsasign выбор кривой определяется строковым идентификатором:
"secp256k1"
"prime256v1"
"P-256"
Схема подписи включает три этапа: генерация ключей, создание подписи и её проверка.
Закрытый ключ:
Открытый ключ:
В Jsrsasign генерация выполняется через KEYUTIL:
const kp = KEYUTIL.generateKeypair("EC", "secp256k1");
const priv = kp.prvKeyObj;
const pub = kp.pubKeyObj;
Либо через импорт PEM:
const privateKey = KEYUTIL.getKey(pemPrivateKey);
const publicKey = KEYUTIL.getKey(pemPublicKey);
Подпись сообщения состоит из пары чисел ( (r, s) ).
Сообщение сначала проходит через криптографическую хеш-функцию:
const msgHash = KJUR.crypto.Util.sha256("message");
Каждая подпись требует уникального случайного числа ( k ):
Где:
Библиотека скрывает математические операции и предоставляет высокоуровневый API.
const sig = new KJUR.crypto.Signature({ "alg": "SHA256withECDSA" });
sig.init(privateKey);
sig.updateString("message");
const signature = sig.sign();
Результат обычно возвращается в формате DER (ASN.1 структура).
const sig = new KJUR.crypto.Signature({
alg: "SHA256withECDSA",
prov: "cryptojs/jsrsa"
});
sig.init(privateKey);
sig.updateString("data");
const sigHex = sig.sign();
ECDSA подпись может быть представлена в нескольких форматах.
Наиболее распространённый формат:
SEQUENCE {
r INTEGER,
s INTEGER
}
Jsrsasign по умолчанию использует DER:
const signatureHex = sig.sign(); // DER в hex
Иногда используется в протоколах:
const sig = new KJUR.crypto.Signature({
alg: "SHA256withECDSA",
format: "RAW"
});
Проверка выполняется с использованием открытого ключа:
Проверяется равенство:
Если равенство выполняется, подпись считается корректной.
const sig = new KJUR.crypto.Signature({ "alg": "SHA256withECDSA" });
sig.init(publicKey);
sig.updateString("message");
const isValid = sig.verify(signature);
Результат:
true — подпись корректнаfalse — подпись нарушена или ключ не соответствуетconst pemPrivate = `
-----BEGIN EC PRIVATE KEY-----
...
-----END EC PRIVATE KEY-----
`;
const pemPublic = `
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
`;
const privKey = KEYUTIL.getKey(pemPrivate);
const pubKey = KEYUTIL.getKey(pemPublic);
const pem = KEYUTIL.getPEM(privKey, "PKCS8PRV");
Jsrsasign может использовать разные backend-реализации:
Конфигурация:
const sig = new KJUR.crypto.Signature({
alg: "SHA256withECDSA",
prov: "cryptojs/jsrsa"
});
Ключевые свойства, определяющие устойчивость схемы:
Повторное использование ( k ) приводит к раскрытию закрытого ключа:
Генерация ( k ) должна быть криптографически стойкой.
Используются:
Слабые хеш-функции снижают стойкость всей схемы.
const kp = KEYUTIL.generateKeypair("EC", "secp256k1");
const priv = kp.prvKeyObj;
const pub = kp.pubKeyObj;
const sig = new KJUR.crypto.Signature({
alg: "SHA256withECDSA"
});
sig.init(priv);
sig.updateString("transaction data");
const signature = sig.sign();
const verifier = new KJUR.crypto.Signature({
alg: "SHA256withECDSA"
});
verifier.init(pub);
verifier.updateString("transaction data");
const result = verifier.verify(signature);
ECDSA отличается от RSA следующими свойствами:
ECDSA применяется в:
В JWT форматах Jsrsasign часто используется для ES256:
const jwt = KJUR.jws.JWS.sign(
"ES256",
{ alg: "ES256" },
{ data: "payload" },
privateKey
);
Библиотека включает несколько ключевых компонентов:
KJUR.crypto.Signature — основной класс подписиKEYUTIL — работа с ключамиKJUR.crypto.ECDSA — низкоуровневая реализация
алгоритмаKJUR.asn1 — работа с ASN.1 структурамиconst ecdsa = new KJUR.crypto.ECDSA({ curve: "secp256k1" });
const sigObj = ecdsa.signHex(hashHex, privateKeyHex);
const valid = ecdsa.verifyHex(hashHex, sigObj, publicKeyHex);
Типичные ошибки:
Jsrsasign возвращает false при неудачной проверке, но не
всегда выбрасывает исключения, что требует явной проверки входных
данных.
ECDSA используется в:
В каждом случае ключевым элементом остаётся проверяемая криптографическая гарантия подлинности данных без раскрытия закрытого ключа.