Хеширование — это процесс преобразования произвольного объёма входных данных в фиксированную строку байтов (хеш). В контексте Web Crypto API особое значение имеет работа именно с бинарными данными, поскольку большинство криптографических операций происходит на уровне байтов, а не строк.
Браузерный API ориентирован на использование типов
ArrayBuffer, TypedArray и
DataView. Это обеспечивает предсказуемость и безопасность
при обработке данных, исключая неоднозначности, связанные с кодировками
строк.
crypto.subtle.digestОсновным инструментом для хеширования является метод:
crypto.subtle.digest(algorithm, data)
Параметры:
algorithm — строка с именем алгоритма
("SHA-1", "SHA-256", "SHA-384",
"SHA-512")data — бинарные данные (ArrayBuffer или
TypedArray)Возвращаемое значение:
Promise, который разрешается в ArrayBuffer
с результатом хешированияWeb Crypto API предоставляет доступ к следующим алгоритмам хеширования:
Строки необходимо явно преобразовывать в бинарный формат. Для этого
используется TextEncoder:
const encoder = new TextEncoder();
const data = encoder.encode("Пример строки");
Результат — Uint8Array, который можно напрямую передать
в digest.
async function hashString(str) {
const encoder = new TextEncoder();
const data = encoder.encode(str);
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
return new Uint8Array(hashBuffer);
}
Работа с бинарными данными часто возникает при обработке файлов, сетевых пакетов или буферов.
async function hashBuffer(buffer) {
const hash = await crypto.subtle.digest("SHA-512", buffer);
return new Uint8Array(hash);
}
Если данные представлены в виде Uint8Array, их можно
передать напрямую:
const data = new Uint8Array([1, 2, 3, 4]);
const hash = await crypto.subtle.digest("SHA-256", data);
Хеш возвращается в виде бинарного массива. Для отображения его обычно переводят в шестнадцатеричную строку:
function toHex(buffer) {
return Array.from(new Uint8Array(buffer))
.map(b => b.toString(16).padStart(2, "0"))
.join("");
}
Использование:
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
const hexHash = toHex(hashBuffer);
Хеширование файлов требует чтения их содержимого как
ArrayBuffer:
async function hashFile(file) {
const buffer = await file.arrayBuffer();
const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
return toHex(hashBuffer);
}
1. Асинхронность Метод digest всегда
возвращает Promise, даже для небольших данных.
2. Отсутствие потокового хеширования Web Crypto API не поддерживает инкрементальное хеширование (как, например, в Node.js). Все данные должны быть доступны целиком.
3. Неизменяемость входных данных Переданный буфер не модифицируется в процессе хеширования.
4. Производительность Нативная реализация в браузере значительно быстрее JavaScript-библиотек.
Из-за отсутствия потокового API возникает проблема при работе с большими файлами. Возможные подходы:
ArrayBuffer и TypedArrayWeb Crypto API принимает различные формы бинарных данных:
// ArrayBuffer
const buffer = new ArrayBuffer(8);
// TypedArray
const uint8 = new Uint8Array(buffer);
// DataView
const view = new DataView(buffer);
Все эти структуры можно передавать в digest.
Сравнение хешей должно выполняться осторожно, особенно в криптографических сценариях. Простое сравнение строк может быть уязвимо к тайминговым атакам.
Безопасный вариант — побайтовое сравнение:
function compareHashes(a, b) {
if (a.length !== b.length) return false;
let result = 0;
for (let i = 0; i < a.length; i++) {
result |= a[i] ^ b[i];
}
return result === 0;
}
Хеширование часто используется вместе с:
crypto.subtle.sign — для цифровых подписейcrypto.subtle.verify — для проверки подписиcrypto.subtle.deriveKey — для генерации ключейОшибки возникают при:
Пример обработки:
try {
const hash = await crypto.subtle.digest("SHA-256", data);
} catch (e) {
console.error("Ошибка хеширования:", e);
}
Web Crypto API доступен только в защищённой среде:
Попытка использования в небезопасном контексте приведёт к ошибке.
Ошибки часто возникают из-за неправильной обработки строк:
"abc" в UTF-8 ≠ "abc" в UTF-16TextEncoder для предсказуемого
результатаasync function hashExample() {
const encoder = new TextEncoder();
const data = encoder.encode("Hello, WebCrypto");
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map(b => b.toString(16).padStart(2, "0")).join("");
console.log(hashHex);
}
hashExample();
awaitArrayBuffer
вместо строки)Хеширование бинарных данных в Web Crypto API — это строго типизированный, асинхронный процесс, требующий точного контроля форматов данных и понимания особенностей работы с буферами.