or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.mdpassword-hashing.mdpassword-verification.mdsalt-generation.mdutility-functions.md
tile.json

salt-generation.mddocs/

Salt Generation

Cryptographically secure salt generation functionality with configurable rounds for controlling computation cost. Provides both synchronous and asynchronous APIs with callback and Promise support.

Capabilities

Synchronous Salt Generation

Synchronously generates a cryptographically secure salt with configurable rounds.

/**
 * Synchronously generates a salt.
 * @param rounds Number of rounds to use, defaults to 10 if omitted (range: 4-31)
 * @returns Resulting salt string in bcrypt format
 * @throws Error if a random fallback is required but not set
 */
function genSaltSync(rounds?: number): string;

Usage Examples:

import { genSaltSync } from "bcryptjs";

// Generate salt with default rounds (10)
const salt1 = genSaltSync();
console.log(salt1); // "$2b$10$N9qo8uLOickgx2ZMRZoMye"

// Generate salt with custom rounds
const salt2 = genSaltSync(12);
console.log(salt2); // "$2b$12$X8qo9uLOickgx2ZMRZoMye"

// Use in password hashing
const salt = genSaltSync(10);
const hash = hashSync("myPassword", salt);

Asynchronous Salt Generation (Promise)

Asynchronously generates a cryptographically secure salt using Promises.

/**
 * Asynchronously generates a salt.
 * @param rounds Number of rounds to use, defaults to 10 if omitted
 * @returns Promise with resulting salt
 */
function genSalt(rounds?: number): Promise<string>;

Usage Examples:

import { genSalt, hash } from "bcryptjs";

// Generate salt with default rounds
const salt1 = await genSalt();
console.log(salt1); // "$2b$10$N9qo8uLOickgx2ZMRZoMye"

// Generate salt with custom rounds
const salt2 = await genSalt(12);
console.log(salt2); // "$2b$12$X8qo9uLOickgx2ZMRZoMye"

// Complete async password hashing workflow
async function hashPassword(password, rounds = 10) {
  try {
    const salt = await genSalt(rounds);
    const hash = await hash(password, salt);
    return hash;
  } catch (error) {
    console.error("Password hashing failed:", error);
    throw error;
  }
}

// Usage in Express.js route
app.post('/register', async (req, res) => {
  const { username, password } = req.body;
  
  try {
    const salt = await genSalt(12);
    const hashedPassword = await hash(password, salt);
    
    const user = await createUser({
      username,
      hashedPassword
    });
    
    res.json({ success: true, userId: user.id });
  } catch (error) {
    res.status(500).json({ error: "Registration failed" });
  }
});

Asynchronous Salt Generation (Callback - No Rounds)

Asynchronously generates a salt with default rounds using callback API.

/**
 * Asynchronously generates a salt.
 * @param callback Callback receiving the error, if any, and the resulting salt
 */
function genSalt(callback: Callback<string>): void;

Usage Examples:

import { genSalt } from "bcryptjs";

// Basic callback usage with default rounds
genSalt((err, salt) => {
  if (err) {
    console.error("Salt generation failed:", err);
    return;
  }
  console.log("Salt generated:", salt);
  // Continue with password hashing...
});

Asynchronous Salt Generation (Callback - With Rounds)

Asynchronously generates a salt with specified rounds using callback API.

/**
 * Asynchronously generates a salt.
 * @param rounds Number of rounds to use, defaults to 10 if omitted
 * @param callback Callback receiving the error, if any, and the resulting salt
 */
function genSalt(rounds: number, callback: Callback<string>): void;

Usage Examples:

import { genSalt, hash } from "bcryptjs";

// Callback with custom rounds
genSalt(12, (err, salt) => {
  if (err) {
    console.error("Salt generation failed:", err);
    return;
  }
  
  console.log("Salt generated:", salt);
  
  // Continue with password hashing
  hash("myPassword", salt, (err, hash) => {
    if (err) {
      console.error("Hashing failed:", err);
      return;
    }
    console.log("Password hashed:", hash);
  });
});

