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

key-derivation.mddocs/

Key Derivation

SJCL provides multiple key derivation functions (KDFs) for converting passwords and other input material into cryptographic keys. These functions include PBKDF2, scrypt, and HKDF, each suited for different security requirements.

Capabilities

PBKDF2 (Password-Based Key Derivation Function 2)

The most commonly used password-based key derivation function, applying HMAC iteratively to derive keys from passwords.

/**
 * PBKDF2 key derivation function
 * @param {string|BitArray} password - Password or key material
 * @param {BitArray} salt - Random salt (recommended: at least 8 bytes)
 * @param {number} count - Number of iterations (recommended: ≥10,000)
 * @param {number} length - Desired key length in bits
 * @param {Function} [Prff] - Pseudorandom function (default: HMAC-SHA256)
 * @returns {BitArray} Derived key as bit array
 * @throws {sjcl.exception.invalid} If parameters are invalid
 */
sjcl.misc.pbkdf2(password, salt, count, length, Prff);

Usage Examples:

const sjcl = require('sjcl');

// Basic PBKDF2 key derivation
const password = "userPassword123";
const salt = sjcl.random.randomWords(4); // 16 bytes
const iterations = 100000; // High iteration count for security
const keyLength = 256; // 256-bit key

const derivedKey = sjcl.misc.pbkdf2(password, salt, iterations, keyLength);
const aes = new sjcl.cipher.aes(derivedKey);

// Using different hash functions
const derivedKeySHA1 = sjcl.misc.pbkdf2(
  password, 
  salt, 
  iterations, 
  keyLength, 
  sjcl.misc.hmac.prototype.encrypt // Uses HMAC-SHA1
);

// Derive multiple keys from same password
function deriveKeys(password, salt, iterations) {
  return {
    encryptionKey: sjcl.misc.pbkdf2(password, salt, iterations, 256),
    authKey: sjcl.misc.pbkdf2(password + "auth", salt, iterations, 256),
    iv: sjcl.misc.pbkdf2(password + "iv", salt, iterations, 128)
  };
}

const keys = deriveKeys("masterPassword", salt, 100000);

scrypt

Memory-hard key derivation function designed to be resistant to hardware-based attacks by requiring significant memory usage.

/**
 * scrypt key derivation function
 * @param {string|BitArray} password - Password or key material
 * @param {BitArray} salt - Random salt
 * @param {number} N - CPU/memory cost parameter (power of 2)
 * @param {number} r - Block size parameter
 * @param {number} p - Parallelization parameter
 * @param {number} length - Desired key length in bits
 * @param {Function} [Prff] - Pseudorandom function (default: HMAC-SHA256)
 * @returns {BitArray} Derived key as bit array
 * @throws {sjcl.exception.invalid} If parameters are invalid
 */
sjcl.misc.scrypt(password, salt, N, r, p, length, Prff);

Usage Examples:

const sjcl = require('sjcl');

// Basic scrypt usage
const password = "strongPassword";
const salt = sjcl.random.randomWords(4);
const N = 16384;  // CPU/memory cost (2^14)
const r = 8;      // Block size
const p = 1;      // Parallelization
const keyLength = 256;

const scryptKey = sjcl.misc.scrypt(password, salt, N, r, p, keyLength);

// Higher security settings (more memory/time intensive)
const secureKey = sjcl.misc.scrypt(
  password, 
  salt, 
  32768,  // N = 2^15 (more memory)
  8,      // r = 8
  1,      // p = 1
  256     // 256-bit key
);

// Lighter settings for mobile/resource-constrained environments
const mobileKey = sjcl.misc.scrypt(
  password, 
  salt, 
  4096,   // N = 2^12 (less memory)
  8,      // r = 8
  1,      // p = 1
  256     // 256-bit key
);

HKDF (HMAC-based Key Derivation Function)

Key derivation function for expanding existing key material into multiple cryptographic keys.

/**
 * HKDF key derivation function
 * @param {BitArray} ikm - Input key material (should have good entropy)
 * @param {number} keyBitLength - Desired output key length in bits
 * @param {BitArray} [salt] - Optional salt (if not provided, zero salt is used)
 * @param {BitArray} [info] - Optional context/application info
 * @param {Function} [Hash] - Hash function to use (default: SHA-256)
 * @returns {BitArray} Derived key as bit array
 * @throws {sjcl.exception.invalid} If parameters are invalid
 */
sjcl.misc.hkdf(ikm, keyBitLength, salt, info, Hash);

Usage Examples:

const sjcl = require('sjcl');

