CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-sodium-native

Low level bindings for libsodium cryptographic library

Pending
Overview
Eval results
Files

aead.mddocs/

Authenticated Encryption with Additional Data (AEAD)

Modern authenticated encryption schemes using ChaCha20-Poly1305 and XChaCha20-Poly1305 for secure encryption with additional data authentication.

Capabilities

XChaCha20-Poly1305-IETF AEAD

Extended nonce authenticated encryption suitable for high-volume applications.

/**
 * Generate random key for XChaCha20-Poly1305-IETF AEAD
 * @param k - Output buffer for key (must be KEYBYTES long)
 */
function crypto_aead_xchacha20poly1305_ietf_keygen(k: Buffer): void;

/**
 * Encrypt message with XChaCha20-Poly1305-IETF AEAD
 * @param c - Output buffer for ciphertext (must be m.length + ABYTES)
 * @param m - Message buffer to encrypt
 * @param ad - Additional data buffer to authenticate (can be null)
 * @param nsec - Must always be null (reserved parameter)
 * @param npub - Nonce/public number buffer (must be NPUBBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 * @returns Number of bytes written to ciphertext buffer
 * @throws Error if encryption fails or parameters invalid
 */
function crypto_aead_xchacha20poly1305_ietf_encrypt(
  c: Buffer,
  m: Buffer,
  ad: Buffer | null,
  nsec: null,
  npub: Buffer,
  k: Buffer
): number;

/**
 * Decrypt and verify with XChaCha20-Poly1305-IETF AEAD
 * @param m - Output buffer for plaintext (must be c.length - ABYTES)
 * @param nsec - Must always be null (reserved parameter)
 * @param c - Ciphertext buffer to decrypt
 * @param ad - Additional data buffer that was authenticated (can be null)
 * @param npub - Nonce/public number buffer (must be NPUBBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 * @returns Number of bytes written to plaintext buffer
 * @throws Error if decryption fails or authentication invalid
 */
function crypto_aead_xchacha20poly1305_ietf_decrypt(
  m: Buffer,
  nsec: null,
  c: Buffer,
  ad: Buffer | null,
  npub: Buffer,
  k: Buffer
): number;

Usage Example:

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

// Generate key and nonce
const key = Buffer.alloc(sodium.crypto_aead_xchacha20poly1305_ietf_KEYBYTES);
const nonce = Buffer.alloc(sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
sodium.crypto_aead_xchacha20poly1305_ietf_keygen(key);
sodium.randombytes_buf(nonce);

// Encrypt with additional data
const message = Buffer.from('Secret message');
const additionalData = Buffer.from('header info');
const ciphertext = Buffer.alloc(message.length + sodium.crypto_aead_xchacha20poly1305_ietf_ABYTES);

const cipherLen = sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(
  ciphertext, message, additionalData, null, nonce, key
);

// Decrypt and verify
const plaintext = Buffer.alloc(ciphertext.length - sodium.crypto_aead_xchacha20poly1305_ietf_ABYTES);
const plainLen = sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
  plaintext, null, ciphertext, additionalData, nonce, key
);

console.log('Decrypted:', plaintext.subarray(0, plainLen).toString());

XChaCha20-Poly1305-IETF Detached Mode

Encrypt with authentication tag stored separately from ciphertext.

/**
 * Encrypt with XChaCha20-Poly1305-IETF AEAD (detached mode)
 * @param c - Output buffer for ciphertext (must be same length as message)
 * @param mac - Output buffer for authentication tag (must be ABYTES long)
 * @param m - Message buffer to encrypt
 * @param ad - Additional data buffer to authenticate (can be null)
 * @param nsec - Must always be null (reserved parameter)
 * @param npub - Nonce/public number buffer (must be NPUBBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 * @returns Number of bytes written to ciphertext buffer
 * @throws Error if encryption fails
 */
function crypto_aead_xchacha20poly1305_ietf_encrypt_detached(
  c: Buffer,
  mac: Buffer,
  m: Buffer,
  ad: Buffer | null,
  nsec: null,
  npub: Buffer,
  k: Buffer
): number;

