{"id":16783,"library":"chacha","title":"ChaCha20 Poly1305 Authenticated Cipher","description":"The `chacha` package provides an implementation of the ChaCha20 Poly1305 authenticated encryption algorithm, designed to be compatible with Node.js's `crypto.createCipheriv()` and `createDecipheriv()` API for AES-GCM mode. It uses the more recent IETF draft for ChaCha20-Poly1305 AEAD, which features a 96-bit nonce, distinct from earlier drafts implemented in systems like BoringSSL (though it offers a 'Legacy Aead' for compatibility). The library supports both a pure JavaScript implementation and optional native bindings for performance in Node.js environments, automatically falling back to pure JS where native bindings are unavailable or explicitly opted out. It exposes APIs for the full AEAD, the ChaCha20 stream cipher, and the Poly1305 message authentication code independently. The current stable version is 2.1.0, and while a specific release cadence isn't published, the active GitHub repository and continuous integration suggest ongoing maintenance and stability.","status":"active","version":"2.1.0","language":"javascript","source_language":"en","source_url":"git://github.com/calvinmetcalf/chacha20poly1305","tags":["javascript","chacha20","chacha","poly1305","cipher","hmac","crypto"],"install":[{"cmd":"npm install chacha","lang":"bash","label":"npm"},{"cmd":"yarn add chacha","lang":"bash","label":"yarn"},{"cmd":"pnpm add chacha","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Provides optional performance-optimized native bindings for Node.js. The package falls back to pure JavaScript if native bindings are not available or explicitly bypassed.","package":"chacha-native","optional":true}],"imports":[{"note":"The primary entry point is a CommonJS module that exports an object. For ESM contexts, use `import * as chacha from 'chacha';` and then access properties like `chacha.createCipher`.","wrong":"import chacha from 'chacha';","symbol":"chacha","correct":"const chacha = require('chacha');"},{"note":"Functions like `createCipher` are properties of the main 'chacha' export. While CJS destructuring `const { createCipher } = require('chacha')` works, for ESM, you would typically use `import * as chacha from 'chacha'; const cipher = chacha.createCipher(key, nonce);`.","wrong":"import { createCipher } from 'chacha';","symbol":"createCipher","correct":"const { createCipher } = require('chacha');"},{"note":"To explicitly use the pure JavaScript implementation in a Node.js environment (bypassing native bindings), require this specific path. This is useful for debugging or environments where native modules are problematic.","wrong":"import chachaPureJs from 'chacha/browser';","symbol":"Pure JS Fallback","correct":"const chachaPureJs = require('chacha/browser');"}],"quickstart":{"code":"const chacha = require('chacha');\nconst { Buffer } = require('buffer');\n\n// --- Configuration ---\n// Keys and nonces must be Buffers of specific lengths\nconst key = Buffer.from('0123456789abcdef0123456789abcdef01234567', 'hex'); // 256-bit (32 bytes)\nconst nonce = Buffer.from('fedcba9876543210', 'hex'); // 96-bit (12 bytes)\nconst associatedData = Buffer.from('Example AAD for authentication', 'utf8');\nconst plaintext = Buffer.from('This is a highly confidential message that needs secure encryption!', 'utf8');\n\nconsole.log('Original plaintext:', plaintext.toString('utf8'));\n\n// --- Encryption ---\nconst cipher = chacha.createCipher(key, nonce);\n\n// Set Additional Authenticated Data (AAD) BEFORE processing any data\ncipher.setAAD(associatedData);\n\n// Encrypt the plaintext in parts or all at once\nconst ciphertextChunks = [];\nciphertextChunks.push(cipher.update(plaintext.subarray(0, plaintext.length / 2)));\nciphertextChunks.push(cipher.update(plaintext.subarray(plaintext.length / 2)));\nciphertextChunks.push(cipher.final());\nconst ciphertext = Buffer.concat(ciphertextChunks);\n\n// Get the authentication tag AFTER all data has been processed (after final())\nconst tag = cipher.getAuthTag();\n\nconsole.log('\\nEncrypted Ciphertext (hex):', ciphertext.toString('hex'));\nconsole.log('Authentication Tag (hex):', tag.toString('hex'));\n\n// --- Decryption ---\nconst decipher = chacha.createDecipher(key, nonce);\n\n// Set AAD BEFORE processing any data (must match encryption AAD)\ndecipher.setAAD(associatedData);\n\n// Set the authentication tag BEFORE processing any data (must match encryption tag)\ndecipher.setAuthTag(tag);\n\n// Decrypt the ciphertext\nlet decryptedPlaintext;\ntry {\n  const decryptedChunks = [];\n  decryptedChunks.push(decipher.update(ciphertext.subarray(0, ciphertext.length / 2)));\n  decryptedChunks.push(decipher.update(ciphertext.subarray(ciphertext.length / 2)));\n  decryptedChunks.push(decipher.final());\n  decryptedPlaintext = Buffer.concat(decryptedChunks);\n  console.log('\\nDecrypted Plaintext:', decryptedPlaintext.toString('utf8'));\n  console.log('Decryption successful:', decryptedPlaintext.equals(plaintext));\n} catch (e) {\n  console.error('\\nDecryption failed: The authentication tag or AAD did not match!', e.message);\n}\n","lang":"javascript","description":"This quickstart demonstrates the full ChaCha20 Poly1305 Authenticated Encryption and Decryption (AEAD) flow, including setting the key, nonce, Additional Authenticated Data (AAD), and handling the authentication tag. It highlights the correct order of operations for `setAAD`, `update`, `final`, `getAuthTag`, and `setAuthTag`."},"warnings":[{"fix":"Ensure all parties use the same version of the ChaCha20-Poly1305 AEAD. If interoperating with systems using the older draft, use `chacha.AeadLegacy(key, nonce)` for encryption/decryption on both sides.","message":"The ChaCha20-Poly1305 AEAD standard has evolved. This library primarily implements the more recent IETF draft (longer nonce, shorter counter, specific tag generation). Older implementations, like those in BoringSSL, followed an earlier draft. Mixing versions will lead to authentication failures.","severity":"breaking","affected_versions":">=1.0.0"},{"fix":"Always invoke `cipher.setAAD(associatedData)` immediately after creating the cipher/decipher instance and before processing any encrypted or plaintext data. The same AAD must be used for both encryption and decryption.","message":"The `setAAD(data)` method on cipher/decipher objects MUST be called before any calls to `update()` or `final()`. Calling it out of order will result in incorrect authentication or decryption errors.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure `cipher.getAuthTag()` is the last operation performed on the cipher instance after `cipher.final()` has been called to ensure the complete and correct authentication tag is generated.","message":"The `getAuthTag()` method on a cipher object MUST be called only AFTER all plaintext data has been processed (i.e., after the final `update()` call and `final()`). Calling it prematurely will result in an incomplete or incorrect tag.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Always set the correct authentication tag using `decipher.setAuthTag(tag)` after initializing the decipher and setting AAD, but before decrypting any ciphertext data. Handle potential `try...catch` blocks around decryption to gracefully manage authentication failures.","message":"When decrypting, `decipher.setAuthTag(tag)` MUST be called before any calls to `update()`. If the tag is not set, or if it does not match the tag generated during encryption, the decryption process will throw an 'Error: Mac mismatch' or similar authentication failure.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"To explicitly use the pure JavaScript implementation in Node.js, `require` the specific browser path: `const chachaPureJs = require('chacha/browser');`. This bypasses the native binding attempt.","message":"In Node.js, the package attempts to use native bindings for performance by default. If you need to force the pure JavaScript implementation (e.g., for cross-platform consistency or debugging), the standard `require('chacha')` will not suffice.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Verify that the correct authentication tag (obtained from `cipher.getAuthTag()`) is being passed to `decipher.setAuthTag()`. Ensure `setAuthTag` is called before any `update()` operations during decryption.","cause":"The authentication tag provided to `decipher.setAuthTag()` does not match the original tag generated during encryption, or no tag was set.","error":"Error: Mac mismatch"},{"fix":"Ensure that `cipher.setAAD()` and `decipher.setAAD()` (and `decipher.setAuthTag()`) are called immediately after creating the cipher/decipher instance and before any `update()` or `final()` calls.","cause":"Attempting to call `setAAD()` or `setAuthTag()` after data has already been passed to `update()` or `final()`.","error":"TypeError: decipher.setAAD is not a function"},{"fix":"If in a CommonJS module, use `const chacha = require('chacha');`. If in an ES module, use `import * as chacha from 'chacha';` and then access methods via the `chacha` object (e.g., `chacha.createCipher`).","cause":"Attempting to use ES module `import chacha from 'chacha'` syntax in a CommonJS module context, or vice-versa.","error":"ReferenceError: chacha is not defined (or similar import error in ESM)"},{"fix":"Ensure the key is a 32-byte Buffer (256 bits) and the nonce is a 12-byte Buffer (96 bits). Generate them securely using a cryptographically strong random number generator.","cause":"The provided key or nonce `Buffer` does not match the required length (32 bytes for key, 12 bytes for nonce).","error":"Error: key must be 32 bytes (or similar length mismatch for key/nonce)"}],"ecosystem":"npm","meta_description":null}