0
# Public-Key Authenticated Encryption
1
2
Public-key authenticated encryption using x25519-xsalsa20-poly1305. This system provides confidentiality and authenticity between two parties using their respective public and secret key pairs, without requiring a shared secret.
3
4
## Capabilities
5
6
### Basic Encryption and Decryption
7
8
Encrypt and decrypt messages using public-key cryptography.
9
10
```javascript { .api }
11
/**
12
* Encrypts and authenticates a message using peer's public key and our secret key
13
* @param {Uint8Array} message - The plaintext message to encrypt
14
* @param {Uint8Array} nonce - Unique nonce for this encryption (24 bytes)
15
* @param {Uint8Array} theirPublicKey - Recipient's public key (32 bytes)
16
* @param {Uint8Array} mySecretKey - Sender's secret key (32 bytes)
17
* @returns {Uint8Array} Encrypted and authenticated message (16 bytes longer than original)
18
*/
19
nacl.box(message, nonce, theirPublicKey, mySecretKey): Uint8Array
20
21
/**
22
* Authenticates and decrypts a box using peer's public key and our secret key
23
* @param {Uint8Array} box - The encrypted message to decrypt
24
* @param {Uint8Array} nonce - The nonce used for encryption (24 bytes)
25
* @param {Uint8Array} theirPublicKey - Sender's public key (32 bytes)
26
* @param {Uint8Array} mySecretKey - Recipient's secret key (32 bytes)
27
* @returns {Uint8Array | null} Decrypted message or null if authentication fails
28
*/
29
nacl.box.open(box, nonce, theirPublicKey, mySecretKey): Uint8Array | null
30
```
31
32
**Usage Example:**
33
34
```javascript
35
const nacl = require('tweetnacl');
36
37
// Generate key pairs for Alice and Bob
38
const alice = nacl.box.keyPair();
39
const bob = nacl.box.keyPair();
40
41
// Alice encrypts a message for Bob
42
const message = new TextEncoder().encode("Hello Bob!");
43
const nonce = nacl.randomBytes(nacl.box.nonceLength);
44
const encrypted = nacl.box(message, nonce, bob.publicKey, alice.secretKey);
45
46
// Bob decrypts Alice's message
47
const decrypted = nacl.box.open(encrypted, nonce, alice.publicKey, bob.secretKey);
48
if (decrypted) {
49
console.log(new TextDecoder().decode(decrypted)); // "Hello Bob!"
50
}
51
```
52
53
### Optimized Operations with Precomputed Keys
54
55
For multiple operations between the same key pairs, precompute shared keys for better performance.
56
57
```javascript { .api }
58
/**
59
* Precomputes a shared key for multiple box operations between the same key pairs
60
* @param {Uint8Array} theirPublicKey - Peer's public key (32 bytes)
61
* @param {Uint8Array} mySecretKey - Our secret key (32 bytes)
62
* @returns {Uint8Array} Precomputed shared key (32 bytes)
63
*/
64
nacl.box.before(theirPublicKey, mySecretKey): Uint8Array
65
66
/**
67
* Encrypts using a precomputed shared key
68
* @param {Uint8Array} message - The plaintext message to encrypt
69
* @param {Uint8Array} nonce - Unique nonce for this encryption (24 bytes)
70
* @param {Uint8Array} sharedKey - Precomputed shared key from nacl.box.before
71
* @returns {Uint8Array} Encrypted and authenticated message
72
*/
73
nacl.box.after(message, nonce, sharedKey): Uint8Array
74
75
/**
76
* Decrypts using a precomputed shared key
77
* @param {Uint8Array} box - The encrypted message to decrypt
78
* @param {Uint8Array} nonce - The nonce used for encryption (24 bytes)
79
* @param {Uint8Array} sharedKey - Precomputed shared key from nacl.box.before
80
* @returns {Uint8Array | null} Decrypted message or null if authentication fails
81
*/
82
nacl.box.open.after(box, nonce, sharedKey): Uint8Array | null
83
```
84
85
**Usage Example:**
86
87
```javascript
88
const nacl = require('tweetnacl');
89
90
const alice = nacl.box.keyPair();
91
const bob = nacl.box.keyPair();
92
93
// Precompute shared keys (do this once)
94
const aliceSharedKey = nacl.box.before(bob.publicKey, alice.secretKey);
95
const bobSharedKey = nacl.box.before(alice.publicKey, bob.secretKey);
96
97
// Now encrypt/decrypt multiple messages efficiently
98
const message1 = new TextEncoder().encode("First message");
99
const message2 = new TextEncoder().encode("Second message");
100
101
const nonce1 = nacl.randomBytes(nacl.box.nonceLength);
102
const nonce2 = nacl.randomBytes(nacl.box.nonceLength);
103
104
const encrypted1 = nacl.box.after(message1, nonce1, aliceSharedKey);
105
const encrypted2 = nacl.box.after(message2, nonce2, aliceSharedKey);
106
107
const decrypted1 = nacl.box.open.after(encrypted1, nonce1, bobSharedKey);
108
const decrypted2 = nacl.box.open.after(encrypted2, nonce2, bobSharedKey);
109
```
110
111
### Key Generation
112
113
Generate key pairs for box operations.
114
115
```javascript { .api }
116
/**
117
* Generates a new random key pair for box operations
118
* @returns {{publicKey: Uint8Array, secretKey: Uint8Array}} Key pair object
119
*/
120
nacl.box.keyPair(): {publicKey: Uint8Array, secretKey: Uint8Array}
121
122
/**
123
* Derives a key pair from an existing secret key
124
* @param {Uint8Array} secretKey - The secret key (32 bytes)
125
* @returns {{publicKey: Uint8Array, secretKey: Uint8Array}} Key pair with corresponding public key
126
*/
127
nacl.box.keyPair.fromSecretKey(secretKey): {publicKey: Uint8Array, secretKey: Uint8Array}
128
```
129
130
**Usage Example:**
131
132
```javascript
133
const nacl = require('tweetnacl');
134
135
// Generate a new random key pair
136
const keyPair = nacl.box.keyPair();
137
console.log(keyPair.publicKey.length); // 32
138
console.log(keyPair.secretKey.length); // 32
139
140
// Derive key pair from existing secret key
141
const newKeyPair = nacl.box.keyPair.fromSecretKey(keyPair.secretKey);
142
// newKeyPair.publicKey will be identical to keyPair.publicKey
143
```
144
145
## Constants
146
147
```javascript { .api }
148
nacl.box.publicKeyLength: number // 32 - Length of public key in bytes
149
nacl.box.secretKeyLength: number // 32 - Length of secret key in bytes
150
nacl.box.sharedKeyLength: number // 32 - Length of precomputed shared key in bytes
151
nacl.box.nonceLength: number // 24 - Length of nonce in bytes
152
nacl.box.overheadLength: number // 16 - Length of overhead added to encrypted messages
153
```
154
155
## Error Handling
156
157
Common error patterns and proper handling:
158
159
```javascript
160
const nacl = require('tweetnacl');
161
162
function safeEncrypt(message, theirPublicKey, mySecretKey) {
163
try {
164
// Validate inputs
165
if (!message || !theirPublicKey || !mySecretKey) {
166
throw new Error('Missing required parameters');
167
}
168
169
if (theirPublicKey.length !== nacl.box.publicKeyLength) {
170
throw new Error(`Invalid public key length: expected ${nacl.box.publicKeyLength}, got ${theirPublicKey.length}`);
171
}
172
173
if (mySecretKey.length !== nacl.box.secretKeyLength) {
174
throw new Error(`Invalid secret key length: expected ${nacl.box.secretKeyLength}, got ${mySecretKey.length}`);
175
}
176
177
const nonce = nacl.randomBytes(nacl.box.nonceLength);
178
const encrypted = nacl.box(message, nonce, theirPublicKey, mySecretKey);
179
180
return { encrypted, nonce };
181
} catch (error) {
182
console.error('Encryption failed:', error.message);
183
return null;
184
}
185
}
186
187
function safeDecrypt(encrypted, nonce, theirPublicKey, mySecretKey) {
188
try {
189
const decrypted = nacl.box.open(encrypted, nonce, theirPublicKey, mySecretKey);
190
191
if (decrypted === null) {
192
throw new Error('Decryption failed: message was tampered with or keys are incorrect');
193
}
194
195
return decrypted;
196
} catch (error) {
197
console.error('Decryption failed:', error.message);
198
return null;
199
}
200
}
201
```
202
203
## Security Considerations
204
205
- **Nonce Uniqueness**: Each message encrypted with the same key pair must use a unique nonce. Reusing nonces breaks security.
206
- **Key Management**: Keep secret keys secure and never transmit them. Only share public keys.
207
- **Message Integrity**: If `nacl.box.open` returns `null`, the message was tampered with or authentication failed.
208
- **Overhead**: Encrypted messages are 16 bytes longer than the original due to authentication data.