CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-sodium-native

Low level bindings for libsodium cryptographic library

Pending
Overview
Eval results
Files

stream.mddocs/

Stream Ciphers

High-performance stream ciphers including ChaCha20, XChaCha20, and Salsa20 for fast symmetric encryption with XOR operations.

Capabilities

ChaCha20 Stream Cipher

High-speed stream cipher suitable for bulk encryption.

/**
 * Generate ChaCha20 keystream
 * @param c - Output buffer for keystream
 * @param n - Nonce buffer (must be NONCEBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 * @throws Error if buffer sizes are incorrect or generation fails
 */
function crypto_stream_chacha20(c: Buffer, n: Buffer, k: Buffer): void;

/**
 * Encrypt/decrypt data with ChaCha20 (XOR operation)
 * @param c - Output buffer for ciphertext/plaintext (same length as message)
 * @param m - Message buffer to encrypt/decrypt
 * @param n - Nonce buffer (must be NONCEBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 * @throws Error if buffer sizes are incorrect or operation fails
 */
function crypto_stream_chacha20_xor(c: Buffer, m: Buffer, n: Buffer, k: Buffer): void;

/**
 * Encrypt/decrypt with ChaCha20 and initial counter
 * @param c - Output buffer for ciphertext/plaintext (same length as message)
 * @param m - Message buffer to encrypt/decrypt
 * @param n - Nonce buffer (must be NONCEBYTES long)
 * @param ic - Initial counter value
 * @param k - Key buffer (must be KEYBYTES long)
 * @throws Error if buffer sizes are incorrect or operation fails
 */
function crypto_stream_chacha20_xor_ic(c: Buffer, m: Buffer, n: Buffer, ic: number, k: Buffer): void;

Usage Example:

const sodium = require('sodium-native');

// ChaCha20 encryption/decryption
const key = Buffer.alloc(sodium.crypto_stream_chacha20_KEYBYTES);
const nonce = Buffer.alloc(sodium.crypto_stream_chacha20_NONCEBYTES);
sodium.randombytes_buf(key);
sodium.randombytes_buf(nonce);

const message = Buffer.from('Hello, ChaCha20!');
const ciphertext = Buffer.alloc(message.length);
const plaintext = Buffer.alloc(message.length);

// Encrypt
sodium.crypto_stream_chacha20_xor(ciphertext, message, nonce, key);

// Decrypt (same operation)
sodium.crypto_stream_chacha20_xor(plaintext, ciphertext, nonce, key);
console.log(plaintext.toString()); // "Hello, ChaCha20!"

ChaCha20-IETF Stream Cipher

IETF-standardized variant of ChaCha20 with different nonce size.

/**
 * Generate ChaCha20-IETF keystream
 * @param c - Output buffer for keystream
 * @param n - Nonce buffer (must be NONCEBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 * @throws Error if buffer sizes are incorrect or generation fails
 */
function crypto_stream_chacha20_ietf(c: Buffer, n: Buffer, k: Buffer): void;

/**
 * Encrypt/decrypt data with ChaCha20-IETF
 * @param c - Output buffer for ciphertext/plaintext (same length as message)
 * @param m - Message buffer to encrypt/decrypt
 * @param n - Nonce buffer (must be NONCEBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 * @throws Error if buffer sizes are incorrect or operation fails
 */
function crypto_stream_chacha20_ietf_xor(c: Buffer, m: Buffer, n: Buffer, k: Buffer): void;

/**
 * Encrypt/decrypt with ChaCha20-IETF and initial counter
 * @param c - Output buffer for ciphertext/plaintext (same length as message)
 * @param m - Message buffer to encrypt/decrypt
 * @param n - Nonce buffer (must be NONCEBYTES long)
 * @param ic - Initial counter value
 * @param k - Key buffer (must be KEYBYTES long)
 * @throws Error if buffer sizes are incorrect or operation fails
 */
function crypto_stream_chacha20_ietf_xor_ic(c: Buffer, m: Buffer, n: Buffer, ic: number, k: Buffer): void;

XChaCha20 Stream Cipher

Extended nonce variant of ChaCha20 for better nonce management.

/**
 * Generate XChaCha20 keystream
 * @param c - Output buffer for keystream
 * @param n - Nonce buffer (must be NONCEBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 * @throws Error if buffer sizes are incorrect or generation fails
 */
function crypto_stream_xchacha20(c: Buffer, n: Buffer, k: Buffer): void;

/**
 * Encrypt/decrypt data with XChaCha20
 * @param c - Output buffer for ciphertext/plaintext (same length as message)
 * @param m - Message buffer to encrypt/decrypt
 * @param n - Nonce buffer (must be NONCEBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 * @throws Error if buffer sizes are incorrect or operation fails
 */
function crypto_stream_xchacha20_xor(c: Buffer, m: Buffer, n: Buffer, k: Buffer): void;

