Low level bindings for libsodium cryptographic library
—
Modern authenticated encryption schemes using ChaCha20-Poly1305 and XChaCha20-Poly1305 for secure encryption with additional data authentication.
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());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;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;/**
* 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
);// 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;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());
}
}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);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