/**
 * Decrypt with XChaCha20-Poly1305-IETF AEAD (detached mode)
 * @param m - Output buffer for plaintext (must be same length as ciphertext)
 * @param nsec - Must always be null (reserved parameter)
 * @param c - Ciphertext buffer to decrypt
 * @param mac - Authentication tag buffer (must be ABYTES long)
 * @param ad - Additional data buffer that was authenticated (can be null)
 * @param npub - Nonce/public number buffer (must be NPUBBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 * @throws Error if decryption fails or authentication invalid
 */
function crypto_aead_xchacha20poly1305_ietf_decrypt_detached(
  m: Buffer,
  nsec: null,
  c: Buffer,
  mac: Buffer,
  ad: Buffer | null,
  npub: Buffer,
  k: Buffer
): void;

ChaCha20-Poly1305-IETF AEAD

Standard IETF ChaCha20-Poly1305 authenticated encryption.

/**
 * Generate random key for ChaCha20-Poly1305-IETF AEAD
 * @param k - Output buffer for key (must be KEYBYTES long)
 */
function crypto_aead_chacha20poly1305_ietf_keygen(k: Buffer): void;

/**
 * Encrypt message with ChaCha20-Poly1305-IETF AEAD
 * @param c - Output buffer for ciphertext (must be m.length + ABYTES)
 * @param m - Message buffer to encrypt
 * @param ad - Additional data buffer to authenticate (can be null)
 * @param nsec - Must always be null (reserved parameter)
 * @param npub - Nonce/public number buffer (must be NPUBBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 * @returns Number of bytes written to ciphertext buffer
 * @throws Error if encryption fails or parameters invalid
 */
function crypto_aead_chacha20poly1305_ietf_encrypt(
  c: Buffer,
  m: Buffer,
  ad: Buffer | null,
  nsec: null,
  npub: Buffer,
  k: Buffer
): number;

/**
 * Decrypt and verify with ChaCha20-Poly1305-IETF AEAD
 * @param m - Output buffer for plaintext (must be c.length - ABYTES)
 * @param nsec - Must always be null (reserved parameter)
 * @param c - Ciphertext buffer to decrypt
 * @param ad - Additional data buffer that was authenticated (can be null)
 * @param npub - Nonce/public number buffer (must be NPUBBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 * @returns Number of bytes written to plaintext buffer
 * @throws Error if decryption fails or authentication invalid
 */
function crypto_aead_chacha20poly1305_ietf_decrypt(
  m: Buffer,
  nsec: null,
  c: Buffer,
  ad: Buffer | null,
  npub: Buffer,
  k: Buffer
): number;

ChaCha20-Poly1305-IETF Detached Mode

/**
 * Encrypt with ChaCha20-Poly1305-IETF AEAD (detached mode)
 * @param c - Output buffer for ciphertext (must be same length as message)
 * @param mac - Output buffer for authentication tag (must be ABYTES long)
 * @param m - Message buffer to encrypt
 * @param ad - Additional data buffer to authenticate (can be null)
 * @param nsec - Must always be null (reserved parameter)
 * @param npub - Nonce/public number buffer (must be NPUBBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 * @returns Number of bytes written to ciphertext buffer
 * @throws Error if encryption fails
 */
function crypto_aead_chacha20poly1305_ietf_encrypt_detached(
  c: Buffer,
  mac: Buffer,
  m: Buffer,
  ad: Buffer | null,
  nsec: null,
  npub: Buffer,
  k: Buffer
): number;

/**
 * Decrypt with ChaCha20-Poly1305-IETF AEAD (detached mode)
 * @param m - Output buffer for plaintext (must be same length as ciphertext)
 * @param nsec - Must always be null (reserved parameter)
 * @param c - Ciphertext buffer to decrypt
 * @param mac - Authentication tag buffer (must be ABYTES long)
 * @param ad - Additional data buffer that was authenticated (can be null)
 * @param npub - Nonce/public number buffer (must be NPUBBYTES long)
 * @param k - Key buffer (must be KEYBYTES long)
 * @throws Error if decryption fails or authentication invalid
 */
function crypto_aead_chacha20poly1305_ietf_decrypt_detached(
  m: Buffer,
  nsec: null,
  c: Buffer,
  mac: Buffer,
  ad: Buffer | null,
  npub: Buffer,
  k: Buffer
): void;

Usage Example:

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

