3.9 KiB
engines/sodium-auth-box-engine
(no submodules)
Purpose
sodiumAuthBoxEngine implements the AuthBoxEngine interface from @suaveplan/crypto using libsodium's crypto_box_easy and crypto_box_open_easy. This construction provides authenticated key-exchange encryption: both the sender and recipient are authenticated because the shared secret is derived from a static X25519 DH between sender's secret and recipient's public key, then used to encrypt with XSalsa20-Poly1305.
Unlike sodiumSealedBoxEngine, the sender's public key is not included in the ciphertext — the recipient must already know who sent the message (i.e., possess the sender's public key independently).
Features
- Mutually authenticated encryption using
crypto_box_easy/crypto_box_open_easy. - XSalsa20-Poly1305 authenticated encryption via X25519 key agreement.
- 24-byte explicit nonce required from caller.
- 16-byte MAC overhead in the ciphertext.
- Throws
SodiumErroron authentication failure duringopen. - Conforms to
AuthBoxEnginefrom@suaveplan/crypto/engines.
Usage: Basic Example
import { sodiumReady } from "@suaveplan/crypto-sodium/init";
import { sodiumAgreeEngine } from "@suaveplan/crypto-sodium/engines/agree";
import { sodiumAuthBoxEngine } from "@suaveplan/crypto-sodium/engines/auth-box";
await sodiumReady();
const alice = sodiumAgreeEngine.generateKeypair();
const bob = sodiumAgreeEngine.generateKeypair();
const nonce = crypto.getRandomValues(new Uint8Array(24));
const msg = new TextEncoder().encode("authenticated message");
// Alice sends to Bob
const ct = sodiumAuthBoxEngine.seal(
alice.secretKey,
bob.publicKey,
msg,
nonce
);
// Bob receives from Alice
const pt = sodiumAuthBoxEngine.open(
alice.publicKey,
bob.secretKey,
ct,
nonce
);
console.log(new TextDecoder().decode(pt)); // "authenticated message"
Usage: Advanced Example
Bidirectional messaging channel with distinct nonce counters per direction:
import { sodiumReady } from "@suaveplan/crypto-sodium/init";
import { sodiumAgreeEngine } from "@suaveplan/crypto-sodium/engines/agree";
import { sodiumAuthBoxEngine } from "@suaveplan/crypto-sodium/engines/auth-box";
await sodiumReady();
const alice = sodiumAgreeEngine.generateKeypair();
const bob = sodiumAgreeEngine.generateKeypair();
function incrementNonce(nonce: Uint8Array): Uint8Array {
const n = nonce.slice();
for (let i = n.length - 1; i >= 0; i--) {
if (++n[i]) break;
}
return n;
}
let aliceNonce = new Uint8Array(24);
const ct1 = sodiumAuthBoxEngine.seal(
alice.secretKey, bob.publicKey,
new TextEncoder().encode("msg 1"), aliceNonce
);
aliceNonce = incrementNonce(aliceNonce);
API Reference
sodiumAuthBoxEngine: AuthBoxEngine
Singleton engine.
seal(senderSecret, recipientPublic, plaintext, nonce): Uint8Array
Encrypts plaintext using crypto_box_easy. Returns ciphertext with 16-byte MAC prepended.
Parameters:
senderSecret— sender's 32-byte secret key.recipientPublic— recipient's 32-byte public key.plaintext— message bytes.nonce— 24-byte nonce (must be unique per message under the same keypair).
open(senderPublic, recipientSecret, ciphertext, nonce): Uint8Array
Decrypts and authenticates. Both keys must correspond to the same exchange as seal.
Throws: SodiumError (SODIUM.INIT.FAILED) if MAC verification fails.
Implementation Notes
crypto_box_easy computes Curve25519(senderSecret, recipientPublic) as the shared secret and uses HSalsa20 as KDF before XSalsa20-Poly1305. Nonces must be 24 bytes. The nonce management strategy (random, counter, or derived) is left to the caller — each (keypair, nonce) pair must be used at most once for confidentiality.
The MAC overhead is 16 bytes (crypto_box_MACBYTES). The nonce must be transmitted alongside the ciphertext; a common convention is to prepend it to the ciphertext.