js-nacl: High-level libsodium API
js-nacl is a JavaScript library offering a high-level API for libsodium, a well-regarded cryptographic library based on NaCl. It operates by wrapping an Emscripten-compiled version of libsodium, providing robust cryptographic primitives for both Node.js and browser environments. The current stable version, 1.4.0, was released in late 2018 and is based on libsodium 1.0.18-stable. Key differentiators include its adherence to the security-focused libsodium API, cross-platform compatibility, and the use of WebAssembly (WASM) for performance since version 1.3.0. It aims to simplify complex cryptographic tasks, offering functions for encryption, decryption, hashing, and digital signatures. Browser usage requires support for the `window.crypto.getRandomValues` API. The project's release cadence historically followed libsodium updates, with a focus on stability and API consistency, though it has not seen recent updates since 2018.
Common errors
-
TypeError: nacl is not defined
cause Attempting to use the `nacl` API object directly without first instantiating it through `nacl_factory.instantiate()`.fixAlways call `nacl_factory.instantiate((naclInstance) => { /* use naclInstance */ })` to get the `nacl` object. The instantiation is asynchronous. -
TypeError: nacl_factory.instantiate is not a function
cause The `nacl_factory` object was not correctly loaded or required. In Node.js, often caused by an incorrect `require` path or trying to use ES Modules `import`.fixFor Node.js, use `const nacl_factory = require('js-nacl/lib/nacl_factory.js');`. For browsers, ensure `<script src="lib/nacl_factory.js">` is correctly placed before your script. -
SecurityError: The operation is not supported.
cause This error typically occurs in a browser environment when `window.crypto.getRandomValues` is not available or accessible, which is required by `js-nacl`.fixEnsure the browser is modern enough to support `window.crypto.getRandomValues` and that the script is running in a secure context (e.g., HTTPS) if the browser enforces it.
Warnings
- breaking The `nacl_factory.instantiate` function's API changed to expect a callback as its first argument, which receives the `nacl` instance.
- breaking The library API was changed from directly providing a `nacl` module to providing `nacl_factory` with an `instantiate` function that returns the `nacl` instance.
- deprecated Functions `crypto_sign_keypair_from_seed` and `crypto_box_keypair_from_seed` were renamed to `crypto_sign_seed_keypair` and `crypto_box_seed_keypair` respectively to align with libsodium naming conventions.
- gotcha js-nacl is known to have issues and potential data corruption when running on Safari version 5.1.x, especially with Javascript debug mode disabled.
- gotcha Browser usage of js-nacl requires support for the `window.crypto.getRandomValues` API for secure random number generation.
- gotcha As of version 1.3.2, the Emscripten-compiled code no longer adds a listener to the `uncaughtException` event in Node.js.
Install
-
npm install js-nacl -
yarn add js-nacl -
pnpm add js-nacl
Imports
- nacl_factory
import { nacl_factory } from 'js-nacl';const nacl_factory = require('js-nacl/lib/nacl_factory.js'); - nacl
const nacl = require('js-nacl');nacl_factory.instantiate((nacl) => { /* use nacl API */ }); - Browser Global
import * as nacl from 'js-nacl';
<script src="node_modules/js-nacl/lib/nacl_factory.js"></script> <script> nacl_factory.instantiate((nacl) => { /* use nacl */ }); </script>
Quickstart
const nacl_factory = require('js-nacl/lib/nacl_factory.js');
nacl_factory.instantiate((nacl) => {
if (!nacl) {
console.error('Failed to instantiate nacl library.');
return;
}
// Generate a random 32-byte key
const key = nacl.random_bytes(nacl.crypto_box_SECRETKEYBYTES);
console.log('Generated key (hex):', nacl.to_hex(key));
// Example: Generate a random nonce
const nonce = nacl.random_bytes(nacl.crypto_box_NONCEBYTES);
console.log('Generated nonce (hex):', nacl.to_hex(nonce));
// Example: Hash a message
const message = nacl.from_string('Hello, js-nacl!');
const hash = nacl.crypto_hash(message);
console.log('Hashed message (hex):', nacl.to_hex(hash));
});