CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-libsodium-wrappers-sumo

The Sodium cryptographic library compiled to pure JavaScript (wrappers, sumo variant)

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

hash.mddocs/

Hashing

Cryptographic hash functions provide secure message digests for data integrity, fingerprinting, and key derivation. The library includes BLAKE2b (generic hash), SHA-256, and SHA-512 implementations with both one-shot and streaming operations.

Generic Hash (BLAKE2b)

BLAKE2b is a high-performance cryptographic hash function that's faster than SHA-3 and more secure than SHA-2. It supports keyed hashing and variable output lengths.

Key Generation

/**
 * Generate a random key for BLAKE2b keyed hashing
 * @returns Uint8Array - Random key (up to 64 bytes)
 */
function crypto_generichash_keygen(): Uint8Array;

One-Shot Hashing

/**
 * Compute BLAKE2b hash with optional key and custom length
 * @param hash_length - Desired output length (1-64 bytes, default 32)
 * @param message - Data to hash
 * @param key - Optional key for keyed hashing (null for unkeyed)
 * @returns Uint8Array - Hash digest
 */
function crypto_generichash(
  hash_length: number,
  message: Uint8Array,
  key?: Uint8Array | null
): Uint8Array;

Streaming Operations

/**
 * Initialize BLAKE2b streaming state
 * @param key - Optional key for keyed hashing
 * @param hash_length - Output length (1-64 bytes)
 * @returns Uint8Array - State object for streaming
 */
function crypto_generichash_init(
  key: Uint8Array | null,
  hash_length: number
): Uint8Array;

/**
 * Update BLAKE2b state with data chunk
 * @param state_address - State from init function
 * @param message_chunk - Data chunk to hash
 */
function crypto_generichash_update(
  state_address: any,
  message_chunk: Uint8Array
): void;

/**
 * Finalize BLAKE2b and return hash digest
 * @param state_address - State from init/update functions
 * @param hash_length - Output length (must match init)
 * @returns Uint8Array - Final hash digest
 */
function crypto_generichash_final(
  state_address: any,
  hash_length: number
): Uint8Array;

BLAKE2b Constants

const crypto_generichash_BYTES: number;         // 32 (default output size)
const crypto_generichash_BYTES_MIN: number;     // 16 (minimum output size)
const crypto_generichash_BYTES_MAX: number;     // 64 (maximum output size)
const crypto_generichash_KEYBYTES: number;      // 32 (default key size)
const crypto_generichash_KEYBYTES_MIN: number;  // 16 (minimum key size)
const crypto_generichash_KEYBYTES_MAX: number;  // 64 (maximum key size)

// BLAKE2b specific constants
const crypto_generichash_blake2b_BYTES: number;         // 32
const crypto_generichash_blake2b_BYTES_MIN: number;     // 16
const crypto_generichash_blake2b_BYTES_MAX: number;     // 64
const crypto_generichash_blake2b_KEYBYTES: number;      // 32
const crypto_generichash_blake2b_KEYBYTES_MIN: number;  // 16
const crypto_generichash_blake2b_KEYBYTES_MAX: number;  // 64
const crypto_generichash_blake2b_SALTBYTES: number;     // 16
const crypto_generichash_blake2b_PERSONALBYTES: number; // 16

BLAKE2b with Salt and Personal Parameters

/**
 * BLAKE2b with salt and personalization parameters
 * @param subkey_len - Output length
 * @param key - Optional key
 * @param id - Salt parameter (16 bytes or null)
 * @param ctx - Personalization parameter (16 bytes or null)
 * @returns Uint8Array - Hash digest
 */
function crypto_generichash_blake2b_salt_personal(
  subkey_len: number,
  key: Uint8Array | null,
  id: Uint8Array | null,
  ctx: Uint8Array | null
): Uint8Array;

SHA-256

Secure Hash Algorithm 256-bit, widely used and standardized hash function.

One-Shot Hashing

/**
 * Compute SHA-256 hash
 * @param message - Data to hash
 * @returns Uint8Array - 32-byte hash digest
 */
function crypto_hash_sha256(message: Uint8Array): Uint8Array;