// Basic HKDF usage
const inputKeyMaterial = sjcl.random.randomWords(8); // 256 bits of random data
const salt = sjcl.random.randomWords(4); // Optional salt
const info = sjcl.codec.utf8String.toBits("MyApp-EncryptionKey-v1");

const derivedKey = sjcl.misc.hkdf(inputKeyMaterial, 256, salt, info);

// Derive multiple keys from shared secret
function deriveMultipleKeys(sharedSecret) {
  const salt = sjcl.random.randomWords(4);
  
  return {
    encKey: sjcl.misc.hkdf(
      sharedSecret, 
      256, 
      salt, 
      sjcl.codec.utf8String.toBits("encryption")
    ),
    macKey: sjcl.misc.hkdf(
      sharedSecret, 
      256, 
      salt, 
      sjcl.codec.utf8String.toBits("authentication")
    ),
    kdfKey: sjcl.misc.hkdf(
      sharedSecret, 
      256, 
      salt, 
      sjcl.codec.utf8String.toBits("key-derivation")
    )
  };
}

// HKDF with different hash functions
const hkdfSHA512 = sjcl.misc.hkdf(
  inputKeyMaterial,
  512,
  salt,
  info,
  sjcl.hash.sha512
);

Cached PBKDF2

Optimized PBKDF2 implementation with automatic salt generation and caching capabilities.

/**
 * Cached PBKDF2 with automatic salt generation
 * @param {string} password - Password for key derivation
 * @param {Object} obj - Object containing salt and other parameters
 * @returns {BitArray} Derived key as bit array
 */
sjcl.misc.cachedPbkdf2(password, obj);

Usage Examples:

const sjcl = require('sjcl');

// Using cached PBKDF2
const password = "userPassword";
const params = {
  salt: sjcl.random.randomWords(4),
  iter: 100000
};

const cachedKey = sjcl.misc.cachedPbkdf2(password, params);

// The params object will be modified with additional metadata
console.log(params); // Contains salt, iter, and derived key info

Security Recommendations

PBKDF2

  • Minimum iterations: 10,000 (preferably 100,000+)
  • Salt length: At least 128 bits (4 words)
  • Unique salts: Generate new salt for each password
  • Memory considerations: PBKDF2 is not memory-hard

scrypt

  • Parameter selection: Balance security vs. performance
  • N parameter: Should be power of 2, start with 16384
  • Memory usage: N * r * 128 bytes
  • Mobile devices: Use lower N values (4096-8192)

HKDF

  • Input entropy: Ensure IKM has sufficient entropy
  • Context separation: Use different info for different purposes
  • Salt usage: Optional but recommended for security
  • Key expansion: Can generate multiple keys from one input

Common Usage Patterns

Password-to-Key Conversion

const sjcl = require('sjcl');

function passwordToKey(password, options = {}) {
  const salt = options.salt || sjcl.random.randomWords(4);
  const iterations = options.iterations || 100000;
  const keySize = options.keySize || 256;
  
  // Use scrypt for higher security, PBKDF2 for compatibility
  const useScrypt = options.useScrypt !== false;
  
  let key;
  if (useScrypt) {
    const N = options.scryptN || 16384;
    key = sjcl.misc.scrypt(password, salt, N, 8, 1, keySize);
  } else {
    key = sjcl.misc.pbkdf2(password, salt, iterations, keySize);
  }
  
  return {
    key: key,
    salt: salt,
    iterations: iterations,
    algorithm: useScrypt ? 'scrypt' : 'pbkdf2'
  };
}

// Usage
const keyInfo = passwordToKey("userPassword", {
  keySize: 256,
  useScrypt: true,
  scryptN: 32768
});

Key Stretching for Weak Keys

const sjcl = require('sjcl');

function stretchWeakKey(weakKey, targetLength = 256) {
  const salt = sjcl.random.randomWords(4);
  
  // Convert weak key to bit array if it's a string
  const keyBits = typeof weakKey === 'string' 
    ? sjcl.codec.utf8String.toBits(weakKey)
    : weakKey;
  
  // Use HKDF to expand the weak key
  return sjcl.misc.hkdf(
    keyBits,
    targetLength,
    salt,
    sjcl.codec.utf8String.toBits("key-stretching")
  );
}

// Usage
const weakKey = "short"; // Weak key material
const strongKey = stretchWeakKey(weakKey, 256);

Performance Considerations

  • PBKDF2: Fast, CPU-intensive only
  • scrypt: Memory-hard, slower but more secure against hardware attacks
  • HKDF: Very fast, for expanding existing good key material
  • Iteration counts: Higher is more secure but slower
  • Memory usage: scrypt requires N * r * 128 bytes of memory

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