0
# Cipher Modes
1
2
SJCL provides various cipher modes for secure encryption including authenticated modes (CCM, GCM, OCB2) and traditional modes (CBC, CTR). Authenticated modes are recommended for most applications as they provide both encryption and authentication.
3
4
## Capabilities
5
6
### CCM Mode (Counter with CBC-MAC)
7
8
Authenticated encryption mode combining CTR encryption with CBC-MAC authentication, providing both confidentiality and integrity.
9
10
```javascript { .api }
11
/**
12
* CCM mode name constant
13
*/
14
sjcl.mode.ccm.name = "ccm";
15
16
/**
17
* CCM authenticated encryption
18
* @param {Cipher} prf - Block cipher instance (typically AES)
19
* @param {BitArray} plaintext - Data to encrypt
20
* @param {BitArray} iv - Initialization vector (7-15 bytes)
21
* @param {BitArray} [adata] - Additional authenticated data (not encrypted)
22
* @param {number} [tlen] - Authentication tag length in bits (default 64)
23
* @returns {BitArray} Concatenated ciphertext and authentication tag
24
* @throws {sjcl.exception.invalid} If IV length is invalid
25
*/
26
sjcl.mode.ccm.encrypt(prf, plaintext, iv, adata, tlen);
27
28
/**
29
* CCM authenticated decryption
30
* @param {Cipher} prf - Block cipher instance (same as used for encryption)
31
* @param {BitArray} ciphertext - Encrypted data with authentication tag
32
* @param {BitArray} iv - Initialization vector (must match encryption)
33
* @param {BitArray} [adata] - Additional authenticated data (must match encryption)
34
* @param {number} [tlen] - Authentication tag length in bits (default 64)
35
* @returns {BitArray} Decrypted plaintext
36
* @throws {sjcl.exception.corrupt} If authentication tag doesn't match
37
*/
38
sjcl.mode.ccm.decrypt(prf, ciphertext, iv, adata, tlen);
39
```
40
41
**Progress Monitoring:**
42
43
```javascript { .api }
44
/**
45
* Add progress callback for long operations
46
* @param {Function} cb - Callback function receiving progress value
47
*/
48
sjcl.mode.ccm.listenProgress(cb);
49
50
/**
51
* Remove progress callback
52
* @param {Function} cb - Callback function to remove
53
*/
54
sjcl.mode.ccm.unListenProgress(cb);
55
```
56
57
**Usage Examples:**
58
59
```javascript
60
const sjcl = require('sjcl');
61
62
// Basic CCM encryption
63
const key = sjcl.random.randomWords(8); // 256-bit key
64
const aes = new sjcl.cipher.aes(key);
65
const plaintext = sjcl.codec.utf8String.toBits("Hello, World!");
66
const iv = sjcl.random.randomWords(3); // 12-byte IV
67
const adata = sjcl.codec.utf8String.toBits("authenticated data");
68
69
const encrypted = sjcl.mode.ccm.encrypt(aes, plaintext, iv, adata, 128);
70
const decrypted = sjcl.mode.ccm.decrypt(aes, encrypted, iv, adata, 128);
71
72
console.log(sjcl.codec.utf8String.fromBits(decrypted)); // "Hello, World!"
73
74
// Progress monitoring for large operations
75
sjcl.mode.ccm.listenProgress(function(progress) {
76
console.log("CCM progress:", Math.round(progress * 100) + "%");
77
});
78
```
79
80
### GCM Mode (Galois/Counter Mode)
81
82
Authenticated encryption mode providing both encryption and authentication with excellent performance characteristics.
83
84
```javascript { .api }
85
/**
86
* GCM mode name constant
87
*/
88
sjcl.mode.gcm.name = "gcm";
89
90
/**
91
* GCM authenticated encryption
92
* @param {Cipher} prf - Block cipher instance (typically AES)
93
* @param {BitArray} plaintext - Data to encrypt
94
* @param {BitArray} iv - Initialization vector (recommended 12 bytes)
95
* @param {BitArray} [adata] - Additional authenticated data
96
* @param {number} [tlen] - Authentication tag length in bits (default 128)
97
* @returns {BitArray} Concatenated ciphertext and authentication tag
98
*/
99
sjcl.mode.gcm.encrypt(prf, plaintext, iv, adata, tlen);
100
101
/**
102
* GCM authenticated decryption
103
* @param {Cipher} prf - Block cipher instance (same as used for encryption)
104
* @param {BitArray} ciphertext - Encrypted data with authentication tag
105
* @param {BitArray} iv - Initialization vector (must match encryption)
106
* @param {BitArray} [adata] - Additional authenticated data (must match encryption)
107
* @param {number} [tlen] - Authentication tag length in bits (default 128)
108
* @returns {BitArray} Decrypted plaintext
109
* @throws {sjcl.exception.corrupt} If authentication tag doesn't match
110
*/
111
sjcl.mode.gcm.decrypt(prf, ciphertext, iv, adata, tlen);
112
```
113
114
**Usage Examples:**
115
116
```javascript
117
const sjcl = require('sjcl');
118
119
// GCM encryption with 12-byte IV (recommended)
120
const key = sjcl.random.randomWords(8);
121
const aes = new sjcl.cipher.aes(key);
122
const plaintext = sjcl.codec.utf8String.toBits("Sensitive data");
123
const iv = sjcl.random.randomWords(3); // 12 bytes
124
const adata = sjcl.codec.utf8String.toBits("public metadata");
125
126
const encrypted = sjcl.mode.gcm.encrypt(aes, plaintext, iv, adata);
127
const decrypted = sjcl.mode.gcm.decrypt(aes, encrypted, iv, adata);
128
129
console.log(sjcl.codec.utf8String.fromBits(decrypted)); // "Sensitive data"
130
131
// GCM with custom tag length
132
const encryptedShortTag = sjcl.mode.gcm.encrypt(aes, plaintext, iv, adata, 96);
133
const decryptedShortTag = sjcl.mode.gcm.decrypt(aes, encryptedShortTag, iv, adata, 96);
134
```
135
136
### OCB2 Mode (Offset Codebook Mode)
137
138
Authenticated encryption mode providing both encryption and authentication in a single pass.
139
140
```javascript { .api }
141
/**
142
* OCB2 mode name constant
143
*/
144
sjcl.mode.ocb2.name = "ocb2";
145
146
/**
147
* OCB2 authenticated encryption
148
* @param {Cipher} prp - Block cipher instance (typically AES)
149
* @param {BitArray} plaintext - Data to encrypt
150
* @param {BitArray} iv - 128-bit initialization vector
151
* @param {BitArray} [adata] - Additional authenticated data
152
* @param {number} [tlen] - Authentication tag length in bits (default 64)
153
* @param {boolean} [premac] - Whether adata is already processed
154
* @returns {BitArray} Concatenated ciphertext and authentication tag
155
* @throws {sjcl.exception.invalid} If IV is not 128 bits
156
*/
157
sjcl.mode.ocb2.encrypt(prp, plaintext, iv, adata, tlen, premac);
158
159
/**
160
* OCB2 authenticated decryption
161
* @param {Cipher} prp - Block cipher instance (same as used for encryption)
162
* @param {BitArray} ciphertext - Encrypted data with authentication tag
163
* @param {BitArray} iv - 128-bit initialization vector (must match encryption)
164
* @param {BitArray} [adata] - Additional authenticated data (must match encryption)
165
* @param {number} [tlen] - Authentication tag length in bits (default 64)
166
* @param {boolean} [premac] - Whether adata is already processed
167
* @returns {BitArray} Decrypted plaintext
168
* @throws {sjcl.exception.corrupt} If authentication tag doesn't match
169
*/
170
sjcl.mode.ocb2.decrypt(prp, ciphertext, iv, adata, tlen, premac);
171
172
/**
173
* Compute PMAC authentication for additional data
174
* @param {Cipher} prp - Block cipher instance
175
* @param {BitArray} adata - Additional data to authenticate
176
* @returns {BitArray} PMAC authentication tag
177
*/
178
sjcl.mode.ocb2.pmac(prp, adata);
179
```
180
181
**Usage Examples:**
182
183
```javascript
184
const sjcl = require('sjcl');
185
186
// OCB2 encryption (requires 128-bit IV)
187
const key = sjcl.random.randomWords(8);
188
const aes = new sjcl.cipher.aes(key);
189
const plaintext = sjcl.codec.utf8String.toBits("OCB2 test data");
190
const iv = sjcl.random.randomWords(4); // Must be exactly 128 bits
191
const adata = sjcl.codec.utf8String.toBits("additional data");
192
193
const encrypted = sjcl.mode.ocb2.encrypt(aes, plaintext, iv, adata);
194
const decrypted = sjcl.mode.ocb2.decrypt(aes, encrypted, iv, adata);
195
196
console.log(sjcl.codec.utf8String.fromBits(decrypted)); // "OCB2 test data"
197
198
// Using PMAC for separate authentication
199
const pmacTag = sjcl.mode.ocb2.pmac(aes, adata);
200
```
201
202
### CBC Mode (Cipher Block Chaining)
203
204
Traditional encryption mode that requires separate authentication. **Security Warning**: CBC mode without authentication is vulnerable to padding oracle attacks.
205
206
```javascript { .api }
207
/**
208
* CBC mode name constant
209
*/
210
sjcl.mode.cbc.name = "cbc";
211
212
/**
213
* CBC encryption - REQUIRES sjcl.beware acknowledgment
214
* @param {Cipher} prp - Block cipher instance
215
* @param {BitArray} plaintext - Data to encrypt (must be multiple of block size)
216
* @param {BitArray} iv - Initialization vector (128 bits)
217
* @param {BitArray} [adata] - Ignored parameter for compatibility
218
* @returns {BitArray} Encrypted ciphertext
219
*/
220
sjcl.mode.cbc.encrypt(prp, plaintext, iv, adata);
221
222
/**
223
* CBC decryption - REQUIRES sjcl.beware acknowledgment
224
* @param {Cipher} prp - Block cipher instance
225
* @param {BitArray} ciphertext - Data to decrypt
226
* @param {BitArray} iv - Initialization vector (must match encryption)
227
* @param {BitArray} [adata] - Ignored parameter for compatibility
228
* @returns {BitArray} Decrypted plaintext
229
*/
230
sjcl.mode.cbc.decrypt(prp, ciphertext, iv, adata);
231
```
232
233
**Usage Examples:**
234
235
```javascript
236
const sjcl = require('sjcl');
237
238
// CBC mode requires acknowledging security risks
239
sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."]();
240
241
const key = sjcl.random.randomWords(8);
242
const aes = new sjcl.cipher.aes(key);
243
const plaintext = sjcl.codec.utf8String.toBits("This must be padded to block boundary");
244
// Pad to multiple of 128 bits (4 words)
245
const paddedPlaintext = sjcl.bitArray.clamp(plaintext, Math.ceil(sjcl.bitArray.bitLength(plaintext) / 128) * 128);
246
const iv = sjcl.random.randomWords(4);
247
248
const encrypted = sjcl.mode.cbc.encrypt(aes, paddedPlaintext, iv);
249
const decrypted = sjcl.mode.cbc.decrypt(aes, encrypted, iv);
250
251
// Must also implement authentication separately (HMAC recommended)
252
const hmacKey = sjcl.random.randomWords(8);
253
const hmac = new sjcl.misc.hmac(hmacKey);
254
const authTag = hmac.encrypt(encrypted);
255
```
256
257
### CTR Mode (Counter Mode)
258
259
Stream cipher mode that converts block ciphers into stream ciphers. **Security Warning**: Requires separate authentication.
260
261
```javascript { .api }
262
/**
263
* CTR mode name constant
264
*/
265
sjcl.mode.ctr.name = "ctr";
266
267
/**
268
* CTR encryption - REQUIRES sjcl.beware acknowledgment
269
* @param {Cipher} prf - Block cipher instance
270
* @param {BitArray} plaintext - Data to encrypt
271
* @param {BitArray} iv - Initialization vector/counter
272
* @param {BitArray} [adata] - Ignored parameter for compatibility
273
* @returns {BitArray} Encrypted ciphertext
274
*/
275
sjcl.mode.ctr.encrypt(prf, plaintext, iv, adata);
276
277
/**
278
* CTR decryption - REQUIRES sjcl.beware acknowledgment
279
* @param {Cipher} prf - Block cipher instance
280
* @param {BitArray} ciphertext - Data to decrypt
281
* @param {BitArray} iv - Initialization vector/counter (must match encryption)
282
* @param {BitArray} [adata] - Ignored parameter for compatibility
283
* @returns {BitArray} Decrypted plaintext
284
*/
285
sjcl.mode.ctr.decrypt(prf, ciphertext, iv, adata);
286
```
287
288
**Usage Examples:**
289
290
```javascript
291
const sjcl = require('sjcl');
292
293
// CTR mode requires acknowledging security risks
294
sjcl.beware["CTR mode is dangerous because it doesn't protect message integrity."]();
295
296
const key = sjcl.random.randomWords(8);
297
const aes = new sjcl.cipher.aes(key);
298
const plaintext = sjcl.codec.utf8String.toBits("CTR mode can encrypt any length");
299
const iv = sjcl.random.randomWords(4); // Counter/IV
300
301
const encrypted = sjcl.mode.ctr.encrypt(aes, plaintext, iv);
302
const decrypted = sjcl.mode.ctr.decrypt(aes, encrypted, iv);
303
304
console.log(sjcl.codec.utf8String.fromBits(decrypted));
305
306
// Must implement authentication separately
307
const authKey = sjcl.random.randomWords(8);
308
const hmac = new sjcl.misc.hmac(authKey);
309
const authTag = hmac.encrypt(sjcl.bitArray.concat(iv, encrypted));
310
```
311
312
## ArrayBuffer Support
313
314
### CCM ArrayBuffer
315
316
CCM mode with ArrayBuffer support for working with binary data directly.
317
318
```javascript { .api }
319
/**
320
* CCM encryption for ArrayBuffers
321
* @param {Cipher} prf - Block cipher instance
322
* @param {ArrayBuffer} plaintext - Data to encrypt
323
* @param {ArrayBuffer} iv - Initialization vector
324
* @param {ArrayBuffer} [adata] - Additional authenticated data
325
* @param {number} [tlen] - Authentication tag length in bits
326
* @returns {ArrayBuffer} Encrypted data with authentication tag
327
*/
328
sjcl.mode.ccmArrayBuffer.encrypt(prf, plaintext, iv, adata, tlen);
329
330
/**
331
* CCM decryption for ArrayBuffers
332
* @param {Cipher} prf - Block cipher instance
333
* @param {ArrayBuffer} ciphertext - Encrypted data with tag
334
* @param {ArrayBuffer} iv - Initialization vector
335
* @param {ArrayBuffer} [adata] - Additional authenticated data
336
* @param {number} [tlen] - Authentication tag length in bits
337
* @returns {ArrayBuffer} Decrypted plaintext
338
*/
339
sjcl.mode.ccmArrayBuffer.decrypt(prf, ciphertext, iv, adata, tlen);
340
```
341
342
## Progressive OCB2
343
344
OCB2 mode with progressive/streaming capabilities for large data processing.
345
346
```javascript { .api }
347
/**
348
* Create progressive OCB2 encryptor
349
* @param {Cipher} prf - Block cipher instance
350
* @param {BitArray} iv - 128-bit initialization vector
351
* @param {BitArray} [adata] - Additional authenticated data
352
* @returns {Object} Progressive encryptor object
353
*/
354
sjcl.mode.ocb2progressive.createEncryptor(prf, iv, adata);
355
356
/**
357
* Create progressive OCB2 decryptor
358
* @param {Cipher} prf - Block cipher instance
359
* @param {BitArray} iv - 128-bit initialization vector
360
* @param {BitArray} [adata] - Additional authenticated data
361
* @returns {Object} Progressive decryptor object
362
*/
363
sjcl.mode.ocb2progressive.createDecryptor(prf, iv, adata);
364
```
365
366
## Security Recommendations
367
368
1. **Use authenticated modes** (CCM, GCM, OCB2) for all new applications
369
2. **Avoid CBC and CTR** unless you implement separate authentication
370
3. **Never reuse IV/nonce** with the same key
371
4. **Use proper IV lengths**: 12 bytes for GCM, 7-15 bytes for CCM, 16 bytes for OCB2
372
5. **Validate authentication tags** before processing decrypted data
373
6. **Use unique IVs** for each encryption operation
374
375
## Mode Comparison
376
377
| Mode | Authentication | Performance | IV Requirements | Security Level |
378
|------|---------------|-------------|-----------------|----------------|
379
| GCM | Yes | Excellent | 12 bytes (rec.) | High |
380
| CCM | Yes | Good | 7-15 bytes | High |
381
| OCB2 | Yes | Excellent | 16 bytes | High |
382
| CBC | No | Good | 16 bytes | Low (vulnerable) |
383
| CTR | No | Excellent | 16 bytes | Low (vulnerable) |