Хеш-функция в криптографии преобразует произвольный набор данных в фиксированную последовательность байтов. Основное свойство — детерминированность: одинаковые входные данные всегда дают одинаковый результат. Любое изменение исходного сообщения, даже на один бит, приводит к радикально отличающемуся хешу.
В TweetNaCl.js реализована криптографическая хеш-функция на основе
SHA-512. В библиотеке nacl.js доступ к ней предоставляется через функцию
nacl.hash.
const nacl = require('tweetnacl');
nacl.util = require('tweetnacl-util');
const message = nacl.util.decodeUTF8("hello world");
const hash = nacl.hash(message);
console.log(nacl.util.encodeBase64(hash));
Результатом является 64-байтный массив, представляющий SHA-512 хеш входного сообщения.
TweetNaCl.js работает исключительно с бинарными данными в формате
Uint8Array. Любые строковые значения должны быть
преобразованы перед обработкой.
const text = "пример сообщения";
const encoded = nacl.util.decodeUTF8(text);
const hash = nacl.hash(encoded);
При обратной операции используется кодирование в строку, чаще всего Base64, поскольку вывод хеша в «сыром» виде неудобен для хранения и передачи.
const hashBase64 = nacl.util.encodeBase64(hash);
Важным моментом является неизменность входных данных: любые преобразования строки (например, пробелы, кодировка, нормализация Unicode) приводят к полностью другому результату.
Основной механизм верификации заключается в сравнении ранее сохранённого хеша с хешем текущих данных. Если значения совпадают — данные не изменялись.
function verifyIntegrity(originalData, expectedHashBase64) {
const dataUint8 = nacl.util.decodeUTF8(originalData);
const computedHash = nacl.hash(dataUint8);
const computedBase64 = nacl.util.encodeBase64(computedHash);
return computedBase64 === expectedHashBase64;
}
Такой подход используется для:
SHA-512 относится к семейству SHA-2 и обладает рядом характеристик, важных для проверки целостности:
В TweetNaCl.js хеш-функция реализована как часть криптографического ядра и не предназначена для кастомизации. Это упрощает использование, но ограничивает выбор алгоритмов.
Хотя часто используется строковое сравнение Base64, более корректный
способ — побайтовое сравнение Uint8Array.
function compareHashes(a, b) {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
}
Такой метод исключает ошибки, связанные с различиями в кодировке или форматировании строкового представления.
При передаче файлов через ненадёжные каналы часто используется схема предварительного вычисления хеша:
const fileData = new Uint8Array([...]);
const fileHash = nacl.hash(fileData);
const fileHashB64 = nacl.util.encodeBase64(fileHash);
На принимающей стороне выполняется повторное вычисление и сравнение:
const receivedFileData = new Uint8Array([...]);
const receivedHash = nacl.hash(receivedFileData);
const receivedHashB64 = nacl.util.encodeBase64(receivedHash);
const isValid = fileHashB64 === receivedHashB64;
Несовпадение указывает на изменение данных в процессе передачи или хранения.
Классический хеш не обеспечивает аутентификацию источника данных. Он фиксирует только факт изменения, но не подтверждает, кто именно сформировал сообщение.
Это означает:
По этой причине в реальных протоколах хеш часто комбинируется с секретным ключом или используется вместе с механизмами подписи.
В TweetNaCl.js для задач аутентификации применяется схема цифровой
подписи через nacl.sign.
Хеш-функция в этом контексте используется внутри алгоритма, но напрямую разработчику обычно не требуется её комбинировать с ключами.
const keyPair = nacl.sign.keyPair();
const message = nacl.util.decodeUTF8("secure message");
const signed = nacl.sign(message, keyPair.secretKey);
const opened = nacl.sign.open(signed, keyPair.publicKey);
Здесь целостность и подлинность обеспечиваются одновременно, что делает отдельное сравнение хешей избыточным в сценариях подписи.
При хранении контрольных сумм обычно применяется отдельное поле или структура данных:
const record = {
data: "example",
hash: nacl.util.encodeBase64(nacl.hash(nacl.util.decodeUTF8("example")))
};
При загрузке выполняется проверка:
const isValid =
nacl.util.encodeBase64(nacl.hash(nacl.util.decodeUTF8(record.data))) === record.hash;
Такой подход часто используется в кэшах, локальных базах данных и конфигурационных системах.
TweetNaCl.js не предоставляет потокового хеширования. Это означает необходимость загрузки всего массива данных в память перед вычислением.
Для больших файлов применяется предварительное разбиение на блоки на
уровне приложения или использование специализированных библиотек. В
рамках nacl.js весь ввод должен быть представлен единым
Uint8Array.
Наиболее частые проблемы при работе с хешами связаны с преобразованием данных:
Uint8ArrayПример корректной последовательности:
const input = "данные";
const bytes = nacl.util.decodeUTF8(input);
const hash = nacl.hash(bytes);
const base64 = nacl.util.encodeBase64(hash);
Обратное преобразование хеша в строку используется только для хранения и передачи, но не для криптографических операций.
Хеширование в контексте TweetNaCl.js выполняет вспомогательную функцию в общей криптографической системе. Оно используется как базовый строительный блок для:
Самостоятельно хеш не обеспечивает защиту от подмены без дополнительного криптографического контекста, но является фундаментальным элементом всей схемы безопасности.