crypto.subtle.sign — это метод Web Crypto API, предназначенный для
создания цифровой подписи над произвольными данными с использованием
криптографического ключа. Результат операции представляет собой бинарную
подпись (ArrayBuffer), которая затем может быть использована для
проверки целостности данных и аутентичности отправителя через
crypto.subtle.verify.
Метод работает асинхронно и возвращает
Promise<ArrayBuffer>, что позволяет выполнять
криптографические операции без блокировки основного потока выполнения
JavaScript.
crypto.subtle.sign(algorithm, key, data)
Объект или строка, определяющая используемый алгоритм подписи. Поддерживаемые варианты:
"HMAC""RSASSA-PKCS1-v1_5""RSA-PSS""ECDSA"Каждый алгоритм требует специфической конфигурации.
Примеры:
{ name: "HMAC", hash: "SHA-256" }
{
name: "RSA-PSS",
saltLength: 32
}
{
name: "ECDSA",
hash: "SHA-256"
}
Объект CryptoKey, содержащий приватный ключ,
используемый для генерации подписи.
Ключ должен быть создан или импортирован с соответствующим назначением:
sign должен быть включён в keyUsagesПример генерации:
const keyPair = await crypto.subtle.generateKey(
{
name: "ECDSA",
namedCurve: "P-256"
},
true,
["sign", "verify"]
);
Данные, которые необходимо подписать. Представляют собой
BufferSource:
ArrayBufferTypedArray (Uint8Array, etc.)Перед подписанием данные обычно кодируются в бинарный формат:
const encoder = new TextEncoder();
const data = encoder.encode("сообщение для подписи");
Метод возвращает:
Promise<ArrayBuffer>
Это бинарная подпись, формат которой зависит от алгоритма:
Используется симметричный ключ. Подходит для проверки целостности данных в доверенной среде.
const key = await crypto.subtle.generateKey(
{
name: "HMAC",
hash: "SHA-256"
},
true,
["sign", "verify"]
);
const signature = await crypto.subtle.sign(
"HMAC",
key,
data
);
Особенность: один и тот же ключ используется для подписи и проверки.
Современный RSA-алгоритм подписи с вероятностным паддингом. Более безопасен, чем PKCS#1 v1.5.
const signature = await crypto.subtle.sign(
{
name: "RSA-PSS",
saltLength: 32
},
privateKey,
data
);
Критически важно, чтобы saltLength совпадал при
верификации.
Более старый RSA-алгоритм. Широко поддерживается, но менее устойчив к некоторым типам атак.
const signature = await crypto.subtle.sign(
{
name: "RSASSA-PKCS1-v1_5"
},
privateKey,
data
);
Алгоритм на эллиптических кривых. Используется в современных системах, включая криптовалютные и TLS-сертификаты.
const signature = await crypto.subtle.sign(
{
name: "ECDSA",
hash: "SHA-256"
},
privateKey,
data
);
Особенность: подпись возвращается в формате DER и требует дополнительного разбора при низкоуровневой работе.
const encoder = new TextEncoder();
const data = encoder.encode("важное сообщение");
// генерация ключевой пары
const keyPair = await crypto.subtle.generateKey(
{
name: "RSA-PSS",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256"
},
true,
["sign", "verify"]
);
// создание подписи
const signature = await crypto.subtle.sign(
{
name: "RSA-PSS",
saltLength: 32
},
keyPair.privateKey,
data
);
Web Crypto API работает исключительно с бинарными данными. Поэтому почти всегда требуется преобразование:
const encoder = new TextEncoder();
const data = encoder.encode("пример");
function toBase64(buffer) {
const bytes = new Uint8Array(buffer);
let binary = "";
bytes.forEach(b => binary += String.fromCharCode(b));
return btoa(binary);
}
Если ключ не создан с "sign", метод завершится
ошибкой:
InvalidAccessError
Ключ и алгоритм должны соответствовать друг другу:
Передаваемые данные должны быть BufferSource, строки
недопустимы напрямую.
Метод sign всегда используется вместе с
verify:
sign — создаёт подписьverify — проверяет подписьconst valid = await crypto.subtle.verify(
{
name: "RSA-PSS",
saltLength: 32
},
publicKey,
signature,
data
);
Возвращаемый ArrayBuffer не имеет универсального
текстового формата. Его структура зависит от алгоритма:
При необходимости передачи подписи в сеть используется кодирование: