
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
next-cryptr
Advanced tools
Cryptographic utility for encrypting and decrypting data using AES-GCM 256 algorithm. Fully optimized for Next.js. Based on built-in API crypto.subtle.* methods.
NextCryptr is a cryptographic utility module for encrypting and decrypting data using the AES-GCM 256 algorithm. It's specifically designed to work with Next.js Edge Runtime and thus has no dependency to Node.js built-in modules like crypto. It is also optimized for browser with a reduced total bundle size, thanks to its tree-shaking ready dependencies and import schemas.
AES-GCM algorithm is a symmetric encryption algorithm that provides both confidentiality and integrity. It is based on the Advanced Encryption Standard (AES) and the Galois/Counter Mode (GCM) block cipher mode of operation. It can be use to encrypt messages or documents between two or more parties who share the same secret key. Another usecase is for webservers in procedure like One-Time Password (OTP), or for cookie session encryption.
A proper use of AES-GCM should follow the NIST Special Publication 800-38D recommendations. This includes:
This package is based on the standard web crypto API, specifically the crypto.subtle.* methods. You can use this package without any other external cryptographic package.
NextCryptr is compatible with the following runtime environments (non exhaustive):
NextCryptr is fully optimized and has great performances (see dedicated section for more information):
node:crypto module for encrypting and decryptind data up to 4kB;cryptr NPM module for encrypting and decrypting data up to 10kB.Install NextCryptr with npm:
npm install next-cryptr
First, import the NextCryptr class from the next-cryptr package:
import { NextCryptr } from 'next-cryptr';
Next, create a new instance of NextCryptr, passing your secret as a parameter to the constructor:
const cryptr = new NextCryptr({
secret: 'your-256-bits-secret-base64-encoded',
});
Replace 'your-256-bits-secret-base64-encoded' with your actual secret. Please check the following section to learn how to generate a secret.
You can also provide some optional parameters:
ivGenerator: A custom IV generator function. By default, NextCryptr uses a random IV generator function. Please check the following section to learn more about IV generation.encoding: The encoding for returning the encrypted data as a string. Default is TO_BASE64URL, thus the encrypt results in base64url encoded string. But you can also use TO_HEX, TO_BASE64, or your own Encoder instance. These are encoders from the next-buffer package. For convenience, they are also exported by next-cryptr package, and you can use them as follow:import { NextCryptr, TO_HEX } from 'next-cryptr';
const cryptr = new NextCryptr({
secret: 'your-256-bits-secret-base64-encoded',
encoder: TO_HEX,
});
Now, you can use the encrypt and decrypt methods to encrypt and decrypt ArrayBuffer, TypedArray or DataView of data, or their respective encryptString and decryptString methods to encrypt and decrypt string. Here's an example with the latest:
const clearText = "Hello, Mr Warniiiz 👋"
const encryptedText = await cryptr.encryptString(clearText);
console.log(encryptedText);
// Expected result (should vary depending on your own secret):
// 'rZfOpIz3QrUzvXSLODlKs7kZplVfdG82u9LInUQtFTLpOlzro7yEC6N1kux3IEQvXXQP'
const decryptedText = await cryptr.decryptString(encryptedText);
console.log(decryptedText);
// Expected result: 'Hello, Mr Warniiiz 👋'
Also, note that the encrypt and decrypt methods are asynchronous and return Promises, so you need to use async/await or .then/.catch to handle them.
The security of symmetric encryption resides in the secrecy of the key. Any person who knows your key could decrypt your encrypted data. You must generate a strong secret on your own device and keep it secure.
Another consideration is the correct use of IV (Initialization Vector). Next-cryptr is handling all the implementation details for you, randomly generating the IV at each encryption, as per the NIST recommandations. But is has some implications on the maximum message size and maximum number of messages that can be encrypted with the same key.
To generate a secret, you can use the included static async method in NextCryptr class:
import { generateBase64Secret } from 'next-cryptr';
const mySecret = await generateBase64Secret();
console.log(mySecret);
// Expected result (should change on each call):
// 'BK1jwARaoB1/gK1s1qA6qE7mFbdjV1wgAy1PRfWEvQU='
The previous code generates a random 256-bit secret, converts it to base64 encoded string, and logs it to the console. Please check the following section to learn how to store this secret.
You can also generate a secret directly in a terminal using node and the following command:
# Command line interface
node -e "crypto.subtle.generateKey({name: 'AES-GCM', length: 256}, true, ['encrypt', 'decrypt']).then(v => crypto.subtle.exportKey('raw', v)).then(v => console.log(Buffer.from(v).toString('base64')))";
Best practices concerning the storage of your newly created secret key are to store it in an environment variable, like in a .env file for example.
You should never hardcode your secret key in your code and, worst, store it in a public repository. So be sure to add your .env file to your .gitignore file.
Here is an example of a .env file:
# File: .env
SECRET_KEY="your-256-bits-secret-base64-encoded"
And how to use it in Node Runtime environment:
import { NextCryptr } from 'next-cryptr';
const cryptr = new NextCryptr(process.env.SECRET_KEY);
Depending on your use cases, you may need to manage multiple keys. NextCryptr does not provide a built-in way to manage multiple keys or key-rotation, but it could be an implementation idea for further development / packages.
Rules concerning the IV (Initialization Vector) for AES-GCM:
IV is not a secret. It is actually shared as a prefix of the encrypted message. In the cas of AES-GCM algorithm, IV does not need to be very different for each message: a simple incremental counter can do the task, as long as it is unique for each message encrypted under the same key.
As per the NIST recommendations, you shall use the same IV generator function for the entire lifespan of the key. By default, NextCryptr uses a random IV generator function, which comes with the following limitations:
Explanation: Since the IV is 96 bits, the maximum number of messages that can be encrypted under the same key would be 2^96, which is an extremely large number... but considering that the IV is randomly generated, there is a risk of IV collision (same IV for different messages). And considering the "birthday problem", the NIST suggests to limit probability of IV collision to 2^-32 (about 1 out of 4,300,000,000). This probability is reached when number of encryptions under the same key reach 2^32 (about 4,300,000,000 encrypted messages), so NIST recommends to change your key before reaching this number of encryptions.
Please read the NIST Special Publication 800-38D for more information.
Be sure to understand the implications of using a custom IV generator function. NextCryptr and its contributors disclaim all liaibility in the event of misuse.
NextCryptr allows you to provide your own IV generator function:
import { NextCryptr } from 'next-cryptr';
const cryptr = new NextCryptr({
secret: 'your-256-bits-secret-base64-encoded',
ivGenerator: yourOwnGeneratorFunction,
});
This function shall return an UInt8Array of 12 bytes (96 bits), or the constructor will throw an error. It is called each time the encrypt method is called. No parameters are passed to this function.
For example, since the only specification for AES-GCM IV is to be a nonce, you could use a basic counter (fully deterministic) for an IV generator function. If you manage to implement it in your system (and to guarantee that the IV remains unique even after a crash / restart, for example), it would be the best option. But implementations becomes far more complex in real environments, especially in distributed systems.
NextCryptr also comes with a timestamp-based IV generator function. This IV generator has been made for those who don't want to rely only on a random number generator. This generator uses a combination of the current timestamp and some random number to generate a 12-bytes IV, thus guaranteeing a new unique IV prefix each second, on a period of 34 years.
IV is composed of:
66 random bits means 2^66 possible values. The probability of collision used in the NIST specification, of 2^-32 (1 out of 4,300,000,000), is then reached when you encode more than 185,000 messages in less than 1 second.
The probability of collision becomes inexistant if you encode no more than 1 message per second and you use the same key no more than 34 years.
import { NextCryptr, getTimestampComposedIv } from 'next-cryptr';
const cryptr = new NextCryptr({
secret: 'your-256-bits-secret-base64-encoded',
ivGenerator: getTimestampComposedIv,
});
Please note that this implementation does not follow the NIST recommendations. Use it at your own risk.
Maximum message size: AES-GCM is limited to 64 GBytes of encrypted data for each Key-IV couple. You should consider other cryptographic algorithms if you need to encrypt larger messages.
The NextCryptr class has the following methods:
NextCryptr(options)Creates a new instance of NextCryptr. Options:
secret: The secret key to use for encryption and decryption. This parameter is required and should be a base64 encoded string.ivGenerator (optional): A custom IV generator function. By default, NextCryptr uses a random IV generator function.encoder (optional): The encoding for returning the encrypted data as a string. Default is TO_BASE64URL, thus the encrypt results in base64url encoded string. More information.const cryptr = new NextCryptr({secret});
cryptr.encrypt(data)Encrypts binary data (Uint8Array), based on AES-GCM algorithm, and encode the result in base64url (or any chosen encoding scheme).
data (Uint8Array): The data to encrypt. This parameter is required and can be an ArrayBuffer, a TypedArray, or a DataView.Returns a Promise that resolves with the encrypted data as an encoded string. Result is composed of the IV and the encrypted data, both encoded (base64url-encoded by default) in a single string.
cryptr.decrypt(encodedEncryptedData)Decodes and decrypts the encrypted and encoded data.
encodedEncryptedData (string): The encrypted and encoded data to decrypt.Returns a Promise that resolves with the decrypted data as binary data (Uint8Array).
cryptr.encryptString(string)Encrypts a simple string, converting the string to a Uint8Array, and using above encrypt method, thus returning an encoded string.
string (string): The string to encrypt.Returns a Promise that resolves with the encrypted data as a base64 encoded string.
cryptr.decryptString(encodedEncryptedString)Decode and decrypts the encrypted and encoded string.
encodedEncryptedString (string): The encrypted ans encoded string to decrypt.Returns a Promise that resolves with the decrypted string.
generateBase64Secret()Generates a random 256-bit secret key with built-in cryptographically secured methods, and returns it as a base64 encoded string.
For tree-shaking purpose, generateBase64Secret is neither a static method nor an instance method of NextCryptr and shall be imported separately:
import { generateBase64Secret } from 'next-cryptr';
const myNewSecret = generateBase64Secret();
getRandomIv() and getTimestampComposedIv()Respectively generates a random IV and a timestamp-based IV.
getRandomIv is the default IV generator used in NextCryptr. It follows the NIST recommendations for IV generation;getTimestampComposedIv is a custom IV generator function that uses a timestamp-based IV, that you can use if you don't want to rely only on a random number generator. Please read the related section before using it.For tree-shaking purpose, these methods are neither static method nor instance method of NextCryptr and shall be imported separately:
import { getRandomIv } from 'next-cryptr';
import { getTimestampComposedIv } from 'next-cryptr';
To launch the tests using jest:
npm run test
You can check encrypting / decrypting performances, on different string lengths, running the following command:
npm run perf
Speed of encryption / decryption is measured against the widely used cryptr NPM module, and also directly against the Node's crypto API (node:crypto).
Contributions are welcome! Please open an issue or submit a pull request on GitHub.
NextCryptr is ISC licensed.
FAQs
Cryptographic utility for encrypting and decrypting data using AES-GCM 256 algorithm. Fully optimized for Next.js. Based on built-in API crypto.subtle.* methods.
We found that next-cryptr demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.