Архитектуры, в которых сервер не обладает возможностью расшифровывать пользовательские данные, строятся на принципе end-to-end encryption. В контексте JavaScript-библиотек TweetNaCl.js и nacl.js это означает, что криптографические операции выполняются исключительно на стороне клиента, а сервер выступает лишь как транспорт и хранилище зашифрованных сообщений.
Ключевая идея заключается в том, что сервер никогда не получает секретных ключей и не имеет математической возможности восстановить исходные данные из шифротекста.
TweetNaCl.js представляет собой компактную реализацию библиотеки NaCl (Networking and Cryptography library), адаптированную для JavaScript. Она реализует строго ограниченный набор проверенных примитивов:
box)secretbox)sign)В контексте клиент-серверной архитектуры наибольшую роль играет
конструкция box, основанная на Curve25519 и
XSalsa20-Poly1305.
Модель строится вокруг следующего разделения:
Сервер не обладает:
Это делает сервер криптографически «слепым» к содержимому сообщений.
Каждый участник системы создаёт собственную пару ключей:
import nacl from 'tweetnacl';
import util from 'tweetnacl-util';
const keyPair = nacl.box.keyPair();
const publicKey = keyPair.publicKey;
const secretKey = keyPair.secretKey;
publicKey распространяется через серверsecretKey никогда не покидает устройство клиентаВ модели nacl.js / TweetNaCl.js приватный ключ считается полностью недоступным для инфраструктуры.
Сервер выполняет роль каталога:
Client A → сервер: publicKeyA
Client B → сервер: publicKeyB
Сервер хранит:
Сервер не может использовать эти данные для расшифровки сообщений.
Для шифрования сообщений используется nacl.box, который
требует:
const nonce = nacl.randomBytes(nacl.box.nonceLength);
const message = util.decodeUTF8('секретное сообщение');
const encrypted = nacl.box(
message,
nonce,
recipientPublicKey,
senderSecretKey
);
const decrypted = nacl.box.open(
encrypted,
nonce,
senderPublicKey,
recipientSecretKey
);
const text = util.encodeUTF8(decrypted);
Ключевой момент: сервер никогда не участвует в этом процессе.
Типичный поток данных выглядит следующим образом:
Клиент A шифрует сообщение
Отправляет на сервер:
Сервер сохраняет/пересылает пакет
Клиент B получает пакет
Расшифровывает локально
Структура сообщения на сервере:
{
"from": "A",
"to": "B",
"nonce": "...",
"ciphertext": "..."
}
Nonce в XSalsa20-Poly1305 должен быть:
const nonce = nacl.randomBytes(24);
Повтор nonce с тем же ключом приводит к криптографической компрометации.
При использовании TweetNaCl.js сервер считается полностью недоверенным. Это означает:
Сервер может:
Сервер не может:
boxnacl.box одновременно обеспечивает:
Это достигается через Poly1305 MAC поверх XSalsa20.
Для уменьшения вычислительной нагрузки часто применяются сессионные ключи.
Идея:
box.beforebox.after для сообщенийconst sharedKey = nacl.box.before(
recipientPublicKey,
senderSecretKey
);
const encrypted = nacl.box.after(
message,
nonce,
sharedKey
);
Это снижает стоимость операций по Curve25519.
В расширенных моделях используется:
Это означает:
Сервер может хранить:
Пример схемы БД:
messages(
id,
sender_id,
receiver_id,
nonce,
ciphertext,
timestamp
)
Никакие поля не содержат открытого текста.
В такой архитектуре клиент становится доверенной криптографической средой:
Любая утечка приватного ключа происходит на стороне клиента, а не сервера.
Минимальный поток:
function sendMessage(text, recipientPublicKey, senderSecretKey) {
const nonce = nacl.randomBytes(24);
const messageUint8 = util.decodeUTF8(text);
const encrypted = nacl.box(
messageUint8,
nonce,
recipientPublicKey,
senderSecretKey
);
return {
nonce: util.encodeBase64(nonce),
ciphertext: util.encodeBase64(encrypted)
};
}
function receiveMessage(payload, senderPublicKey, recipientSecretKey) {
const nonce = util.decodeBase64(payload.nonce);
const ciphertext = util.decodeBase64(payload.ciphertext);
const decrypted = nacl.box.open(
ciphertext,
nonce,
senderPublicKey,
recipientSecretKey
);
return util.encodeUTF8(decrypted);
}
При росте системы возникают дополнительные требования:
Каждое из этих требований усложняет баланс между удобством и криптографической строгостью.
Несмотря на криптографическую строгость, модель имеет ограничения:
TweetNaCl.js используется там, где требуется:
Минимализм библиотеки снижает риск ошибок реализации, что критично для криптографии.
В такой архитектуре доверие распределяется следующим образом:
Это полностью меняет классическую модель клиент-сервер, превращая сервер в пассивный узел хранения и маршрутизации.