Streaming Operations

/**
 * Initialize SHA-256 streaming state
 * @returns Uint8Array - State object for streaming
 */
function crypto_hash_sha256_init(): Uint8Array;

/**
 * Update SHA-256 state with data chunk
 * @param state_address - State from init function
 * @param message_chunk - Data chunk to hash
 */
function crypto_hash_sha256_update(
  state_address: any,
  message_chunk: Uint8Array
): void;

/**
 * Finalize SHA-256 and return hash digest
 * @param state_address - State from init/update functions
 * @returns Uint8Array - 32-byte hash digest
 */
function crypto_hash_sha256_final(state_address: any): Uint8Array;

SHA-256 Constants

const crypto_hash_sha256_BYTES: number; // 32 (output size)

SHA-512

Secure Hash Algorithm 512-bit, provides higher security margin than SHA-256.

One-Shot Hashing

/**
 * Compute SHA-512 hash
 * @param message - Data to hash
 * @returns Uint8Array - 64-byte hash digest
 */
function crypto_hash_sha512(message: Uint8Array): Uint8Array;

Streaming Operations

/**
 * Initialize SHA-512 streaming state
 * @returns Uint8Array - State object for streaming
 */
function crypto_hash_sha512_init(): Uint8Array;

/**
 * Update SHA-512 state with data chunk
 * @param state_address - State from init function
 * @param message_chunk - Data chunk to hash
 */
function crypto_hash_sha512_update(
  state_address: any,
  message_chunk: Uint8Array
): void;

/**
 * Finalize SHA-512 and return hash digest
 * @param state_address - State from init/update functions
 * @returns Uint8Array - 64-byte hash digest
 */
function crypto_hash_sha512_final(state_address: any): Uint8Array;

SHA-512 Constants

const crypto_hash_sha512_BYTES: number; // 64 (output size)

Generic Hash (Default)

The generic hash function defaults to SHA-512.

/**
 * Compute generic hash (SHA-512)
 * @param message - Data to hash
 * @returns Uint8Array - 64-byte hash digest
 */
function crypto_hash(message: Uint8Array): Uint8Array;

const crypto_hash_BYTES: number; // 64 (output size)

Usage Examples

Basic Hashing

import _sodium from 'libsodium-wrappers-sumo';
await _sodium.ready;
const sodium = _sodium;

// Basic BLAKE2b hashing
const message = sodium.from_string('Hello, World!');

// Default 32-byte BLAKE2b hash
const hash = sodium.crypto_generichash(32, message);
console.log('BLAKE2b hash:', sodium.to_hex(hash));

// SHA-256 hash
const sha256 = sodium.crypto_hash_sha256(message);
console.log('SHA-256 hash:', sodium.to_hex(sha256));

// SHA-512 hash
const sha512 = sodium.crypto_hash_sha512(message);
console.log('SHA-512 hash:', sodium.to_hex(sha512));

// Generic hash (SHA-512)
const genericHash = sodium.crypto_hash(message);
console.log('Generic hash equals SHA-512:', 
  sodium.memcmp(sha512, genericHash)); // true

Keyed Hashing with BLAKE2b

// Generate key for keyed hashing
const key = sodium.crypto_generichash_keygen();
const message = sodium.from_string('Keyed message');

// Keyed BLAKE2b hash
const keyedHash = sodium.crypto_generichash(32, message, key);
console.log('Keyed hash:', sodium.to_hex(keyedHash));

// Same message with different key produces different hash
const differentKey = sodium.crypto_generichash_keygen();
const differentHash = sodium.crypto_generichash(32, message, differentKey);

console.log('Same message, different key produces different hash:',
  !sodium.memcmp(keyedHash, differentHash)); // true

Variable Length BLAKE2b

const message = sodium.from_string('Variable length hashing');

// Different output lengths
const hash16 = sodium.crypto_generichash(16, message); // 16 bytes
const hash32 = sodium.crypto_generichash(32, message); // 32 bytes
const hash64 = sodium.crypto_generichash(64, message); // 64 bytes

