0
# Symmetric Encryption
1
2
SJCL provides AES (Advanced Encryption Standard) implementation supporting 128, 192, and 256-bit keys for secure symmetric encryption operations.
3
4
## Capabilities
5
6
### AES Cipher
7
8
The primary symmetric cipher in SJCL, providing industry-standard AES encryption with support for multiple key sizes.
9
10
```javascript { .api }
11
/**
12
* AES cipher constructor
13
* @param {BitArray} key - Encryption key as bit array (4, 6, or 8 words for 128/192/256-bit keys)
14
* @throws {sjcl.exception.invalid} If key size is not 4, 6, or 8 words
15
*/
16
new sjcl.cipher.aes(key);
17
```
18
19
**Instance Methods:**
20
21
```javascript { .api }
22
/**
23
* Encrypt a single 128-bit block
24
* @param {BitArray} data - 4-word (128-bit) plaintext block
25
* @returns {BitArray} 4-word (128-bit) ciphertext block
26
* @throws {sjcl.exception.invalid} If block size is not exactly 4 words
27
*/
28
sjcl.cipher.aes.prototype.encrypt(data);
29
30
/**
31
* Decrypt a single 128-bit block
32
* @param {BitArray} data - 4-word (128-bit) ciphertext block
33
* @returns {BitArray} 4-word (128-bit) plaintext block
34
* @throws {sjcl.exception.invalid} If block size is not exactly 4 words
35
*/
36
sjcl.cipher.aes.prototype.decrypt(data);
37
```
38
39
**Usage Examples:**
40
41
```javascript
42
const sjcl = require('sjcl');
43
44
// Generate a random 256-bit key
45
const key256 = sjcl.random.randomWords(8); // 8 words = 256 bits
46
const aes256 = new sjcl.cipher.aes(key256);
47
48
// Generate a 128-bit key from password (using PBKDF2)
49
const password = "mySecretPassword";
50
const salt = sjcl.random.randomWords(4);
51
const key128 = sjcl.misc.pbkdf2(password, salt, 10000, 128);
52
const aes128 = new sjcl.cipher.aes(key128);
53
54
// Encrypt a single block
55
const plaintext = sjcl.codec.utf8String.toBits("Hello, World!!!!"); // Must be exactly 16 bytes
56
const paddedPlaintext = sjcl.bitArray.clamp(
57
sjcl.bitArray.concat(plaintext, [0, 0, 0, 0]),
58
128
59
); // Ensure exactly 128 bits
60
const ciphertext = aes128.encrypt(paddedPlaintext);
61
62
// Decrypt the block
63
const decrypted = aes128.decrypt(ciphertext);
64
const decryptedText = sjcl.codec.utf8String.fromBits(decrypted);
65
console.log(decryptedText.trim()); // "Hello, World!!!!"
66
```
67
68
### Key Sizes
69
70
AES supports three different key sizes, each providing different security levels:
71
72
```javascript
73
const sjcl = require('sjcl');
74
75
// 128-bit key (4 words) - Fast, good security
76
const key128 = sjcl.random.randomWords(4);
77
const aes128 = new sjcl.cipher.aes(key128);
78
79
// 192-bit key (6 words) - Medium security/performance
80
const key192 = sjcl.random.randomWords(6);
81
const aes192 = new sjcl.cipher.aes(key192);
82
83
// 256-bit key (8 words) - Highest security
84
const key256 = sjcl.random.randomWords(8);
85
const aes256 = new sjcl.cipher.aes(key256);
86
87
// Key from password using PBKDF2
88
function deriveAESKey(password, salt, keySize) {
89
const iterations = 10000;
90
const keyBits = keySize; // 128, 192, or 256
91
return sjcl.misc.pbkdf2(password, salt, iterations, keyBits);
92
}
93
94
const derivedKey = deriveAESKey("password", sjcl.random.randomWords(4), 256);
95
const aesFromPassword = new sjcl.cipher.aes(derivedKey);
96
```
97
98
### Block Cipher Usage
99
100
AES is a block cipher that encrypts fixed-size 128-bit blocks. For practical use, it must be combined with a cipher mode:
101
102
```javascript
103
const sjcl = require('sjcl');
104
105
// Manual block-by-block encryption (not recommended for production)
106
function encryptMultipleBlocks(aes, plaintext) {
107
const blocks = [];
108
const data = sjcl.bitArray.clamp(plaintext, Math.floor(sjcl.bitArray.bitLength(plaintext) / 128) * 128);
109
110
for (let i = 0; i < data.length; i += 4) {
111
const block = data.slice(i, i + 4);
112
if (block.length === 4) {
113
blocks.push(...aes.encrypt(block));
114
}
115
}
116
117
return blocks;
118
}
119
120
// Better approach: Use cipher modes (see cipher-modes.md)
121
const key = sjcl.random.randomWords(8);
122
const plaintext = sjcl.codec.utf8String.toBits("This is a longer message that spans multiple blocks");
123
const iv = sjcl.random.randomWords(4);
124
125
// Use GCM mode for authenticated encryption
126
const encrypted = sjcl.mode.gcm.encrypt(new sjcl.cipher.aes(key), plaintext, iv);
127
```
128
129
### Key Management
130
131
Proper key management is crucial for AES security:
132
133
```javascript
134
const sjcl = require('sjcl');
135
136
// Generate cryptographically secure keys
137
function generateAESKey(keySize = 256) {
138
const words = keySize / 32; // Convert bits to 32-bit words
139
return sjcl.random.randomWords(words);
140
}
141
142
// Derive keys from passwords
143
function deriveKeyFromPassword(password, salt, keySize = 256, iterations = 100000) {
144
// Ensure salt is provided and sufficiently random
145
if (!salt || sjcl.bitArray.bitLength(salt) < 128) {
146
throw new sjcl.exception.invalid("Salt must be at least 128 bits");
147
}
148
149
return sjcl.misc.pbkdf2(password, salt, iterations, keySize);
150
}
151
152
// Key derivation with automatic salt generation
153
function createKeyWithSalt(password, keySize = 256) {
154
const salt = sjcl.random.randomWords(4); // 128-bit salt
155
const key = deriveKeyFromPassword(password, salt, keySize);
156
157
return {
158
key: key,
159
salt: salt,
160
keySize: keySize
161
};
162
}
163
164
// Usage
165
const keyInfo = createKeyWithSalt("userPassword", 256);
166
const aes = new sjcl.cipher.aes(keyInfo.key);
167
// Store keyInfo.salt for later key reconstruction
168
```
169
170
### Performance Considerations
171
172
Different key sizes have different performance characteristics:
173
174
```javascript
175
const sjcl = require('sjcl');
176
177
// Benchmark different key sizes
178
function benchmarkAES() {
179
const testData = sjcl.random.randomWords(4); // One block
180
const iterations = 10000;
181
182
// Test 128-bit key
183
const key128 = sjcl.random.randomWords(4);
184
const aes128 = new sjcl.cipher.aes(key128);
185
console.time('AES-128');
186
for (let i = 0; i < iterations; i++) {
187
aes128.encrypt(testData);
188
}
189
console.timeEnd('AES-128');
190
191
// Test 256-bit key
192
const key256 = sjcl.random.randomWords(8);
193
const aes256 = new sjcl.cipher.aes(key256);
194
console.time('AES-256');
195
for (let i = 0; i < iterations; i++) {
196
aes256.encrypt(testData);
197
}
198
console.timeEnd('AES-256');
199
}
200
201
// benchmarkAES(); // Uncomment to run benchmark
202
```
203
204
## Security Recommendations
205
206
1. **Use AES-256** for maximum security, AES-128 for performance-critical applications
207
2. **Never reuse keys** for different data or purposes
208
3. **Use proper cipher modes** (GCM, CCM) instead of raw block encryption
209
4. **Generate keys securely** using `sjcl.random.randomWords()` or PBKDF2
210
5. **Store keys securely** and never log or expose them
211
6. **Use authenticated encryption modes** to prevent tampering
212
213
## Common Pitfalls
214
215
1. **Block size requirement**: AES requires exactly 128-bit (4-word) blocks
216
2. **Key reuse**: Never use the same key-IV pair twice
217
3. **Padding**: Raw AES doesn't handle padding - use cipher modes instead
218
4. **Weak key derivation**: Always use sufficient iterations in PBKDF2 (≥10,000)
219
5. **IV reuse**: Initialization vectors must be unique for each encryption