Stanford JavaScript Crypto Library providing comprehensive cryptographic operations including AES encryption, hash functions, key derivation, and elliptic curve cryptography.
—
SJCL provides AES (Advanced Encryption Standard) implementation supporting 128, 192, and 256-bit keys for secure symmetric encryption operations.
The primary symmetric cipher in SJCL, providing industry-standard AES encryption with support for multiple key sizes.
/**
* AES cipher constructor
* @param {BitArray} key - Encryption key as bit array (4, 6, or 8 words for 128/192/256-bit keys)
* @throws {sjcl.exception.invalid} If key size is not 4, 6, or 8 words
*/
new sjcl.cipher.aes(key);Instance Methods:
/**
* Encrypt a single 128-bit block
* @param {BitArray} data - 4-word (128-bit) plaintext block
* @returns {BitArray} 4-word (128-bit) ciphertext block
* @throws {sjcl.exception.invalid} If block size is not exactly 4 words
*/
sjcl.cipher.aes.prototype.encrypt(data);
/**
* Decrypt a single 128-bit block
* @param {BitArray} data - 4-word (128-bit) ciphertext block
* @returns {BitArray} 4-word (128-bit) plaintext block
* @throws {sjcl.exception.invalid} If block size is not exactly 4 words
*/
sjcl.cipher.aes.prototype.decrypt(data);Usage Examples:
const sjcl = require('sjcl');
// Generate a random 256-bit key
const key256 = sjcl.random.randomWords(8); // 8 words = 256 bits
const aes256 = new sjcl.cipher.aes(key256);
// Generate a 128-bit key from password (using PBKDF2)
const password = "mySecretPassword";
const salt = sjcl.random.randomWords(4);
const key128 = sjcl.misc.pbkdf2(password, salt, 10000, 128);
const aes128 = new sjcl.cipher.aes(key128);
// Encrypt a single block
const plaintext = sjcl.codec.utf8String.toBits("Hello, World!!!!"); // Must be exactly 16 bytes
const paddedPlaintext = sjcl.bitArray.clamp(
sjcl.bitArray.concat(plaintext, [0, 0, 0, 0]),
128
); // Ensure exactly 128 bits
const ciphertext = aes128.encrypt(paddedPlaintext);
// Decrypt the block
const decrypted = aes128.decrypt(ciphertext);
const decryptedText = sjcl.codec.utf8String.fromBits(decrypted);
console.log(decryptedText.trim()); // "Hello, World!!!!"AES supports three different key sizes, each providing different security levels:
const sjcl = require('sjcl');
// 128-bit key (4 words) - Fast, good security
const key128 = sjcl.random.randomWords(4);
const aes128 = new sjcl.cipher.aes(key128);
// 192-bit key (6 words) - Medium security/performance
const key192 = sjcl.random.randomWords(6);
const aes192 = new sjcl.cipher.aes(key192);
// 256-bit key (8 words) - Highest security
const key256 = sjcl.random.randomWords(8);
const aes256 = new sjcl.cipher.aes(key256);
// Key from password using PBKDF2
function deriveAESKey(password, salt, keySize) {
const iterations = 10000;
const keyBits = keySize; // 128, 192, or 256
return sjcl.misc.pbkdf2(password, salt, iterations, keyBits);
}
const derivedKey = deriveAESKey("password", sjcl.random.randomWords(4), 256);
const aesFromPassword = new sjcl.cipher.aes(derivedKey);AES is a block cipher that encrypts fixed-size 128-bit blocks. For practical use, it must be combined with a cipher mode:
const sjcl = require('sjcl');
// Manual block-by-block encryption (not recommended for production)
function encryptMultipleBlocks(aes, plaintext) {
const blocks = [];
const data = sjcl.bitArray.clamp(plaintext, Math.floor(sjcl.bitArray.bitLength(plaintext) / 128) * 128);
for (let i = 0; i < data.length; i += 4) {
const block = data.slice(i, i + 4);
if (block.length === 4) {
blocks.push(...aes.encrypt(block));
}
}
return blocks;
}
// Better approach: Use cipher modes (see cipher-modes.md)
const key = sjcl.random.randomWords(8);
const plaintext = sjcl.codec.utf8String.toBits("This is a longer message that spans multiple blocks");
const iv = sjcl.random.randomWords(4);
// Use GCM mode for authenticated encryption
const encrypted = sjcl.mode.gcm.encrypt(new sjcl.cipher.aes(key), plaintext, iv);Proper key management is crucial for AES security:
const sjcl = require('sjcl');
// Generate cryptographically secure keys
function generateAESKey(keySize = 256) {
const words = keySize / 32; // Convert bits to 32-bit words
return sjcl.random.randomWords(words);
}
// Derive keys from passwords
function deriveKeyFromPassword(password, salt, keySize = 256, iterations = 100000) {
// Ensure salt is provided and sufficiently random
if (!salt || sjcl.bitArray.bitLength(salt) < 128) {
throw new sjcl.exception.invalid("Salt must be at least 128 bits");
}
return sjcl.misc.pbkdf2(password, salt, iterations, keySize);
}
// Key derivation with automatic salt generation
function createKeyWithSalt(password, keySize = 256) {
const salt = sjcl.random.randomWords(4); // 128-bit salt
const key = deriveKeyFromPassword(password, salt, keySize);
return {
key: key,
salt: salt,
keySize: keySize
};
}
// Usage
const keyInfo = createKeyWithSalt("userPassword", 256);
const aes = new sjcl.cipher.aes(keyInfo.key);
// Store keyInfo.salt for later key reconstructionDifferent key sizes have different performance characteristics:
const sjcl = require('sjcl');
// Benchmark different key sizes
function benchmarkAES() {
const testData = sjcl.random.randomWords(4); // One block
const iterations = 10000;
// Test 128-bit key
const key128 = sjcl.random.randomWords(4);
const aes128 = new sjcl.cipher.aes(key128);
console.time('AES-128');
for (let i = 0; i < iterations; i++) {
aes128.encrypt(testData);
}
console.timeEnd('AES-128');
// Test 256-bit key
const key256 = sjcl.random.randomWords(8);
const aes256 = new sjcl.cipher.aes(key256);
console.time('AES-256');
for (let i = 0; i < iterations; i++) {
aes256.encrypt(testData);
}
console.timeEnd('AES-256');
}
// benchmarkAES(); // Uncomment to run benchmarksjcl.random.randomWords() or PBKDF2Install with Tessl CLI
npx tessl i tessl/npm-sjcl