console.log('16-byte hash:', sodium.to_hex(hash16));
console.log('32-byte hash:', sodium.to_hex(hash32));
console.log('64-byte hash:', sodium.to_hex(hash64));

Streaming Hash for Large Data

function hashLargeData(chunks, algorithm = 'blake2b') {
  let state;
  
  // Initialize based on algorithm
  switch (algorithm) {
    case 'blake2b':
      state = sodium.crypto_generichash_init(null, 32);
      break;
    case 'sha256':
      state = sodium.crypto_hash_sha256_init();
      break;
    case 'sha512':
      state = sodium.crypto_hash_sha512_init();
      break;
    default:
      throw new Error('Unsupported algorithm');
  }
  
  // Process chunks
  for (const chunk of chunks) {
    switch (algorithm) {
      case 'blake2b':
        sodium.crypto_generichash_update(state, chunk);
        break;
      case 'sha256':
        sodium.crypto_hash_sha256_update(state, chunk);
        break;
      case 'sha512':
        sodium.crypto_hash_sha512_update(state, chunk);
        break;
    }
  }
  
  // Finalize
  switch (algorithm) {
    case 'blake2b':
      return sodium.crypto_generichash_final(state, 32);
    case 'sha256':
      return sodium.crypto_hash_sha256_final(state);
    case 'sha512':
      return sodium.crypto_hash_sha512_final(state);
  }
}

// Create large data set
const largeData = new Uint8Array(10 * 1024 * 1024); // 10MB
sodium.randombytes_buf_into(largeData);

// Split into chunks
const chunkSize = 64 * 1024; // 64KB chunks
const chunks = [];
for (let i = 0; i < largeData.length; i += chunkSize) {
  chunks.push(largeData.subarray(i, i + chunkSize));
}

// Hash with different algorithms
console.time('BLAKE2b streaming');
const blake2bHash = hashLargeData(chunks, 'blake2b');
console.timeEnd('BLAKE2b streaming');

console.time('SHA-256 streaming');
const sha256Hash = hashLargeData(chunks, 'sha256');
console.timeEnd('SHA-256 streaming');

console.time('SHA-512 streaming');
const sha512Hash = hashLargeData(chunks, 'sha512');
console.timeEnd('SHA-512 streaming');

console.log('BLAKE2b result:', sodium.to_hex(blake2bHash));
console.log('SHA-256 result:', sodium.to_hex(sha256Hash));

File Integrity Verification

class FileIntegrity {
  constructor() {
    this.checksums = new Map();
  }
  
  // Store file hash
  addFile(filename, data) {
    const hash = sodium.crypto_generichash(32, data);
    this.checksums.set(filename, {
      hash: sodium.to_hex(hash),
      size: data.length,
      timestamp: new Date().toISOString()
    });
    return sodium.to_hex(hash);
  }
  
  // Verify file integrity
  verifyFile(filename, data) {
    const stored = this.checksums.get(filename);
    if (!stored) {
      return { valid: false, error: 'File not in registry' };
    }
    
    if (data.length !== stored.size) {
      return { valid: false, error: 'Size mismatch' };
    }
    
    const currentHash = sodium.crypto_generichash(32, data);
    const currentHashHex = sodium.to_hex(currentHash);
    
    return {
      valid: currentHashHex === stored.hash,
      storedHash: stored.hash,
      currentHash: currentHashHex,
      timestamp: stored.timestamp
    };
  }
  
  // Export registry
  exportRegistry() {
    return JSON.stringify(Object.fromEntries(this.checksums));
  }
  
  // Import registry
  importRegistry(json) {
    const data = JSON.parse(json);
    this.checksums = new Map(Object.entries(data));
  }
}

// Usage
const integrity = new FileIntegrity();
const fileData = sodium.from_string('Important file content');

// Add file to registry
const hash = integrity.addFile('document.txt', fileData);
console.log('File hash:', hash);

// Verify file later
const verification = integrity.verifyFile('document.txt', fileData);
console.log('File is valid:', verification.valid); // true

// Test with modified file
const modifiedData = sodium.from_string('Modified file content');
const modifiedVerification = integrity.verifyFile('document.txt', modifiedData);
console.log('Modified file is valid:', modifiedVerification.valid); // false

