The Sodium cryptographic library compiled to pure JavaScript (wrappers, sumo variant)
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Utility functions provide essential support for cryptographic operations including random number generation, data conversion, memory operations, and various helper functions for working with cryptographic data.
Cryptographically secure random number generation for keys, nonces, and other security-critical values.
/**
* Generate cryptographically secure random bytes
* @param length - Number of bytes to generate
* @returns Uint8Array - Random bytes
*/
function randombytes_buf(length: number): Uint8Array;
/**
* Fill existing buffer with random bytes
* @param buffer - Buffer to fill with random data
*/
function randombytes_buf_into(buffer: Uint8Array): void;
/**
* Generate deterministic random bytes from seed
* @param length - Number of bytes to generate
* @param seed - 32-byte seed for deterministic generation
* @returns Uint8Array - Deterministic random bytes
*/
function randombytes_buf_deterministic(
length: number,
seed: Uint8Array
): Uint8Array;/**
* Generate random 32-bit unsigned integer
* @returns number - Random 32-bit value
*/
function randombytes_random(): number;
/**
* Generate random integer in range [0, upper_bound)
* @param upper_bound - Exclusive upper bound (must be > 0)
* @returns number - Random integer in range
*/
function randombytes_uniform(upper_bound: number): number;/**
* Stir the random number generator
*/
function randombytes_stir(): void;
/**
* Close the random number generator
*/
function randombytes_close(): void;
/**
* Set random number generator implementation
* @param implementation - Custom RNG implementation
*/
function randombytes_set_implementation(implementation: any): void;Functions for converting between different data representations commonly used in cryptographic operations.
/**
* Convert UTF-8 string to Uint8Array
* @param string - UTF-8 string to convert
* @returns Uint8Array - String as bytes
*/
function from_string(string: string): Uint8Array;
/**
* Convert Uint8Array to UTF-8 string
* @param input - Bytes to convert to string
* @returns string - UTF-8 string
*/
function to_string(input: Uint8Array): string;/**
* Convert hexadecimal string to Uint8Array
* @param hex_string - Hex string to convert (case insensitive)
* @returns Uint8Array - Decoded bytes
*/
function from_hex(hex_string: string): Uint8Array;
/**
* Convert Uint8Array to hexadecimal string
* @param input - Bytes to convert to hex
* @returns string - Lowercase hex string
*/
function to_hex(input: Uint8Array): string;/**
* Convert Base64 string to Uint8Array
* @param input - Base64 string to decode
* @param variant - Base64 variant (optional)
* @returns Uint8Array - Decoded bytes
*/
function from_base64(input: string, variant?: number): Uint8Array;
/**
* Convert Uint8Array to Base64 string
* @param input - Bytes to encode
* @param variant - Base64 variant (optional)
* @returns string - Base64 encoded string
*/
function to_base64(input: Uint8Array, variant?: number): string;const base64_variants = {
ORIGINAL: 1, // Standard Base64 with padding
ORIGINAL_NO_PADDING: 3,// Standard Base64 without padding
URLSAFE: 5, // URL-safe Base64 with padding
URLSAFE_NO_PADDING: 7 // URL-safe Base64 without padding (default)
};Constant-time memory operations for secure comparison and manipulation.
/**
* Constant-time equality comparison
* @param a - First buffer
* @param b - Second buffer
* @returns boolean - True if buffers are equal
*/
function memcmp(a: Uint8Array, b: Uint8Array): boolean;
/**
* Constant-time comparison returning -1, 0, or 1
* @param a - First buffer
* @param b - Second buffer
* @returns number - Comparison result (-1, 0, or 1)
*/
function compare(a: Uint8Array, b: Uint8Array): number;
/**
* Check if buffer contains only zeros (constant-time)
* @param buffer - Buffer to check
* @returns boolean - True if buffer is all zeros
*/
function is_zero(buffer: Uint8Array): boolean;/**
* Securely zero out memory
* @param buffer - Buffer to zero out
*/
function memzero(buffer: Uint8Array): void;
/**
* Increment little-endian number in buffer
* @param buffer - Buffer containing little-endian number
*/
function increment(buffer: Uint8Array): void;
/**
* Add two little-endian numbers
* @param a - First operand (modified in place)
* @param b - Second operand
*/
function add(a: Uint8Array, b: Uint8Array): void;/**
* Pad buffer to specified block size using PKCS#7
* @param buffer - Buffer to pad
* @param blocksize - Target block size
* @returns Uint8Array - Padded buffer
*/
function pad(buffer: Uint8Array, blocksize: number): Uint8Array;
/**
* Remove PKCS#7 padding from buffer
* @param buffer - Padded buffer
* @param blocksize - Block size used for padding
* @returns Uint8Array - Unpadded buffer
*/
function unpad(buffer: Uint8Array, blocksize: number): Uint8Array;Constant-time verification functions for various data sizes.
/**
* Verify 16-byte values (constant-time)
* @param a - First 16-byte value
* @param b - Second 16-byte value
* @returns boolean - True if values are equal
*/
// Uses crypto_verify_16_BYTES constant (16)
/**
* Verify 32-byte values (constant-time)
* @param a - First 32-byte value
* @param b - Second 32-byte value
* @returns boolean - True if values are equal
*/
// Uses crypto_verify_32_BYTES constant (32)
/**
* Verify 64-byte values (constant-time)
* @param a - First 64-byte value
* @param b - Second 64-byte value
* @returns boolean - True if values are equal
*/
// Uses crypto_verify_64_BYTES constant (64)const crypto_verify_16_BYTES: number; // 16
const crypto_verify_32_BYTES: number; // 32
const crypto_verify_64_BYTES: number; // 64Fast polynomial authentication using Poly1305.
/**
* Generate key for one-time authentication
* @returns Uint8Array - 32-byte authentication key
*/
function crypto_onetimeauth_keygen(): Uint8Array;/**
* Compute one-time authentication tag
* @param message - Data to authenticate
* @param key - 32-byte authentication key (use only once!)
* @returns Uint8Array - 16-byte authentication tag
*/
function crypto_onetimeauth(
message: Uint8Array,
key: Uint8Array
): Uint8Array;
/**
* Verify one-time authentication tag
* @param hash - Authentication tag to verify
* @param message - Original message
* @param key - 32-byte authentication key
* @returns boolean - True if tag is valid
*/
function crypto_onetimeauth_verify(
hash: Uint8Array,
message: Uint8Array,
key: Uint8Array
): boolean;/**
* Initialize one-time auth streaming
* @param key - Authentication key
* @returns Uint8Array - State for streaming
*/
function crypto_onetimeauth_init(key: Uint8Array): Uint8Array;
/**
* Update streaming one-time auth
* @param state_address - State from init
* @param message_chunk - Data chunk to authenticate
*/
function crypto_onetimeauth_update(
state_address: any,
message_chunk: Uint8Array
): void;
/**
* Finalize streaming one-time auth
* @param state_address - State from init/update
* @returns Uint8Array - Authentication tag
*/
function crypto_onetimeauth_final(state_address: any): Uint8Array;const crypto_onetimeauth_BYTES: number; // 16 (tag length)
const crypto_onetimeauth_KEYBYTES: number; // 32 (key length)
// Poly1305 specific constants
const crypto_onetimeauth_poly1305_BYTES: number; // 16
const crypto_onetimeauth_poly1305_KEYBYTES: number; // 32Fast non-cryptographic hashing for hash tables and checksums.
/**
* Generate key for short hash function
* @returns Uint8Array - 16-byte hash key
*/
function crypto_shorthash_keygen(): Uint8Array;/**
* Compute short hash (SipHash-2-4)
* @param message - Data to hash
* @param key - 16-byte hash key
* @returns Uint8Array - 8-byte hash value
*/
function crypto_shorthash(
message: Uint8Array,
key: Uint8Array
): Uint8Array;
/**
* Compute SipHashX-2-4 (16-byte output)
* @param message - Data to hash
* @param key - 16-byte hash key
* @returns Uint8Array - 16-byte hash value
*/
function crypto_shorthash_siphashx24(
message: Uint8Array,
key: Uint8Array
): Uint8Array;const crypto_shorthash_BYTES: number; // 8 (SipHash-2-4 output)
const crypto_shorthash_KEYBYTES: number; // 16 (key length)
// SipHash-2-4 constants
const crypto_shorthash_siphash24_BYTES: number; // 8
const crypto_shorthash_siphash24_KEYBYTES: number; // 16
// SipHashX-2-4 constants
const crypto_shorthash_siphashx24_BYTES: number; // 16
const crypto_shorthash_siphashx24_KEYBYTES: number; // 16Functions to get library version and information.
/**
* Get sodium library version string
* @returns string - Version information
*/
function sodium_version_string(): string;import _sodium from 'libsodium-wrappers-sumo';
await _sodium.ready;
const sodium = _sodium;
// Generate random bytes
const randomBytes = sodium.randombytes_buf(32);
console.log('Random bytes:', sodium.to_hex(randomBytes));
// Generate random numbers
const randomInt = sodium.randombytes_random();
const randomRange = sodium.randombytes_uniform(100); // 0-99
console.log('Random 32-bit int:', randomInt);
console.log('Random 0-99:', randomRange);
// Deterministic random generation
const seed = sodium.randombytes_buf(32);
const deterministicBytes1 = sodium.randombytes_buf_deterministic(16, seed);
const deterministicBytes2 = sodium.randombytes_buf_deterministic(16, seed);
console.log('Deterministic bytes match:',
sodium.memcmp(deterministicBytes1, deterministicBytes2)); // true
// Fill existing buffer
const buffer = new Uint8Array(10);
sodium.randombytes_buf_into(buffer);
console.log('Filled buffer:', sodium.to_hex(buffer));// String conversion
const message = 'Hello, 世界! 🌍';
const messageBytes = sodium.from_string(message);
const backToString = sodium.to_string(messageBytes);
console.log('Original:', message);
console.log('Bytes:', sodium.to_hex(messageBytes));
console.log('Back to string:', backToString);
console.log('Strings match:', message === backToString); // true
// Hex conversion
const hexString = 'deadbeef';
const hexBytes = sodium.from_hex(hexString);
const backToHex = sodium.to_hex(hexBytes);
console.log('Hex string:', hexString);
console.log('Hex bytes:', hexBytes);
console.log('Back to hex:', backToHex);
// Base64 conversion with variants
const data = sodium.randombytes_buf(20);
const base64Original = sodium.to_base64(data, sodium.base64_variants.ORIGINAL);
const base64UrlSafe = sodium.to_base64(data, sodium.base64_variants.URLSAFE_NO_PADDING);
console.log('Original Base64:', base64Original);
console.log('URL-safe Base64:', base64UrlSafe);
// Decode back
const decodedOriginal = sodium.from_base64(base64Original, sodium.base64_variants.ORIGINAL);
const decodedUrlSafe = sodium.from_base64(base64UrlSafe, sodium.base64_variants.URLSAFE_NO_PADDING);
console.log('Decoded match:', sodium.memcmp(data, decodedOriginal)); // true
console.log('URL-safe decoded match:', sodium.memcmp(data, decodedUrlSafe)); // true// Constant-time comparison
const secret1 = sodium.randombytes_buf(16);
const secret2 = sodium.randombytes_buf(16);
const secret1Copy = new Uint8Array(secret1);
console.log('Secrets equal:', sodium.memcmp(secret1, secret2)); // false
console.log('Secret equals copy:', sodium.memcmp(secret1, secret1Copy)); // true
// Comparison with ordering
const a = sodium.from_hex('0102');
const b = sodium.from_hex('0201');
const comparison = sodium.compare(a, b);
console.log('Comparison result:', comparison); // -1 (a < b)
// Zero checking
const zeros = new Uint8Array(16); // All zeros
const nonZeros = sodium.randombytes_buf(16);
console.log('Zeros detected:', sodium.is_zero(zeros)); // true
console.log('Non-zeros detected:', !sodium.is_zero(nonZeros)); // true
// Memory zeroing
const sensitive = sodium.from_string('sensitive data');
console.log('Before zeroing:', sodium.to_string(sensitive));
sodium.memzero(sensitive);
console.log('After zeroing is all zeros:', sodium.is_zero(sensitive)); // true
// Increment operation (little-endian)
const counter = new Uint8Array([0, 0, 0, 1]); // 16777216 in little-endian
console.log('Counter before:', Array.from(counter));
sodium.increment(counter);
console.log('Counter after:', Array.from(counter)); // [1, 0, 0, 1]
// Addition (little-endian)
const num1 = new Uint8Array([5, 0, 0, 0]); // 5
const num2 = new Uint8Array([3, 0, 0, 0]); // 3
sodium.add(num1, num2); // num1 = num1 + num2
console.log('Addition result:', Array.from(num1)); // [8, 0, 0, 0] = 8// PKCS#7 padding
const data = sodium.from_string('Hello World!');
const padded = sodium.pad(data, 16);
console.log('Original length:', data.length); // 12
console.log('Padded length:', padded.length); // 16
console.log('Padded data:', sodium.to_hex(padded));
// Unpadding
const unpadded = sodium.unpad(padded, 16);
console.log('Unpadded matches original:',
sodium.memcmp(data, unpadded)); // true
// Different block sizes
const padded8 = sodium.pad(data, 8);
const padded32 = sodium.pad(data, 32);
console.log('8-byte padded length:', padded8.length); // 16
console.log('32-byte padded length:', padded32.length); // 32// One-time authentication (use key only once!)
const onetimeKey = sodium.crypto_onetimeauth_keygen();
const message = sodium.from_string('One-time authenticated message');
const tag = sodium.crypto_onetimeauth(message, onetimeKey);
const isValid = sodium.crypto_onetimeauth_verify(tag, message, onetimeKey);
console.log('One-time auth tag:', sodium.to_hex(tag));
console.log('Tag is valid:', isValid); // true
// CRITICAL: Never reuse the key!
// Using the same key again breaks security
sodium.memzero(onetimeKey); // Clear the key
// Streaming one-time authentication
const streamKey = sodium.crypto_onetimeauth_keygen();
const state = sodium.crypto_onetimeauth_init(streamKey);
const chunk1 = sodium.from_string('First chunk ');
const chunk2 = sodium.from_string('Second chunk');
sodium.crypto_onetimeauth_update(state, chunk1);
sodium.crypto_onetimeauth_update(state, chunk2);
const streamTag = sodium.crypto_onetimeauth_final(state);
// Verify against complete message
const completeMessage = sodium.from_string('First chunk Second chunk');
const streamValid = sodium.crypto_onetimeauth_verify(streamTag, completeMessage, streamKey);
console.log('Streaming auth valid:', streamValid); // true
sodium.memzero(streamKey); // Clear the key// Fast non-cryptographic hashing
const hashKey = sodium.crypto_shorthash_keygen();
// Hash table simulation
const hashTable = new Map();
function addToHashTable(key, value) {
const keyBytes = sodium.from_string(key);
const hash = sodium.crypto_shorthash(keyBytes, hashKey);
const hashHex = sodium.to_hex(hash);
if (!hashTable.has(hashHex)) {
hashTable.set(hashHex, []);
}
hashTable.get(hashHex).push({ key, value });
}
function getFromHashTable(key) {
const keyBytes = sodium.from_string(key);
const hash = sodium.crypto_shorthash(keyBytes, hashKey);
const hashHex = sodium.to_hex(hash);
const bucket = hashTable.get(hashHex);
if (!bucket) return undefined;
const entry = bucket.find(item => item.key === key);
return entry ? entry.value : undefined;
}
// Add some entries
addToHashTable('alice', { id: 1, name: 'Alice' });
addToHashTable('bob', { id: 2, name: 'Bob' });
addToHashTable('charlie', { id: 3, name: 'Charlie' });
// Retrieve entries
console.log('Alice:', getFromHashTable('alice'));
console.log('Bob:', getFromHashTable('bob'));
console.log('David:', getFromHashTable('david')); // undefined
// Show hash distribution
console.log('Hash table size:', hashTable.size);
console.log('Hash table contents:');
for (const [hash, bucket] of hashTable) {
console.log(` ${hash}: ${bucket.length} entries`);
}
// Extended hash for better distribution
const extendedHash = sodium.crypto_shorthash_siphashx24(
sodium.from_string('test key'), hashKey
);
console.log('Extended hash:', sodium.to_hex(extendedHash)); // 16 bytesclass CryptoUtils {
static generateId(length = 16) {
const bytes = sodium.randombytes_buf(length);
return sodium.to_hex(bytes);
}
static constantTimeEquals(a, b) {
if (a.length !== b.length) return false;
return sodium.memcmp(a, b);
}
static secureRandom(min, max) {
const range = max - min;
if (range <= 0) throw new Error('Invalid range');
return min + sodium.randombytes_uniform(range);
}
static encodeData(data, format = 'base64') {
switch (format) {
case 'hex': return sodium.to_hex(data);
case 'base64': return sodium.to_base64(data);
case 'base64url': return sodium.to_base64(data, sodium.base64_variants.URLSAFE_NO_PADDING);
default: throw new Error('Unsupported format');
}
}
static decodeData(encoded, format = 'base64') {
switch (format) {
case 'hex': return sodium.from_hex(encoded);
case 'base64': return sodium.from_base64(encoded);
case 'base64url': return sodium.from_base64(encoded, sodium.base64_variants.URLSAFE_NO_PADDING);
default: throw new Error('Unsupported format');
}
}
static clearSensitiveData(...buffers) {
for (const buffer of buffers) {
if (buffer instanceof Uint8Array) {
sodium.memzero(buffer);
}
}
}
static createChecksum(data) {
// Fast non-cryptographic checksum
const key = sodium.crypto_shorthash_keygen();
const checksum = sodium.crypto_shorthash(data, key);
return {
checksum: sodium.to_hex(checksum),
key: sodium.to_hex(key)
};
}
static verifyChecksum(data, checksumHex, keyHex) {
const key = sodium.from_hex(keyHex);
const expectedChecksum = sodium.crypto_shorthash(data, key);
const actualChecksum = sodium.from_hex(checksumHex);
return sodium.memcmp(expectedChecksum, actualChecksum);
}
}
// Usage examples
console.log('Random ID:', CryptoUtils.generateId());
console.log('Random number 1-100:', CryptoUtils.secureRandom(1, 101));
const testData = sodium.from_string('Test data');
const hex = CryptoUtils.encodeData(testData, 'hex');
const base64 = CryptoUtils.encodeData(testData, 'base64');
const base64url = CryptoUtils.encodeData(testData, 'base64url');
console.log('Hex:', hex);
console.log('Base64:', base64);
console.log('Base64URL:', base64url);
// Checksum example
const fileData = sodium.from_string('Important file content');
const { checksum, key } = CryptoUtils.createChecksum(fileData);
const isValid = CryptoUtils.verifyChecksum(fileData, checksum, key);
console.log('Checksum valid:', isValid); // true// Get library version
console.log('Sodium version:', sodium.sodium_version_string());
console.log('Library version major:', sodium.SODIUM_LIBRARY_VERSION_MAJOR);
console.log('Library version minor:', sodium.SODIUM_LIBRARY_VERSION_MINOR);
console.log('Version string constant:', sodium.SODIUM_VERSION_STRING);Utility functions form the foundation for secure cryptographic implementations and should be used consistently throughout applications.