Функция nacl.box.before предназначена для
предварительного вычисления общего секретного ключа (shared key) на
основе пары ключей: приватного ключа одной стороны и публичного ключа
другой стороны. Этот общий ключ затем используется в симметричных
операциях шифрования и расшифрования, что позволяет значительно повысить
производительность при множественных обменах сообщениями между одними и
теми же участниками.
В основе лежит схема обмена ключами Curve25519,
применяемая в алгоритме crypto_box. Вместо повторного
выполнения дорогой операции скалярного умножения при каждом вызове
nacl.box, общий ключ вычисляется один раз и далее
переиспользуется.
nacl.box.before(theirPublicKey, mySecretKey)
Аргументы:
theirPublicKey — Uint8Array(32) —
публичный ключ другой стороныmySecretKey — Uint8Array(32) — приватный
ключ текущей стороныВозвращаемое значение:
Uint8Array(32) — общий секретный ключ (shared key)Функция реализует операцию:
sharedKey = scalarMult(mySecretKey, theirPublicKey)
Это классическая схема Диффи–Хеллмана на эллиптической кривой Curve25519. Важное свойство:
scalarMult(A_secret, B_public) === scalarMult(B_secret, A_public)
Таким образом, обе стороны независимо получают идентичный общий ключ, не передавая его напрямую.
nacl.box.before используется совместно с:
nacl.box.after — шифрование с уже вычисленным shared
keynacl.box.open.after — расшифрование с shared keyЭквивалент:
nacl.box(message, nonce, theirPublicKey, mySecretKey)
равносилен:
const sharedKey = nacl.box.before(theirPublicKey, mySecretKey);
nacl.box.after(message, nonce, sharedKey);
Если между двумя сторонами происходит интенсивный обмен сообщениями,
повторное вычисление shared key становится узким местом. Использование
nacl.box.before позволяет:
import nacl from 'tweetnacl';
// Генерация ключевых пар
const alice = nacl.box.keyPair();
const bob = nacl.box.keyPair();
// Предварительное вычисление общего ключа
const aliceShared = nacl.box.before(bob.publicKey, alice.secretKey);
const bobShared = nacl.box.before(alice.publicKey, bob.secretKey);
// Проверка равенства
console.log(
nacl.verify(aliceShared, bobShared) // true
);
const message = new TextEncoder().encode("Привет");
const nonce = nacl.randomBytes(nacl.box.nonceLength);
// Alice шифрует
const encrypted = nacl.box.after(message, nonce, aliceShared);
// Bob расшифровывает
const decrypted = nacl.box.open.after(encrypted, nonce, bobShared);
const text = new TextDecoder().decode(decrypted);
console.log(text); // "Привет"
Uint8Array(32))Даже имея shared key, невозможно восстановить ни один из приватных ключей благодаря свойствам эллиптической криптографии.
nacl.box.beforeИспользование оправдано в следующих сценариях:
Необязательно использовать, если сообщение передаётся однократно.
nacl.scalarMultФункция nacl.scalarMult выполняет ту же базовую
операцию, но:
boxnacl.box.before:
box.after// Неправильно
nacl.box.before(mySecretKey, theirPublicKey)
Использование ключей от разных пар приведёт к несовпадающим shared key и невозможности расшифрования.
Хотя это не связано напрямую с before, при использовании
box.after необходимо гарантировать уникальность nonce для
каждого сообщения.
В TweetNaCl:
crypto_scalarmultЭто означает, что shared key — не просто результат умножения, а уже подготовленный симметричный ключ.
Основной выигрыш:
| Операция | Стоимость |
|---|---|
| scalarMult | высокая |
| symmetric encryption | низкая |
nacl.box.before позволяет выполнить дорогую операцию
один раз.
Типичная схема:
beforebox.after / open.after для
всех сообщенийbox.afterfunction createSharedKey(mySecret, theirPublic) {
return nacl.box.before(theirPublic, mySecret);
}
function encrypt(msg, nonce, sharedKey) {
return nacl.box.after(msg, nonce, sharedKey);
}
function decrypt(cipher, nonce, sharedKey) {
return nacl.box.open.after(cipher, nonce, sharedKey);
}
box.after и
open.after