Stanford JavaScript Crypto Library providing comprehensive cryptographic operations including AES encryption, hash functions, key derivation, and elliptic curve cryptography.
—
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.
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);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
);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
);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 infoconst 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
});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);Install with Tessl CLI
npx tessl i tessl/npm-sjcl