Password Hashing (Argon2)

Secure password hashing using Argon2i and Argon2id algorithms for storing user passwords and deriving keys from passwords. Never use regular hash functions for passwords.

Password-Based Key Derivation

/**
 * Derive a key from a password using Argon2
 * @param keyLength - Length of derived key (16-4294967295)
 * @param password - Password to derive from
 * @param salt - Random salt (crypto_pwhash_SALTBYTES)
 * @param opsLimit - CPU/time cost parameter
 * @param memLimit - Memory cost parameter (bytes)
 * @param algorithm - Algorithm (ALG_ARGON2I13 or ALG_ARGON2ID13)
 * @returns Uint8Array - Derived key
 */
function crypto_pwhash(
  keyLength: number,
  password: Uint8Array,
  salt: Uint8Array,
  opsLimit: number,
  memLimit: number,
  algorithm: number
): Uint8Array;

Password String Hashing

/**
 * Hash password to string format for storage
 * @param password - Password to hash
 * @param opsLimit - CPU/time cost parameter
 * @param memLimit - Memory cost parameter (bytes)
 * @returns string - Formatted hash string for storage
 */
function crypto_pwhash_str(
  password: Uint8Array,
  opsLimit: number,
  memLimit: number
): string;

/**
 * Verify password against stored hash string
 * @param hashedPassword - Previously computed hash string
 * @param password - Password to verify
 * @returns boolean - True if password matches
 */
function crypto_pwhash_str_verify(
  hashedPassword: string,
  password: Uint8Array
): boolean;

/**
 * Check if stored hash needs rehashing (parameters changed)
 * @param hashedPassword - Previously computed hash string
 * @param opsLimit - Current CPU cost parameter
 * @param memLimit - Current memory cost parameter
 * @returns boolean - True if rehashing recommended
 */
function crypto_pwhash_str_needs_rehash(
  hashedPassword: string,
  opsLimit: number,
  memLimit: number
): boolean;

Scrypt Legacy Support

/**
 * Legacy scrypt-based password hashing
 * @param keyLength - Length of derived key
 * @param password - Password to derive from
 * @param salt - Random salt (32 bytes)
 * @param opsLimit - CPU/time cost parameter
 * @param memLimit - Memory cost parameter
 * @returns Uint8Array - Derived key
 */
function crypto_pwhash_scryptsalsa208sha256(
  keyLength: number,
  password: Uint8Array,
  salt: Uint8Array,
  opsLimit: number,
  memLimit: number
): Uint8Array;

/**
 * Legacy scrypt string hashing
 * @param password - Password to hash
 * @param opsLimit - CPU cost parameter
 * @param memLimit - Memory cost parameter
 * @returns string - Formatted hash string
 */
function crypto_pwhash_scryptsalsa208sha256_str(
  password: Uint8Array,
  opsLimit: number,
  memLimit: number
): string;

/**
 * Verify password against scrypt hash string
 * @param hashedPassword - Previously computed scrypt hash
 * @param password - Password to verify
 * @returns boolean - True if password matches
 */
function crypto_pwhash_scryptsalsa208sha256_str_verify(
  hashedPassword: string,
  password: Uint8Array
): boolean;

Password Hashing Constants

// Argon2 algorithm identifiers
const crypto_pwhash_ALG_ARGON2I13: number;         // 1 (Argon2i)
const crypto_pwhash_ALG_ARGON2ID13: number;        // 2 (Argon2id - recommended)
const crypto_pwhash_ALG_DEFAULT: number;           // Same as ALG_ARGON2ID13

// Salt and output size limits
const crypto_pwhash_SALTBYTES: number;             // 32 (salt size)
const crypto_pwhash_STRBYTES: number;              // 102 (string hash length)
const crypto_pwhash_STRPREFIX: string;             // "$argon2id$" (string prefix)
const crypto_pwhash_BYTES_MIN: number;             // 16 (min key length)
const crypto_pwhash_BYTES_MAX: number;             // 4294967295 (max key length)
const crypto_pwhash_PASSWD_MIN: number;            // 0 (min password length)
const crypto_pwhash_PASSWD_MAX: number;            // 4294967295 (max password length)