// Node.js callback-style user registration
function registerUser(username, password, callback) {
  genSalt(10, (err, salt) => {
    if (err) {
      return callback(err);
    }
    
    hash(password, salt, (err, hash) => {
      if (err) {
        return callback(err);
      }
      
      saveUser({ username, hash }, callback);
    });
  });
}

Salt Format and Structure

bcryptjs generates salts in the standard bcrypt format:

$2b$[rounds]$[salt]
  • $2b$: bcrypt algorithm identifier (version 2b)
  • [rounds]: Number of iterations, zero-padded (04-31)
  • [salt]: 22-character base64-encoded random salt

Examples:

$2b$10$N9qo8uLOickgx2ZMRZoMye  (10 rounds)
$2b$12$X8qo9uLOickgx2ZMRZoMye  (12 rounds)
$2b$04$A1qo8uLOickgx2ZMRZoMye  (4 rounds - minimum)
$2b$31$Z9qo8uLOickgx2ZMRZoMye  (31 rounds - maximum)

Rounds Configuration

Rounds Range and Validation

  • Minimum: 4 rounds
  • Maximum: 31 rounds
  • Default: 10 rounds
  • Auto-correction: Values below 4 are set to 4, values above 31 are set to 31
// These are automatically corrected
genSaltSync(2);  // Becomes 4 rounds
genSaltSync(50); // Becomes 31 rounds

Rounds vs. Security and Performance

RoundsApproximate TimeSecurity LevelUse Case
4~1msMinimalTesting only
8~16msLowLow-security applications
10~100msGoodStandard web applications
12~400msHighSensitive applications
15~3-4sVery HighHigh-value targets
20~100sExtremeLong-term storage

Choosing Appropriate Rounds

// Development/testing environment
const devSalt = await genSalt(4);

// Production web application
const prodSalt = await genSalt(10);

// High-security financial application
const secureSalt = await genSalt(12);

// Long-term password storage
const archivalSalt = await genSalt(15);

Cryptographic Security

Random Source Priority

bcryptjs uses the following sources for cryptographically secure randomness:

  1. Web Crypto API (browsers and Node.js ≥23)
  2. Node.js crypto module (Node.js environments)
  3. Custom fallback (if set via setRandomFallback)
// If neither Web Crypto nor Node.js crypto is available
import { setRandomFallback } from "bcryptjs";

// Set a cryptographically secure fallback
setRandomFallback((length) => {
  // Return array of `length` cryptographically secure random bytes
  // This is critical for security - must use secure random source!
  return secureRandomBytes(length);
});

Security Best Practices

// Good: Generate new salt for each password
async function hashMultiplePasswords(passwords) {
  const hashes = [];
  for (const password of passwords) {
    const salt = await genSalt(10); // New salt each time
    const hash = await hash(password, salt);
    hashes.push(hash);
  }
  return hashes;
}

// Bad: Reusing the same salt (vulnerable to rainbow tables)
async function hashMultiplePasswordsBad(passwords) {
  const salt = await genSalt(10); // Same salt for all
  const hashes = [];
  for (const password of passwords) {
    const hash = await hash(password, salt); // DON'T DO THIS
    hashes.push(hash);
  }
  return hashes;
}

Error Handling

// Synchronous error handling
try {
  const salt = genSaltSync(10);
  console.log("Salt generated:", salt);
} catch (error) {
  if (error.message.includes("random fallback")) {
    console.error("No secure random source available");
    // Set up fallback or use different environment
  } else {
    console.error("Salt generation failed:", error);
  }
}

// Asynchronous Promise error handling
try {
  const salt = await genSalt(10);
  console.log("Salt generated:", salt);
} catch (error) {
  console.error("Salt generation failed:", error);
}

// Callback error handling
genSalt(10, (err, salt) => {
  if (err) {
    console.error("Salt generation failed:", err);
    return;
  }
  console.log("Salt generated:", salt);
});

Performance Optimization

// Pre-generate salts for batch operations
async function preGenerateSalts(count, rounds = 10) {
  const salts = [];
  const promises = [];
  
  for (let i = 0; i < count; i++) {
    promises.push(genSalt(rounds));
  }
  
  return Promise.all(promises);
}

// Use appropriate rounds for your use case
const rounds = process.env.NODE_ENV === 'production' ? 12 : 8;
const salt = await genSalt(rounds);