or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

asymmetric-cryptography.mddigital-signatures.mdhash-functions.mdhmac.mdindex.mdkey-derivation.mdkey-exchange.mdrandom-generation.mdsymmetric-encryption.md
tile.json

key-derivation.mddocs/

Key Derivation

Password-Based Key Derivation Function 2 (PBKDF2) for securely deriving cryptographic keys from passwords with salt and iteration count protection against brute-force attacks.

Capabilities

PBKDF2 Asynchronous

Derives a key from a password using PBKDF2 asynchronously.

/**
 * Derive key from password using PBKDF2 (asynchronous)
 * @param {string|Buffer} password - Password string or Buffer
 * @param {string|Buffer} salt - Salt string or Buffer (should be random and unique per password)
 * @param {number} iterations - Number of iterations (higher = more secure but slower)
 * @param {number} keylen - Desired key length in bytes
 * @param {string} digest - Hash algorithm to use (e.g., 'sha256', 'sha512')
 * @param {function} callback - Callback function with (err, derivedKey)
 * @param {Error|null} callback.err - Error object or null
 * @param {Buffer} callback.derivedKey - Derived key as Buffer
 */
function pbkdf2(password, salt, iterations, keylen, digest, callback) { }

Usage Examples:

const crypto = require('crypto-browserify');

// Basic key derivation
const password = 'user-password';
const salt = crypto.randomBytes(16); // Generate random salt
const iterations = 100000; // Industry standard minimum
const keyLength = 32; // 256-bit key

crypto.pbkdf2(password, salt, iterations, keyLength, 'sha256', (err, derivedKey) => {
  if (err) throw err;
  console.log('Derived key:', derivedKey.toString('hex'));
  console.log('Salt used:', salt.toString('hex'));
});

// Key derivation for encryption
const userPassword = 'MySecurePassword123!';
const randomSalt = crypto.randomBytes(16);

crypto.pbkdf2(userPassword, randomSalt, 100000, 32, 'sha512', (err, encryptionKey) => {
  if (err) {
    console.error('Key derivation failed:', err);
    return;
  }
  
  // Use the derived key for AES encryption
  const cipher = crypto.createCipher('aes-256-cbc', encryptionKey);
  // ... encryption logic
});

// Storing password hashes
function hashPassword(password, callback) {
  const salt = crypto.randomBytes(16);
  crypto.pbkdf2(password, salt, 100000, 64, 'sha512', (err, hash) => {
    if (err) return callback(err);
    
    // Store both salt and hash
    const result = {
      salt: salt.toString('hex'),
      hash: hash.toString('hex'),
      iterations: 100000
    };
    callback(null, result);
  });
}

PBKDF2 Synchronous

Derives a key from a password using PBKDF2 synchronously.

/**
 * Derive key from password using PBKDF2 (synchronous)
 * @param {string|Buffer} password - Password string or Buffer
 * @param {string|Buffer} salt - Salt string or Buffer (should be random and unique per password)
 * @param {number} iterations - Number of iterations (higher = more secure but slower)
 * @param {number} keylen - Desired key length in bytes
 * @param {string} digest - Hash algorithm to use (e.g., 'sha256', 'sha512')
 * @returns {Buffer} Derived key as Buffer
 */
function pbkdf2Sync(password, salt, iterations, keylen, digest) { }

Usage Examples:

const crypto = require('crypto-browserify');

// Synchronous key derivation
const password = 'user-password';
const salt = crypto.randomBytes(16);
const derivedKey = crypto.pbkdf2Sync(password, salt, 100000, 32, 'sha256');
console.log('Derived key:', derivedKey.toString('hex'));

// Key stretching for master password
function deriveMasterKey(userPassword, userSalt) {
  try {
    return crypto.pbkdf2Sync(userPassword, userSalt, 100000, 32, 'sha512');
  } catch (err) {
    console.error('Failed to derive master key:', err.message);
    return null;
  }
}

// Multiple keys from single password
const basePassword = 'MyStrongPassword';
const baseSalt = Buffer.from('application-salt', 'utf8');