// Computational limits - Argon2
const crypto_pwhash_OPSLIMIT_INTERACTIVE: number;  // 4 (fast login)
const crypto_pwhash_OPSLIMIT_MODERATE: number;     // 6 (moderate security)
const crypto_pwhash_OPSLIMIT_SENSITIVE: number;    // 8 (high security)
const crypto_pwhash_MEMLIMIT_INTERACTIVE: number;  // 67108864 (64MB)
const crypto_pwhash_MEMLIMIT_MODERATE: number;     // 268435456 (256MB)
const crypto_pwhash_MEMLIMIT_SENSITIVE: number;    // 1073741824 (1GB)

// Computational limits - Scrypt legacy
const crypto_pwhash_scryptsalsa208sha256_SALTBYTES: number;     // 32
const crypto_pwhash_scryptsalsa208sha256_STRBYTES: number;      // 102
const crypto_pwhash_scryptsalsa208sha256_STRPREFIX: string;     // "$7$"
const crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE: number;  // 32768
const crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE: number;     // 33554432
const crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE: number;   // 16777216
const crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE: number;     // 1073741824

Usage Examples

// User registration - hash password for storage
const password = sodium.from_string('user_password123');

// String-based hashing (recommended for most use cases)
const hashedPassword = sodium.crypto_pwhash_str(
  password,
  sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
  sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE
);

// Store hashedPassword in database
console.log('Store this hash:', hashedPassword);

// User login - verify password
const loginPassword = sodium.from_string('user_password123');
const isValid = sodium.crypto_pwhash_str_verify(hashedPassword, loginPassword);
console.log('Password is valid:', isValid); // true

// Key derivation from password (for encryption keys)
const salt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES);
const encryptionKey = sodium.crypto_pwhash(
  32, // 32-byte key for ChaCha20
  password,
  salt,
  sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
  sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
  sodium.crypto_pwhash_ALG_ARGON2ID13
);

// Use encryptionKey for symmetric encryption
// Store salt alongside encrypted data for key recovery

BLAKE2b with Personalization

// BLAKE2b with salt and personalization for domain separation
const message = sodium.from_string('Domain-specific message');
const salt = sodium.from_string('app_salt_v1.0'); // 16 bytes max
const personal = sodium.from_string('user_profile_'); // 16 bytes max

// Pad to required lengths
const saltPadded = new Uint8Array(16);
const personalPadded = new Uint8Array(16);
saltPadded.set(salt.subarray(0, Math.min(salt.length, 16)));
personalPadded.set(personal.subarray(0, Math.min(personal.length, 16)));

const domainHash = sodium.crypto_generichash_blake2b_salt_personal(
  32, null, saltPadded, personalPadded
);

console.log('Domain-separated hash:', sodium.to_hex(domainHash));

Performance Comparison

function benchmarkHashing() {
  const message = new Uint8Array(1024 * 1024); // 1MB
  sodium.randombytes_buf_into(message);
  
  const iterations = 10;
  
  // BLAKE2b
  console.time(`BLAKE2b ${iterations}x1MB`);
  for (let i = 0; i < iterations; i++) {
    sodium.crypto_generichash(32, message);
  }
  console.timeEnd(`BLAKE2b ${iterations}x1MB`);
  
  // SHA-256
  console.time(`SHA-256 ${iterations}x1MB`);
  for (let i = 0; i < iterations; i++) {
    sodium.crypto_hash_sha256(message);
  }
  console.timeEnd(`SHA-256 ${iterations}x1MB`);
  
  // SHA-512
  console.time(`SHA-512 ${iterations}x1MB`);
  for (let i = 0; i < iterations; i++) {
    sodium.crypto_hash_sha512(message);
  }
  console.timeEnd(`SHA-512 ${iterations}x1MB`);
}

benchmarkHashing();

Short Hash (SipHash)

Fast non-cryptographic hash functions for hash tables, checksums, and other applications where speed is more important than cryptographic security.

Key Generation

/**
 * Generate random key for short hash functions
 * @returns Uint8Array - 16-byte key for SipHash
 */