/**
 * Encrypt/decrypt with XChaCha20 and initial counter
 * @param c - Output buffer for ciphertext/plaintext (same length as message)
 * @param m - Message buffer to encrypt/decrypt
 * @param n - Nonce buffer (must be NONCEBYTES long)
 * @param ic - Initial counter value
 * @param k - Key buffer (must be KEYBYTES long)
 * @throws Error if buffer sizes are incorrect or operation fails
 */
function crypto_stream_xchacha20_xor_ic(c: Buffer, m: Buffer, n: Buffer, ic: number, k: Buffer): void;

Salsa20 Stream Cipher

High-performance stream cipher, predecessor to ChaCha20.

/**
 * Generate Salsa20 keystream
 * @param c - Output buffer for keystream
 * @param n - Nonce buffer (must be NONCEBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 * @throws Error if buffer sizes are incorrect or generation fails
 */
function crypto_stream_salsa20(c: Buffer, n: Buffer, k: Buffer): void;

/**
 * Encrypt/decrypt data with Salsa20
 * @param c - Output buffer for ciphertext/plaintext (same length as message)
 * @param m - Message buffer to encrypt/decrypt
 * @param n - Nonce buffer (must be NONCEBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 * @throws Error if buffer sizes are incorrect or operation fails
 */
function crypto_stream_salsa20_xor(c: Buffer, m: Buffer, n: Buffer, k: Buffer): void;

/**
 * Encrypt/decrypt with Salsa20 and initial counter
 * @param c - Output buffer for ciphertext/plaintext (same length as message)
 * @param m - Message buffer to encrypt/decrypt
 * @param n - Nonce buffer (must be NONCEBYTES long)
 * @param ic - Initial counter value
 * @param k - Key buffer (must be KEYBYTES long)
 * @throws Error if buffer sizes are incorrect or operation fails
 */
function crypto_stream_salsa20_xor_ic(c: Buffer, m: Buffer, n: Buffer, ic: number, k: Buffer): void;

Stateful Stream Cipher Wrappers

Sodium-native specific wrappers for streaming encryption with state management.

/**
 * Initialize ChaCha20 streaming encryption state
 * @param state - State buffer (must be STATEBYTES long)
 * @param n - Nonce buffer (must be NONCEBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 */
function crypto_stream_chacha20_xor_wrap_init(state: Buffer, n: Buffer, k: Buffer): void;

/**
 * Update ChaCha20 streaming encryption with more data
 * @param state - State buffer from init
 * @param c - Output buffer for ciphertext/plaintext (same length as message)
 * @param m - Message buffer to encrypt/decrypt
 */
function crypto_stream_chacha20_xor_wrap_update(state: Buffer, c: Buffer, m: Buffer): void;

/**
 * Finalize ChaCha20 streaming encryption
 * @param state - State buffer from init/update
 */
function crypto_stream_chacha20_xor_wrap_final(state: Buffer): void;

Usage Example:

const sodium = require('sodium-native');

// Streaming encryption for large data
const key = Buffer.alloc(sodium.crypto_stream_chacha20_KEYBYTES);
const nonce = Buffer.alloc(sodium.crypto_stream_chacha20_NONCEBYTES);
sodium.randombytes_buf(key);
sodium.randombytes_buf(nonce);

const state = Buffer.alloc(sodium.crypto_stream_chacha20_xor_STATEBYTES);
sodium.crypto_stream_chacha20_xor_wrap_init(state, nonce, key);

// Process data in chunks
const chunk1 = Buffer.from('First chunk of data');
const chunk2 = Buffer.from('Second chunk of data');
const encrypted1 = Buffer.alloc(chunk1.length);
const encrypted2 = Buffer.alloc(chunk2.length);

sodium.crypto_stream_chacha20_xor_wrap_update(state, encrypted1, chunk1);
sodium.crypto_stream_chacha20_xor_wrap_update(state, encrypted2, chunk2);

sodium.crypto_stream_chacha20_xor_wrap_final(state);

Constants

// Generic stream cipher constants
const crypto_stream_KEYBYTES: number;
const crypto_stream_NONCEBYTES: number;

// ChaCha20 constants
const crypto_stream_chacha20_KEYBYTES: number;
const crypto_stream_chacha20_NONCEBYTES: number;
const crypto_stream_chacha20_MESSAGEBYTES_MAX: number;
const crypto_stream_chacha20_xor_STATEBYTES: number;

// ChaCha20-IETF constants
const crypto_stream_chacha20_ietf_KEYBYTES: number;
const crypto_stream_chacha20_ietf_NONCEBYTES: number;
const crypto_stream_chacha20_ietf_MESSAGEBYTES_MAX: number;
const crypto_stream_chacha20_ietf_xor_STATEBYTES: number;