// Standard ChaCha20-Poly1305-IETF
const key = Buffer.alloc(sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES);
const nonce = Buffer.alloc(sodium.crypto_aead_chacha20poly1305_ietf_NPUBBYTES);
sodium.crypto_aead_chacha20poly1305_ietf_keygen(key);
sodium.randombytes_buf(nonce);

const message = Buffer.from('Important data');
const header = Buffer.from('v1.0|json|gzip');

// Encrypt with header as additional data
const ciphertext = Buffer.alloc(message.length + sodium.crypto_aead_chacha20poly1305_ietf_ABYTES);
const cipherLen = sodium.crypto_aead_chacha20poly1305_ietf_encrypt(
  ciphertext, message, header, null, nonce, key
);

// Decrypt and authenticate header
const plaintext = Buffer.alloc(ciphertext.length - sodium.crypto_aead_chacha20poly1305_ietf_ABYTES);
const plainLen = sodium.crypto_aead_chacha20poly1305_ietf_decrypt(
  plaintext, null, ciphertext, header, nonce, key
);

Constants

// XChaCha20-Poly1305-IETF constants
const crypto_aead_xchacha20poly1305_ietf_ABYTES: number;
const crypto_aead_xchacha20poly1305_ietf_KEYBYTES: number;
const crypto_aead_xchacha20poly1305_ietf_NPUBBYTES: number;
const crypto_aead_xchacha20poly1305_ietf_NSECBYTES: number;
const crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX: number;

// ChaCha20-Poly1305-IETF constants
const crypto_aead_chacha20poly1305_ietf_ABYTES: number;
const crypto_aead_chacha20poly1305_ietf_KEYBYTES: number;
const crypto_aead_chacha20poly1305_ietf_NPUBBYTES: number;
const crypto_aead_chacha20poly1305_ietf_NSECBYTES: number;
const crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX: number;

Security Considerations

  • Nonce Management: Never reuse nonces with the same key. XChaCha20 allows larger nonces for easier management.
  • Additional Data: Additional data is authenticated but not encrypted. Use for headers, metadata, etc.
  • Key Reuse: Keys can be safely reused with different nonces, but consider key rotation for long-term use.
  • Message Limits: Respect maximum message size limits for each variant.

Common Patterns

API Request/Response Encryption

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

class APIEncryption {
  constructor() {
    this.key = Buffer.alloc(sodium.crypto_aead_xchacha20poly1305_ietf_KEYBYTES);
    sodium.crypto_aead_xchacha20poly1305_ietf_keygen(this.key);
  }
  
  encryptRequest(method, url, body) {
    const nonce = Buffer.alloc(sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
    sodium.randombytes_buf(nonce);
    
    // Use HTTP method and URL as additional data
    const additionalData = Buffer.from(`${method} ${url}`);
    const messageBuffer = Buffer.from(JSON.stringify(body));
    
    const ciphertext = Buffer.alloc(
      messageBuffer.length + sodium.crypto_aead_xchacha20poly1305_ietf_ABYTES
    );
    
    const cipherLen = sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(
      ciphertext,
      messageBuffer,
      additionalData,
      null,
      nonce,
      this.key
    );
    
    return {
      nonce: nonce.toString('base64'),
      ciphertext: ciphertext.subarray(0, cipherLen).toString('base64'),
      method,
      url
    };
  }
  
  decryptRequest(encryptedRequest) {
    const nonce = Buffer.from(encryptedRequest.nonce, 'base64');
    const ciphertext = Buffer.from(encryptedRequest.ciphertext, 'base64');
    const additionalData = Buffer.from(`${encryptedRequest.method} ${encryptedRequest.url}`);
    
    const plaintext = Buffer.alloc(
      ciphertext.length - sodium.crypto_aead_xchacha20poly1305_ietf_ABYTES
    );
    
    const plainLen = sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
      plaintext,
      null,
      ciphertext,
      additionalData,
      nonce,
      this.key
    );
    
    return JSON.parse(plaintext.subarray(0, plainLen).toString());
  }
}

Database Field Encryption

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

class FieldEncryption {
  constructor(masterKey) {
    this.masterKey = Buffer.from(masterKey);
  }
  