function crypto_shorthash_keygen(): Uint8Array;

Short Hash Functions

/**
 * Compute SipHash-2-4 (default short hash)
 * @param message - Data to hash
 * @param key - 16-byte secret key
 * @returns Uint8Array - 8-byte hash output
 */
function crypto_shorthash(
  message: Uint8Array,
  key: Uint8Array
): Uint8Array;

/**
 * Compute SipHash-X-2-4 (128-bit output variant)  
 * @param message - Data to hash
 * @param key - 16-byte secret key
 * @returns Uint8Array - 16-byte hash output
 */
function crypto_shorthash_siphashx24(
  message: Uint8Array,
  key: Uint8Array
): Uint8Array;

Short Hash Constants

const crypto_shorthash_BYTES: number;              // 8 (SipHash-2-4 output)
const crypto_shorthash_KEYBYTES: number;           // 16 (key size)
const crypto_shorthash_siphashx24_BYTES: number;   // 16 (SipHashX-2-4 output)
const crypto_shorthash_siphashx24_KEYBYTES: number; // 16 (key size)

Usage Examples

// Generate key for short hash operations
const shortHashKey = sodium.crypto_shorthash_keygen();

// Hash table usage example
class FastHashMap {
  constructor() {
    this.buckets = new Array(1024).fill(null).map(() => []);
    this.key = sodium.crypto_shorthash_keygen();
  }
  
  getBucket(key) {
    const keyBytes = sodium.from_string(key);
    const hash = sodium.crypto_shorthash(keyBytes, this.key);
    // Convert first 4 bytes to bucket index
    const bucket = new DataView(hash.buffer).getUint32(0, true) % this.buckets.length;
    return this.buckets[bucket];
  }
  
  set(key, value) {
    const bucket = this.getBucket(key);
    const existing = bucket.find(item => item.key === key);
    if (existing) {
      existing.value = value;
    } else {
      bucket.push({ key, value });
    }
  }
  
  get(key) {
    const bucket = this.getBucket(key);
    const item = bucket.find(item => item.key === key);
    return item ? item.value : undefined;
  }
}

// Usage
const hashMap = new FastHashMap();
hashMap.set('user:123', { name: 'Alice', email: 'alice@example.com' });
hashMap.set('user:456', { name: 'Bob', email: 'bob@example.com' });

console.log(hashMap.get('user:123')); // { name: 'Alice', email: 'alice@example.com' }

// Checksums for data integrity (non-cryptographic)
const data1 = sodium.from_string('Version 1.0 data');
const data2 = sodium.from_string('Version 1.1 data');

const checksum1 = sodium.crypto_shorthash(data1, shortHashKey);
const checksum2 = sodium.crypto_shorthash(data2, shortHashKey);

console.log('Data1 checksum:', sodium.to_hex(checksum1));
console.log('Data2 checksum:', sodium.to_hex(checksum2));
console.log('Checksums match:', sodium.memcmp(checksum1, checksum2)); // false

Security Considerations

  • Collision Resistance: All provided hash functions are cryptographically secure
  • Preimage Resistance: Computationally infeasible to reverse hash functions
  • Avalanche Effect: Small input changes produce drastically different outputs
  • Algorithm Selection: BLAKE2b is fastest, SHA-256/512 for standards compliance
  • Keyed Hashing: Use BLAKE2b with keys for MAC-like properties (though HMAC is preferred for MACs)
  • Salt Usage: Use random salts for password-related hashing (prefer crypto_pwhash)

Algorithm Selection Guide

  • BLAKE2b: Best performance, variable output length, optional keying
  • SHA-256: Standards compliance, widely supported
  • SHA-512: Higher security margin, good performance on 64-bit systems
  • Keyed BLAKE2b: Fast alternative to HMAC for some use cases
  • Streaming: Use for large files or memory-constrained environments

BLAKE2b is generally recommended for new applications due to its superior performance and security properties.

docs

aead.md

auth.md

box.md

hash.md

index.md

key-derivation.md

secretbox.md

sign.md

streaming.md

utilities.md

tile.json