Неверное обращение с ключевым материалом — одна из самых частых проблем при использовании TweetNaCl.js / nacl.js. Библиотека построена вокруг строгих требований к типам и размерам ключей:
secretbox требует ключ длиной 32
байтаbox использует пару ключей (public/secret), каждый
строго фиксированного размераТипичная ошибка — хранение ключей в строковом виде без корректного преобразования:
const key = "mysecretkey";
nacl.secretbox(msg, nonce, key); // некорректно
Ключ всегда должен быть представлен как Uint8Array.
Строка не интерпретируется автоматически как байты.
TweetNaCl.js работает исключительно с бинарными данными. Любая строка должна быть явно преобразована.
Частая ошибка — передача текста напрямую:
nacl.secretbox("hello world", nonce, key);
Правильный подход:
const encoder = new TextEncoder();
const message = encoder.encode("hello world");
При расшифровке требуется обратное преобразование через
TextDecoder.
Нарушение этого правила приводит к:
Nonce (одноразовый вектор) — критический элемент безопасности. В TweetNaCl.js он должен быть:
Самая опасная ошибка — повторное использование nonce с тем же ключом:
const nonce = nacl.randomBytes(24);
const c1 = nacl.secretbox(m1, nonce, key);
const c2 = nacl.secretbox(m2, nonce, key); // критическая уязвимость
Повтор nonce приводит к утечке информации о сообщениях через криптоанализ.
Недопустимо также:
Math.random()TweetNaCl.js предоставляет nacl.randomBytes, который
использует криптографически стойкий источник случайности.
Ошибочный подход:
const nonce = new Uint8Array(24).map(() => Math.random() * 256);
Такой nonce предсказуем и ломает безопасность всей схемы.
Корректный вариант:
const nonce = nacl.randomBytes(24);
Две основные конструкции библиотеки часто используются неправильно:
nacl.secretbox — симметричное шифрованиеnacl.box — асимметричное шифрование
(публичный/приватный ключ)Типичная ошибка — попытка использовать public key в secretbox:
nacl.secretbox(msg, nonce, publicKey); // логически неверно
Или наоборот — попытка заменить ключевую пару одним секретом в
box.
Правильное понимание:
Расшифровка может возвращать null, если данные
повреждены или ключ неверный.
Частая ошибка — отсутствие проверки результата:
const decrypted = nacl.secretbox.open(cipher, nonce, key);
// использование decrypted без проверки
Корректный подход:
if (!decrypted) {
throw new Error("decryption failed");
}
Игнорирование этого поведения приводит к обработке null
как данных и последующим логическим сбоям.
Распространённые ошибки:
JSON.stringify без
кодированияПример проблемного хранения:
localStorage.setItem("key", key); // превращается в строку "[object Uint8Array]"
Правильный способ — явное кодирование:
const b64 = btoa(String.fromCharCode(...key));
И обратное восстановление через декодирование в
Uint8Array.
При использовании nacl.box часто нарушается схема обмена
ключами:
Особенно критично:
const shared = nacl.box.before(publicKey, secretKey);
Любое несоответствие ключей делает результат либо null,
либо уязвимым к атаке повторного воспроизведения.
TweetNaCl.js возвращает бинарный массив, который нельзя напрямую передавать как JSON.
Ошибка:
JSON.stringify(ciphertext);
Результат — потеря данных или некорректное восстановление.
Корректный подход:
Особенно часто проявляется в браузерных приложениях:
Пример ошибки:
const arr = Buffer.from(cipher);
nacl.secretbox.open(arr, nonce, key);
Buffer может работать, но несовместимость возникает при дальнейших операциях.
Криптосистемы TweetNaCl.js не являются детерминированными из-за nonce.
Ошибка ожидания одинакового ciphertext:
secretbox(msg, nonce, key) === secretbox(msg, nonce, key)
При изменении nonce результат всегда другой, и это нормальное поведение.
Хотя secretbox уже включает Poly1305 MAC, распространённая ошибка — самостоятельная обрезка или модификация ciphertext:
Любое изменение делает расшифровку невозможной или возвращает
null.
Старые реализации nacl.js и современный
tweetnacl.js не всегда совместимы на уровне форматов:
Типичная ошибка — использование ключей из одной библиотеки в другой без преобразования.
TweetNaCl.js не валидирует содержимое глубоко, но требует точных размеров:
Любое отклонение приводит к тихим сбоям или null без
пояснений.
Вместо явной обработки часто используется:
const result = nacl.secretbox.open(...);
console.log(result);
При null система продолжает работу с повреждёнными
данными, что создаёт цепные ошибки на уровне бизнес-логики.
Правильный подход — строгая проверка результата на каждом этапе криптоопераций.