CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-sjcl

Stanford JavaScript Crypto Library providing comprehensive cryptographic operations including AES encryption, hash functions, key derivation, and elliptic curve cryptography.

Pending
Overview
Eval results
Files

symmetric-encryption.mddocs/

Symmetric Encryption

SJCL provides AES (Advanced Encryption Standard) implementation supporting 128, 192, and 256-bit keys for secure symmetric encryption operations.

Capabilities

AES Cipher

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!!!!"

Key Sizes

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);

Block Cipher Usage

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);

Key Management

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 reconstruction

Performance Considerations

Different 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 benchmark

Security Recommendations

  1. Use AES-256 for maximum security, AES-128 for performance-critical applications
  2. Never reuse keys for different data or purposes
  3. Use proper cipher modes (GCM, CCM) instead of raw block encryption
  4. Generate keys securely using sjcl.random.randomWords() or PBKDF2
  5. Store keys securely and never log or expose them
  6. Use authenticated encryption modes to prevent tampering

Common Pitfalls

  1. Block size requirement: AES requires exactly 128-bit (4-word) blocks
  2. Key reuse: Never use the same key-IV pair twice
  3. Padding: Raw AES doesn't handle padding - use cipher modes instead
  4. Weak key derivation: Always use sufficient iterations in PBKDF2 (≥10,000)
  5. IV reuse: Initialization vectors must be unique for each encryption

Install with Tessl CLI

npx tessl i tessl/npm-sjcl

docs

big-number-arithmetic.md

bit-array-utilities.md

cipher-modes.md

data-encoding.md

elliptic-curve-cryptography.md

hash-functions.md

high-level-encryption.md

index.md

key-derivation.md

key-exchange.md

message-authentication.md

random-number-generation.md

symmetric-encryption.md

tile.json