  // Derive field-specific key from master key
  deriveFieldKey(tableName, fieldName) {
    const context = Buffer.from(`${tableName}.${fieldName}`);
    const fieldKey = Buffer.alloc(sodium.crypto_aead_xchacha20poly1305_ietf_KEYBYTES);
    
    // Simple key derivation (use proper KDF in production)
    const combined = Buffer.concat([this.masterKey, context]);
    sodium.crypto_generichash(fieldKey, combined);
    
    return fieldKey;
  }
  
  encryptField(tableName, fieldName, value, recordId) {
    const fieldKey = this.deriveFieldKey(tableName, fieldName);
    const nonce = Buffer.alloc(sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
    sodium.randombytes_buf(nonce);
    
    // Use record ID as additional data for integrity
    const additionalData = Buffer.from(recordId.toString());
    const plaintext = Buffer.from(value);
    
    const ciphertext = Buffer.alloc(
      plaintext.length + sodium.crypto_aead_xchacha20poly1305_ietf_ABYTES
    );
    
    const cipherLen = sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(
      ciphertext,
      plaintext,
      additionalData,
      null,
      nonce,
      fieldKey
    );
    
    // Return as base64 with nonce prepended
    const encrypted = Buffer.concat([nonce, ciphertext.subarray(0, cipherLen)]);
    return encrypted.toString('base64');
  }
  
  decryptField(tableName, fieldName, encryptedValue, recordId) {
    const fieldKey = this.deriveFieldKey(tableName, fieldName);
    const encrypted = Buffer.from(encryptedValue, 'base64');
    
    const nonce = encrypted.subarray(0, sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
    const ciphertext = encrypted.subarray(sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
    const additionalData = Buffer.from(recordId.toString());
    
    const plaintext = Buffer.alloc(
      ciphertext.length - sodium.crypto_aead_xchacha20poly1305_ietf_ABYTES
    );
    
    const plainLen = sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
      plaintext,
      null,
      ciphertext,
      additionalData,
      nonce,
      fieldKey
    );
    
    return plaintext.subarray(0, plainLen).toString();
  }
}

// Usage
const encryption = new FieldEncryption('master-key-32-bytes-long-exactly!');

// Encrypt sensitive field
const encryptedSSN = encryption.encryptField('users', 'ssn', '123-45-6789', 12345);

// Decrypt when needed
const originalSSN = encryption.decryptField('users', 'ssn', encryptedSSN, 12345);

File Encryption with Compression

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

class SecureFileStorage {
  constructor() {
    this.key = Buffer.alloc(sodium.crypto_aead_xchacha20poly1305_ietf_KEYBYTES);
    sodium.crypto_aead_xchacha20poly1305_ietf_keygen(this.key);
  }
  
  async encryptFile(filename, fileData) {
    // Compress data first
    const compressed = zlib.gzipSync(fileData);
    
    const nonce = Buffer.alloc(sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
    sodium.randombytes_buf(nonce);
    
    // Use filename as additional data
    const additionalData = Buffer.from(filename);
    
    const ciphertext = Buffer.alloc(
      compressed.length + sodium.crypto_aead_xchacha20poly1305_ietf_ABYTES
    );
    
    const cipherLen = sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(
      ciphertext,
      compressed,
      additionalData,
      null,
      nonce,
      this.key
    );
    
    // Return file package with metadata
    return {
      filename,
      nonce: nonce.toString('hex'),
      ciphertext: ciphertext.subarray(0, cipherLen).toString('hex'),
      compressed: true,
      originalSize: fileData.length,
      encryptedSize: cipherLen
    };
  }
  
  async decryptFile(encryptedFile) {
    const nonce = Buffer.from(encryptedFile.nonce, 'hex');
    const ciphertext = Buffer.from(encryptedFile.ciphertext, 'hex');
    const additionalData = Buffer.from(encryptedFile.filename);
    
    const compressed = Buffer.alloc(
      ciphertext.length - sodium.crypto_aead_xchacha20poly1305_ietf_ABYTES
    );
    
    const compressedLen = sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
      compressed,
      null,
      ciphertext,
      additionalData,
      nonce,
      this.key
    );
    
    // Decompress if compressed
    if (encryptedFile.compressed) {
      return zlib.gunzipSync(compressed.subarray(0, compressedLen));
    }
    
    return compressed.subarray(0, compressedLen);
  }
}

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