В криптографических операциях основой является работа с точными
байтовыми последовательностями. В JavaScript такие данные чаще всего
представлены в виде ArrayBuffer, Uint8Array
или строк в формате Base64/Hex.
Библиотека Jsrsasign оперирует в основном строковыми представлениями, поэтому перед подписью бинарных данных требуется корректное преобразование.
Ключевые форматы представления:
Наиболее универсальным вариантом считается Base64, так как он стабильно работает в браузерах и Node.js и не зависит от кодировок.
Перед формированием цифровой подписи бинарные данные должны быть преобразованы в строку, пригодную для криптографического хеширования.
Типичный сценарий включает:
ArrayBufferUint8ArrayПример преобразования:
function arrayBufferToBase64(buffer) {
let binary = '';
const bytes = new Uint8Array(buffer);
const len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
Jsrsasign предоставляет высокоуровневый API через
KJUR.crypto.Signature.
Алгоритм подписи зависит от выбранной хеш-функции:
Пример создания подписи:
const sig = new KJUR.crypto.Signature({
alg: "SHA256withRSA"
});
sig.init(privateKeyPem);
const base64Data = arrayBufferToBase64(fileArrayBuffer);
sig.updateString(base64Data);
const signature = sig.sign();
При работе с файлами важно учитывать, что подпись должна отражать точное содержимое, а не его визуальное представление.
Типичный процесс в браузере:
const fileInput = document.querySelector("input[type=file]");
fileInput.addEventListener("change", async (event) => {
const file = event.target.files[0];
const arrayBuffer = await file.arrayBuffer();
const base64Data = arrayBufferToBase64(arrayBuffer);
const sig = new KJUR.crypto.Signature({
alg: "SHA256withRSA"
});
sig.init(privateKeyPem);
sig.updateString(base64Data);
const signature = sig.sign();
});
При этом важно, что:
В ряде сценариев применяется предварительное хеширование данных перед подписью.
Это снижает нагрузку на алгоритм RSA и позволяет работать с большими файлами.
Пример:
const md = new KJUR.crypto.MessageDigest({ alg: "sha256", prov: "cryptojs" });
md.updateHex(KJUR.lang.String.fromCharCode(...new Uint8Array(arrayBuffer)));
const hash = md.digest();
Далее подпись формируется уже от хеша:
const sig = new KJUR.crypto.Signature({ alg: "SHA256withRSA" });
sig.init(privateKeyPem);
sig.updateHex(hash);
const signature = sig.sign();
Hex-представление часто используется при работе с низкоуровневыми криптографическими системами.
Преобразование:
function bufferToHex(buffer) {
return Array.from(new Uint8Array(buffer))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
}
Использование:
const hexData = bufferToHex(arrayBuffer);
const sig = new KJUR.crypto.Signature({
alg: "SHA256withRSA"
});
sig.init(privateKeyPem);
sig.updateHex(hexData);
const signature = sig.sign();
Hex позволяет избежать проблем с бинарными символами и кодировками.
Проверка выполняется с использованием публичного ключа.
const sig = new KJUR.crypto.Signature({
alg: "SHA256withRSA"
});
sig.init(publicKeyPem);
sig.updateString(base64Data);
const isValid = sig.verify(signature);
Ключевые условия корректной проверки:
При обработке больших бинарных данных возникают ограничения памяти, особенно в браузере.
Практика обработки включает:
Пример концепции чанков:
const sig = new KJUR.crypto.Signature({
alg: "SHA256withRSA"
});
sig.init(privateKeyPem);
for (const chunk of chunks) {
sig.updateString(arrayBufferToBase64(chunk));
}
const signature = sig.sign();
Jsrsasign поддерживает несколько стандартов криптографических форматов:
Подписи, сформированные библиотекой, совместимы с:
Часто возникающие проблемы связаны не с алгоритмом, а с преобразованием данных:
Корректная схема всегда опирается на неизменяемое представление массива байтов.
Цифровая подпись позволяет фиксировать состояние файла в момент подписания.
Любое изменение:
приводит к полной невалидности подписи.
Поэтому структура проверки всегда включает:
Подпись бинарных данных используется в следующих сценариях:
Jsrsasign позволяет реализовать эти механизмы без зависимости от внешних криптосервисов, используя чистый JavaScript-стек.