0
# Public-Key Encryption (Box)
1
2
Public-key encryption functions enable secure communication between parties using public key cryptography. The "box" functions use Curve25519 for key exchange combined with authenticated encryption algorithms.
3
4
## Supported Variants
5
6
- **Curve25519XSalsa20Poly1305**: Original NaCl-compatible implementation
7
- **Curve25519XChaCha20Poly1305**: Extended nonce variant for better security
8
- **Generic Box**: Defaults to Curve25519XSalsa20Poly1305
9
10
## Key Pair Generation
11
12
### Generic Key Pair
13
14
```javascript { .api }
15
/**
16
* Generate a random Curve25519 key pair
17
* @returns Object with publicKey and privateKey properties
18
*/
19
function crypto_box_keypair(): {
20
publicKey: Uint8Array; // 32 bytes
21
privateKey: Uint8Array; // 32 bytes
22
};
23
24
/**
25
* Generate deterministic key pair from seed
26
* @param seed - 32-byte seed for key generation
27
* @returns Object with publicKey and privateKey properties
28
*/
29
function crypto_box_seed_keypair(seed: Uint8Array): {
30
publicKey: Uint8Array;
31
privateKey: Uint8Array;
32
};
33
```
34
35
### XChaCha20 Variant Key Pairs
36
37
```javascript { .api }
38
/**
39
* Generate key pair for XChaCha20 variant
40
* @returns Object with publicKey and secretKey properties
41
*/
42
function crypto_box_curve25519xchacha20poly1305_keypair(): {
43
publicKey: Uint8Array; // 32 bytes
44
secretKey: Uint8Array; // 32 bytes
45
};
46
47
/**
48
* Generate deterministic XChaCha20 key pair from seed
49
* @param seed - 32-byte seed
50
* @returns Object with publicKey and privateKey properties
51
*/
52
function crypto_box_curve25519xchacha20poly1305_seed_keypair(seed: Uint8Array): {
53
publicKey: Uint8Array;
54
privateKey: Uint8Array;
55
};
56
```
57
58
## Authenticated Encryption
59
60
### Generic Box (XSalsa20Poly1305)
61
62
```javascript { .api }
63
/**
64
* Encrypt message for a recipient using public key cryptography
65
* @param message - Plaintext to encrypt
66
* @param nonce - 24-byte nonce (must be unique per key pair)
67
* @param publicKey - Recipient's 32-byte public key
68
* @param privateKey - Sender's 32-byte private key
69
* @returns Uint8Array - Encrypted message with authentication tag
70
*/
71
function crypto_box_easy(
72
message: Uint8Array,
73
nonce: Uint8Array,
74
publicKey: Uint8Array,
75
privateKey: Uint8Array
76
): Uint8Array;
77
78
/**
79
* Decrypt message using public key cryptography
80
* @param ciphertext - Encrypted message with authentication tag
81
* @param nonce - 24-byte nonce used for encryption
82
* @param publicKey - Sender's 32-byte public key
83
* @param privateKey - Recipient's 32-byte private key
84
* @returns Uint8Array - Decrypted plaintext
85
* @throws Error if decryption fails
86
*/
87
function crypto_box_open_easy(
88
ciphertext: Uint8Array,
89
nonce: Uint8Array,
90
publicKey: Uint8Array,
91
privateKey: Uint8Array
92
): Uint8Array;
93
```
94
95
### XChaCha20 Variant
96
97
```javascript { .api }
98
/**
99
* Encrypt using XChaCha20-Poly1305 (recommended)
100
* @param message - Plaintext to encrypt
101
* @param nonce - 24-byte nonce (can be random)
102
* @param publicKey - Recipient's public key
103
* @param privateKey - Sender's private key
104
* @returns Uint8Array - Encrypted message
105
*/
106
function crypto_box_curve25519xchacha20poly1305_easy(
107
message: Uint8Array,
108
nonce: Uint8Array,
109
publicKey: Uint8Array,
110
privateKey: Uint8Array
111
): Uint8Array;
112
113
/**
114
* Decrypt using XChaCha20-Poly1305
115
* @param ciphertext - Encrypted message
116
* @param nonce - 24-byte nonce
117
* @param publicKey - Sender's public key
118
* @param privateKey - Recipient's private key
119
* @returns Uint8Array - Decrypted plaintext
120
*/
121
function crypto_box_curve25519xchacha20poly1305_open_easy(
122
ciphertext: Uint8Array,
123
nonce: Uint8Array,
124
publicKey: Uint8Array,
125
privateKey: Uint8Array
126
): Uint8Array;
127
```
128
129
## Detached Authentication
130
131
### Generic Box Detached
132
133
```javascript { .api }
134
/**
135
* Encrypt with separate authentication tag
136
* @param message - Plaintext to encrypt
137
* @param nonce - 24-byte nonce
138
* @param publicKey - Recipient's public key
139
* @param privateKey - Sender's private key
140
* @returns Object with ciphertext and mac properties
141
*/
142
function crypto_box_detached(
143
message: Uint8Array,
144
nonce: Uint8Array,
145
publicKey: Uint8Array,
146
privateKey: Uint8Array
147
): { ciphertext: Uint8Array; mac: Uint8Array };
148
149
/**
150
* Decrypt with separate authentication tag
151
* @param ciphertext - Encrypted data (without tag)
152
* @param mac - Authentication tag
153
* @param nonce - 24-byte nonce
154
* @param publicKey - Sender's public key
155
* @param privateKey - Recipient's private key
156
* @returns Uint8Array - Decrypted plaintext
157
*/
158
function crypto_box_open_detached(
159
ciphertext: Uint8Array,
160
mac: Uint8Array,
161
nonce: Uint8Array,
162
publicKey: Uint8Array,
163
privateKey: Uint8Array
164
): Uint8Array;
165
```
166
167
### XChaCha20 Detached
168
169
```javascript { .api }
170
function crypto_box_curve25519xchacha20poly1305_detached(
171
message: Uint8Array,
172
nonce: Uint8Array,
173
publicKey: Uint8Array,
174
privateKey: Uint8Array
175
): { ciphertext: Uint8Array; mac: Uint8Array };
176
177
function crypto_box_curve25519xchacha20poly1305_open_detached(
178
ciphertext: Uint8Array,
179
mac: Uint8Array,
180
nonce: Uint8Array,
181
publicKey: Uint8Array,
182
privateKey: Uint8Array
183
): Uint8Array;
184
```
185
186
## Precomputed Shared Keys
187
188
For multiple messages between the same key pair, you can precompute the shared key for better performance.
189
190
### Generic Box Precomputation
191
192
```javascript { .api }
193
/**
194
* Precompute shared secret for multiple encryptions
195
* @param publicKey - Other party's public key
196
* @param privateKey - Your private key
197
* @returns Uint8Array - 32-byte shared secret
198
*/
199
function crypto_box_beforenm(
200
publicKey: Uint8Array,
201
privateKey: Uint8Array
202
): Uint8Array;
203
204
/**
205
* Encrypt using precomputed shared secret
206
* @param message - Plaintext to encrypt
207
* @param nonce - 24-byte nonce
208
* @param sharedKey - Precomputed shared secret
209
* @returns Uint8Array - Encrypted message
210
*/
211
function crypto_box_easy_afternm(
212
message: Uint8Array,
213
nonce: Uint8Array,
214
sharedKey: Uint8Array
215
): Uint8Array;
216
217
/**
218
* Decrypt using precomputed shared secret
219
* @param ciphertext - Encrypted message
220
* @param nonce - 24-byte nonce
221
* @param sharedKey - Precomputed shared secret
222
* @returns Uint8Array - Decrypted plaintext
223
*/
224
function crypto_box_open_easy_afternm(
225
ciphertext: Uint8Array,
226
nonce: Uint8Array,
227
sharedKey: Uint8Array
228
): Uint8Array;
229
```
230
231
### XChaCha20 Precomputation
232
233
```javascript { .api }
234
function crypto_box_curve25519xchacha20poly1305_beforenm(
235
publicKey: Uint8Array,
236
privateKey: Uint8Array
237
): Uint8Array;
238
239
function crypto_box_curve25519xchacha20poly1305_easy_afternm(
240
message: Uint8Array,
241
nonce: Uint8Array,
242
sharedKey: Uint8Array
243
): Uint8Array;
244
245
function crypto_box_curve25519xchacha20poly1305_open_easy_afternm(
246
ciphertext: Uint8Array,
247
nonce: Uint8Array,
248
sharedKey: Uint8Array
249
): Uint8Array;
250
251
function crypto_box_curve25519xchacha20poly1305_detached_afternm(
252
message: Uint8Array,
253
nonce: Uint8Array,
254
sharedKey: Uint8Array
255
): { ciphertext: Uint8Array; mac: Uint8Array };
256
257
function crypto_box_curve25519xchacha20poly1305_open_detached_afternm(
258
ciphertext: Uint8Array,
259
mac: Uint8Array,
260
nonce: Uint8Array,
261
sharedKey: Uint8Array
262
): Uint8Array;
263
```
264
265
## Sealed Boxes (Anonymous Encryption)
266
267
Sealed boxes provide anonymous encryption where only the recipient's public key is needed.
268
269
### Generic Sealed Boxes
270
271
```javascript { .api }
272
/**
273
* Encrypt message anonymously for recipient
274
* @param message - Plaintext to encrypt
275
* @param publicKey - Recipient's public key
276
* @returns Uint8Array - Anonymous encrypted message
277
*/
278
function crypto_box_seal(
279
message: Uint8Array,
280
publicKey: Uint8Array
281
): Uint8Array;
282
283
/**
284
* Decrypt anonymously encrypted message
285
* @param ciphertext - Anonymous encrypted message
286
* @param publicKey - Recipient's public key
287
* @param secretKey - Recipient's private key
288
* @returns Uint8Array - Decrypted plaintext
289
*/
290
function crypto_box_seal_open(
291
ciphertext: Uint8Array,
292
publicKey: Uint8Array,
293
secretKey: Uint8Array
294
): Uint8Array;
295
```
296
297
### XChaCha20 Sealed Boxes
298
299
```javascript { .api }
300
function crypto_box_curve25519xchacha20poly1305_seal(
301
message: Uint8Array,
302
publicKey: Uint8Array
303
): Uint8Array;
304
305
function crypto_box_curve25519xchacha20poly1305_seal_open(
306
ciphertext: Uint8Array,
307
publicKey: Uint8Array,
308
secretKey: Uint8Array
309
): Uint8Array;
310
```
311
312
## Constants
313
314
### Generic Box Constants
315
316
```javascript { .api }
317
const crypto_box_PUBLICKEYBYTES: number; // 32
318
const crypto_box_SECRETKEYBYTES: number; // 32
319
const crypto_box_NONCEBYTES: number; // 24
320
const crypto_box_MACBYTES: number; // 16
321
const crypto_box_BEFORENMBYTES: number; // 32
322
const crypto_box_SEALBYTES: number; // 48
323
const crypto_box_SEEDBYTES: number; // 32
324
const crypto_box_MESSAGEBYTES_MAX: number; // Large value
325
```
326
327
### XChaCha20 Variant Constants
328
329
```javascript { .api }
330
const crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES: number; // 32
331
const crypto_box_curve25519xchacha20poly1305_SECRETKEYBYTES: number; // 32
332
const crypto_box_curve25519xchacha20poly1305_NONCEBYTES: number; // 24
333
const crypto_box_curve25519xchacha20poly1305_MACBYTES: number; // 16
334
const crypto_box_curve25519xchacha20poly1305_BEFORENMBYTES: number; // 32
335
const crypto_box_curve25519xchacha20poly1305_SEALBYTES: number; // 48
336
const crypto_box_curve25519xchacha20poly1305_SEEDBYTES: number; // 32
337
```
338
339
## Usage Examples
340
341
### Basic Public Key Encryption
342
343
```javascript
344
import _sodium from 'libsodium-wrappers-sumo';
345
await _sodium.ready;
346
const sodium = _sodium;
347
348
// Generate key pairs for Alice and Bob
349
const alice = sodium.crypto_box_keypair();
350
const bob = sodium.crypto_box_keypair();
351
352
// Alice encrypts message for Bob
353
const message = sodium.from_string('Secret message from Alice');
354
const nonce = sodium.randombytes_buf(sodium.crypto_box_NONCEBYTES);
355
356
const ciphertext = sodium.crypto_box_easy(
357
message, nonce, bob.publicKey, alice.privateKey
358
);
359
360
// Bob decrypts message from Alice
361
const plaintext = sodium.crypto_box_open_easy(
362
ciphertext, nonce, alice.publicKey, bob.privateKey
363
);
364
365
console.log(sodium.to_string(plaintext)); // "Secret message from Alice"
366
```
367
368
### Using XChaCha20 Variant (Recommended)
369
370
```javascript
371
// XChaCha20 allows safe random nonce generation
372
const alice = sodium.crypto_box_curve25519xchacha20poly1305_keypair();
373
const bob = sodium.crypto_box_curve25519xchacha20poly1305_keypair();
374
375
const message = sodium.from_string('Secure message');
376
const nonce = sodium.randombytes_buf(24); // Safe to generate randomly
377
378
const ciphertext = sodium.crypto_box_curve25519xchacha20poly1305_easy(
379
message, nonce, bob.publicKey, alice.secretKey
380
);
381
382
const plaintext = sodium.crypto_box_curve25519xchacha20poly1305_open_easy(
383
ciphertext, nonce, alice.publicKey, bob.secretKey
384
);
385
```
386
387
### Precomputed Keys for Performance
388
389
```javascript
390
// For multiple messages between same parties
391
const sharedAB = sodium.crypto_box_beforenm(bob.publicKey, alice.privateKey);
392
const sharedBA = sodium.crypto_box_beforenm(alice.publicKey, bob.privateKey);
393
394
// Alice encrypts multiple messages efficiently
395
for (let i = 0; i < 100; i++) {
396
const message = sodium.from_string(`Message ${i}`);
397
const nonce = sodium.randombytes_buf(sodium.crypto_box_NONCEBYTES);
398
399
const ciphertext = sodium.crypto_box_easy_afternm(message, nonce, sharedAB);
400
const plaintext = sodium.crypto_box_open_easy_afternm(ciphertext, nonce, sharedBA);
401
}
402
```
403
404
### Sealed Boxes (Anonymous Encryption)
405
406
```javascript
407
// Anonymous encryption - only recipient's public key needed
408
const recipient = sodium.crypto_box_keypair();
409
const anonymousMessage = sodium.from_string('Anonymous tip');
410
411
// Encrypt anonymously
412
const sealedBox = sodium.crypto_box_seal(anonymousMessage, recipient.publicKey);
413
414
// Only recipient can decrypt (no sender identity revealed)
415
const decrypted = sodium.crypto_box_seal_open(
416
sealedBox, recipient.publicKey, recipient.privateKey
417
);
418
419
console.log(sodium.to_string(decrypted)); // "Anonymous tip"
420
```
421
422
### Deterministic Key Generation
423
424
```javascript
425
// Generate keys from seed for reproducible key pairs
426
const seed = sodium.randombytes_buf(sodium.crypto_box_SEEDBYTES);
427
const keyPair1 = sodium.crypto_box_seed_keypair(seed);
428
const keyPair2 = sodium.crypto_box_seed_keypair(seed);
429
430
// Keys are identical
431
console.log(sodium.memcmp(keyPair1.publicKey, keyPair2.publicKey)); // true
432
console.log(sodium.memcmp(keyPair1.privateKey, keyPair2.privateKey)); // true
433
```
434
435
### Detached Authentication
436
437
```javascript
438
const alice = sodium.crypto_box_keypair();
439
const bob = sodium.crypto_box_keypair();
440
const message = sodium.from_string('Message with separate MAC');
441
const nonce = sodium.randombytes_buf(sodium.crypto_box_NONCEBYTES);
442
443
// Encrypt with separate MAC
444
const { ciphertext, mac } = sodium.crypto_box_detached(
445
message, nonce, bob.publicKey, alice.privateKey
446
);
447
448
console.log('Ciphertext:', sodium.to_hex(ciphertext));
449
console.log('MAC:', sodium.to_hex(mac));
450
451
// Decrypt with separate MAC
452
const plaintext = sodium.crypto_box_open_detached(
453
ciphertext, mac, nonce, alice.publicKey, bob.privateKey
454
);
455
```
456
457
## Security Considerations
458
459
- **Nonce Uniqueness**: Never reuse nonces with the same key pair
460
- **Key Management**: Keep private keys secure, public keys can be shared
461
- **XChaCha20 Preference**: Use XChaCha20 variant for new applications (safer nonce handling)
462
- **Authenticated Encryption**: All box functions provide both confidentiality and authenticity
463
- **Forward Secrecy**: Generate new ephemeral keys for forward secrecy
464
- **Side Channels**: All operations are designed to be constant-time
465
466
## Algorithm Selection Guide
467
468
- **XChaCha20 variant**: Recommended for new applications, safer nonce handling
469
- **Generic box**: NaCl compatibility, careful nonce management required
470
- **Sealed boxes**: Anonymous encryption, perfect for drop-boxes or whistleblowing
471
- **Precomputed keys**: Performance optimization for repeated communication between same parties
472
473
All variants provide equivalent security when used correctly.