ECDSA (Elliptic Curve Digital Signature Algorithm) в контексте Web
Crypto API реализуется через интерфейс SubtleCrypto,
предоставляющий низкоуровневые операции цифровой подписи на
эллиптических кривых. Основное назначение механизма — формирование
криптографически устойчивой подписи сообщений и её последующая проверка
с использованием публичного ключа.
ECDSA опирается на свойства эллиптических кривых и задаётся парой
ключей: приватный ключ используется для формирования подписи, публичный
— для проверки её корректности. В Web Crypto API работа с алгоритмом
происходит через window.crypto.subtle.
Создание ключей осуществляется методом generateKey, где
указывается алгоритм ECDSA и параметр кривой. Наиболее
распространённый вариант — P-256 (также известная как
secp256r1), обеспечивающая баланс между производительностью
и криптостойкостью.
const keyPair = await crypto.subtle.generateKey(
{
name: "ECDSA",
namedCurve: "P-256"
},
true,
["sign", "verify"]
);
Параметры генерации:
name: фиксированное значение
"ECDSA"
namedCurve: выбор эллиптической кривой
"P-256""P-384""P-521"extractable: определяет возможность экспорта
ключей
keyUsages: набор операций, разрешённых для
ключа
Результатом является объект CryptoKeyPair,
содержащий:
privateKeypublicKeyECDSA работает с бинарными данными (ArrayBuffer),
поэтому текстовые данные требуют предварительного преобразования.
const encoder = new TextEncoder();
const data = encoder.encode("message for signing");
Преобразование через TextEncoder обеспечивает корректное
представление UTF-8 последовательности байтов.
Подписание выполняется через метод sign. Важным
элементом является выбор хэш-функции, которая предварительно
обрабатывает данные перед применением ECDSA.
const signature = await crypto.subtle.sign(
{
name: "ECDSA",
hash: { name: "SHA-256" }
},
keyPair.privateKey,
data
);
Используемые компоненты:
"ECDSA""SHA-256" (наиболее распространённый
вариант)Результат signature представляет собой
ArrayBuffer, содержащий DER-кодированную подпись.
Верификация выполняется методом verify, где используется
публичный ключ и исходные данные.
const isValid = await crypto.subtle.verify(
{
name: "ECDSA",
hash: { name: "SHA-256" }
},
keyPair.publicKey,
signature,
data
);
Результат — булево значение:
true — подпись корректнаfalse — подпись не соответствует данным или ключуПроцесс проверки включает:
Подпись, возвращаемая Web Crypto API, кодируется в формате ASN.1 DER и содержит два компонента:
r — первая часть подписиs — вторая часть подписиЭти значения формируются как результат вычислений над точками эллиптической кривой и хэш-значением сообщения.
Web Crypto API позволяет сериализовать ключи для хранения или передачи.
const exported = await crypto.subtle.exportKey(
"spki",
keyPair.publicKey
);
const exportedPrivate = await crypto.subtle.exportKey(
"pkcs8",
keyPair.privateKey
);
Форматы:
spki — публичные ключиpkcs8 — приватные ключиconst importedPublicKey = await crypto.subtle.importKey(
"spki",
exported,
{
name: "ECDSA",
namedCurve: "P-256"
},
true,
["verify"]
);
const importedPrivateKey = await crypto.subtle.importKey(
"pkcs8",
exportedPrivate,
{
name: "ECDSA",
namedCurve: "P-256"
},
true,
["sign"]
);
Импорт требует точного соответствия параметров алгоритма исходной конфигурации ключа.
В Web Crypto API ECDSA всегда используется совместно с хэшированием. Хэш-функция выполняет предварительное сжатие данных перед применением математического аппарата эллиптических кривых.
Поддерживаемые значения:
SHA-256SHA-384SHA-512Наиболее распространённая комбинация:
При попытке проверки подписи с другим хэшем результат всегда будет отрицательным, даже при идентичных данных.
ECDSA не работает с текстом напрямую. Любые строки требуют явного
преобразования в ArrayBuffer.
Подписи, созданные на одной кривой (например, P-384), не могут быть проверены ключом другой кривой (например, P-256).
ECDSA в Web Crypto API обладает следующими характеристиками:
extractable: falseconst encoder = new TextEncoder();
const data = encoder.encode("secure message");
const keyPair = await crypto.subtle.generateKey(
{ name: "ECDSA", namedCurve: "P-256" },
true,
["sign", "verify"]
);
const signature = await crypto.subtle.sign(
{ name: "ECDSA", hash: { name: "SHA-256" } },
keyPair.privateKey,
data
);
const result = await crypto.subtle.verify(
{ name: "ECDSA", hash: { name: "SHA-256" } },
keyPair.publicKey,
signature,
data
);
ECDSA основан на дискретном логарифмировании на эллиптических кривых. Приватный ключ участвует в генерации уникального значения подписи для каждого сообщения. Публичный ключ используется для проверки математической связности параметров подписи с исходным сообщением.
Ключевое свойство алгоритма — невозможность восстановления приватного ключа по известной подписи и публичному ключу при корректно выбранных параметрах кривой и хэш-функции.