// Derive different keys for different purposes
const encryptionKey = crypto.pbkdf2Sync(basePassword, baseSalt + '-encrypt', 100000, 32, 'sha256');
const signingKey = crypto.pbkdf2Sync(basePassword, baseSalt + '-sign', 100000, 32, 'sha256');
const authKey = crypto.pbkdf2Sync(basePassword, baseSalt + '-auth', 100000, 32, 'sha256');

Common Use Cases

Password Hashing for Storage

Securely hash passwords for database storage with salt and iterations.

const crypto = require('crypto-browserify');

class PasswordManager {
  static hashPassword(password) {
    const salt = crypto.randomBytes(16);
    const hash = crypto.pbkdf2Sync(password, salt, 100000, 64, 'sha512');
    
    return {
      salt: salt.toString('hex'),
      hash: hash.toString('hex'),
      iterations: 100000,
      algorithm: 'sha512'
    };
  }
  
  static verifyPassword(password, stored) {
    const salt = Buffer.from(stored.salt, 'hex');
    const hash = crypto.pbkdf2Sync(password, salt, stored.iterations, 64, stored.algorithm);
    
    return hash.toString('hex') === stored.hash;
  }
}

// Usage
const userPassword = 'MySecurePassword123!';
const hashedData = PasswordManager.hashPassword(userPassword);
console.log('Stored hash data:', hashedData);

const isValid = PasswordManager.verifyPassword(userPassword, hashedData);
console.log('Password valid:', isValid);

Encryption Key Derivation

Derive strong encryption keys from user passwords.

const crypto = require('crypto-browserify');

function encryptData(plaintext, password) {
  // Generate random salt and IV
  const salt = crypto.randomBytes(16);
  const iv = crypto.randomBytes(16);
  
  // Derive encryption key from password
  const key = crypto.pbkdf2Sync(password, salt, 100000, 32, 'sha256');
  
  // Encrypt data
  const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
  let encrypted = cipher.update(plaintext, 'utf8', 'hex');
  encrypted += cipher.final('hex');
  
  // Return salt, IV, and encrypted data
  return {
    salt: salt.toString('hex'),
    iv: iv.toString('hex'),
    encrypted: encrypted
  };
}

function decryptData(encryptedData, password) {
  const salt = Buffer.from(encryptedData.salt, 'hex');
  const iv = Buffer.from(encryptedData.iv, 'hex');
  
  // Derive the same key from password and salt
  const key = crypto.pbkdf2Sync(password, salt, 100000, 32, 'sha256');
  
  // Decrypt data  
  const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
  let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
  decrypted += decipher.final('utf8');
  
  return decrypted;
}

Security Best Practices

Iteration Count

Use a high iteration count to slow down brute-force attacks:

  • Minimum: 100,000 iterations (2023 OWASP recommendation)
  • Recommended: 600,000+ iterations for password hashing
  • Balance: Higher iterations = better security but slower performance

Salt Requirements

Always use a unique, random salt for each password:

  • Length: At least 16 bytes (128 bits)
  • Uniqueness: Each password gets its own salt
  • Storage: Store salt alongside the hash
  • Randomness: Use cryptographically secure random generation

Algorithm Selection

Choose strong hash algorithms:

  • Preferred: SHA-256, SHA-512
  • Avoid: SHA-1, MD5 (cryptographically broken)

Error Handling

PBKDF2 functions may throw errors in the following scenarios:

  • Invalid parameters: Negative iterations, zero key length, invalid digest
  • Unsupported algorithm: When the specified digest algorithm is not available
  • Memory allocation: When unable to allocate memory for the derived key
const crypto = require('crypto-browserify');

try {
  // Invalid parameters will throw
  const key = crypto.pbkdf2Sync('password', 'salt', -1, 32, 'sha256');
} catch (err) {
  console.error('Invalid PBKDF2 parameters:', err.message);
}

try {
  // Unsupported algorithm will throw
  const key = crypto.pbkdf2Sync('password', 'salt', 1000, 32, 'unsupported');
} catch (err) {
  console.error('Unsupported hash algorithm:', err.message);
}

// Async error handling
crypto.pbkdf2('password', 'salt', 1000, 32, 'sha256', (err, key) => {
  if (err) {
    console.error('PBKDF2 failed:', err.message);
    return;
  }
  console.log('Key derived successfully');
});