// XChaCha20 constants
const crypto_stream_xchacha20_KEYBYTES: number;
const crypto_stream_xchacha20_NONCEBYTES: number;
const crypto_stream_xchacha20_MESSAGEBYTES_MAX: number;
const crypto_stream_xchacha20_xor_STATEBYTES: number;

// Salsa20 constants
const crypto_stream_salsa20_KEYBYTES: number;
const crypto_stream_salsa20_NONCEBYTES: number;
const crypto_stream_salsa20_MESSAGEBYTES_MAX: number;
const crypto_stream_salsa20_xor_STATEBYTES: number;

// Sodium-native specific
const sn_crypto_stream_xor_STATEBYTES: number;

Security Considerations

  • Nonce Reuse: Never reuse nonces with the same key. Each encryption must use a unique nonce.
  • Key Management: Use secure key generation and storage practices.
  • Message Size: Be aware of maximum message size limits for each cipher variant.
  • Authentication: Stream ciphers provide no authentication - consider using AEAD modes or separate MAC.

Common Patterns

File Encryption with Stream Cipher

const sodium = require('sodium-native');
const fs = require('fs');

class StreamFileEncryption {
  constructor(cipher = 'xchacha20') {
    this.cipher = cipher;
    this.keyBytes = sodium[`crypto_stream_${cipher}_KEYBYTES`];
    this.nonceBytes = sodium[`crypto_stream_${cipher}_NONCEBYTES`];
  }
  
  encryptFile(inputFile, outputFile, key) {
    const nonce = Buffer.alloc(this.nonceBytes);
    sodium.randombytes_buf(nonce);
    
    const input = fs.readFileSync(inputFile);
    const output = Buffer.alloc(input.length);
    
    sodium[`crypto_stream_${this.cipher}_xor`](output, input, nonce, key);
    
    // Prepend nonce to encrypted data
    const encrypted = Buffer.concat([nonce, output]);
    fs.writeFileSync(outputFile, encrypted);
  }
  
  decryptFile(inputFile, outputFile, key) {
    const encrypted = fs.readFileSync(inputFile);
    const nonce = encrypted.subarray(0, this.nonceBytes);
    const ciphertext = encrypted.subarray(this.nonceBytes);
    
    const output = Buffer.alloc(ciphertext.length);
    sodium[`crypto_stream_${this.cipher}_xor`](output, ciphertext, nonce, key);
    
    fs.writeFileSync(outputFile, output);
  }
}

Streaming Data Encryption

const sodium = require('sodium-native');

class StreamCipher {
  constructor(key, nonce, cipher = 'chacha20') {
    this.cipher = cipher;
    this.state = Buffer.alloc(sodium[`crypto_stream_${cipher}_xor_STATEBYTES`]);
    sodium[`crypto_stream_${cipher}_xor_wrap_init`](this.state, nonce, key);
  }
  
  process(data) {
    const output = Buffer.alloc(data.length);
    sodium[`crypto_stream_${this.cipher}_xor_wrap_update`](this.state, output, data);
    return output;
  }
  
  finalize() {
    sodium[`crypto_stream_${this.cipher}_xor_wrap_final`](this.state);
  }
}

// Usage
const key = Buffer.alloc(sodium.crypto_stream_chacha20_KEYBYTES);
const nonce = Buffer.alloc(sodium.crypto_stream_chacha20_NONCEBYTES);
sodium.randombytes_buf(key);
sodium.randombytes_buf(nonce);

const cipher = new StreamCipher(key, nonce);

// Process data in chunks
const encrypted1 = cipher.process(Buffer.from('First chunk'));
const encrypted2 = cipher.process(Buffer.from('Second chunk'));

cipher.finalize();

Counter Mode with Custom Position

const sodium = require('sodium-native');

function encryptAtPosition(data, key, nonce, position) {
  // Calculate initial counter based on position
  const blockSize = 64; // ChaCha20 block size
  const initialCounter = Math.floor(position / blockSize);
  
  const output = Buffer.alloc(data.length);
  sodium.crypto_stream_chacha20_xor_ic(output, data, nonce, initialCounter, key);
  
  return output;
}

// Useful for random access in encrypted files
const key = Buffer.alloc(sodium.crypto_stream_chacha20_KEYBYTES);
const nonce = Buffer.alloc(sodium.crypto_stream_chacha20_NONCEBYTES);
sodium.randombytes_buf(key);
sodium.randombytes_buf(nonce);

// Encrypt data at specific file position
const position = 1024; // Start encryption at byte 1024
const data = Buffer.from('Data to encrypt at position');
const encrypted = encryptAtPosition(data, key, nonce, position);

Install with Tessl CLI

npx tessl i tessl/npm-sodium-native

docs

aead.md

auth.md

box.md

ed25519.md

hash.md

index.md

kdf.md

kx.md

memory.md

pwhash.md

random.md

secretbox.md

secretstream.md

shorthash.md

sign.md

stream.md

tile.json