npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

aes-128-cbc

v1.0.7

Published

Web Encrypt,支持AES-128-CBC和RSA加密解密

Readme

aes-128-cbc

A lightweight, dependency-free encryption library for Node.js and browsers, supporting AES-128-CBC and RSA-OAEP with SHA-256. It uses native cryptographic APIs and provides utilities for binary data, UTF-8 strings, and PEM-encoded RSA keys.

Features

  • Native cryptographic APIs with no third-party runtime dependencies.
  • Binary encryption and decryption with ArrayBuffer output.
  • UTF-8 string encryption with Base64-encoded ciphertext.
  • Compatible ciphertext across Node.js and browsers when the key and IV match.
  • Included TypeScript declarations.

Installation

npm install aes-128-cbc

The root entry exports both Aes128CBC and AsymmetricCrypto. Node.js uses index.js; browser-aware bundlers select browser.js. Existing libs/node-aes-utils, libs/web-aes-utils, and libs/AsymmetricCrypto imports remain available.

// Node.js
const { Aes128CBC, AsymmetricCrypto } = require('aes-128-cbc');
// Browser bundlers: explicit entry also selects the browser TypeScript declarations.
import { Aes128CBC, AsymmetricCrypto } from 'aes-128-cbc/browser';

For classic browser scripts, load the files in this order:

<script src="./libs/web/aes-utils.js"></script>
<script src="./libs/web/AsymmetricCrypto.js"></script>
<script src="./browser.js"></script>
<script>
  console.log(window.WebEncrypt.Aes128CBC, window.WebEncrypt.AsymmetricCrypto);
</script>

Vite 8.3.1 and Webpack 5.111.1 production builds have been verified in a browser with both AES and RSA, without Node.js polyfills. The exports browser condition selects the browser entry. The browser mappings also redirect the legacy Node AES path and the Node RSA adapter for frontend builds. Custom bundler configurations that disable browser resolution are outside this setup.

Each library script also exposes its class individually on the browser global object. browser.js groups them under WebEncrypt; it is not a standalone bundle. Native browser ESM imports are not provided.

Source layout

index.js                  # Node.js package entry
browser.js                # Browser package entry
libs/
  node/
    aes-utils.js          # Synchronous Node.js AES implementation
    AsymmetricCrypto.js   # Node.js adapter for the shared RSA implementation
  web/
    aes-utils.js          # Asynchronous browser AES implementation
    AsymmetricCrypto.js   # Shared RSA implementation using Web Crypto

Each implementation has an adjacent .d.ts file. Legacy npm subpaths are retained through exports; direct filesystem or script URLs should use the new directories.

Node.js quick start

const { randomBytes } = require('node:crypto');
const { Aes128CBC } = require('aes-128-cbc');

// Generate a key once and keep it secret for subsequent decryption.
const keyHex = randomBytes(16).toString('hex');

// Generate a fresh IV for every encryption under the same key.
const ivHex = randomBytes(16).toString('hex');
const aes = new Aes128CBC(keyHex, ivHex);

const ciphertext = aes.encrypt_utf8_base64('Hello, world!');

// Store or transmit the IV alongside the ciphertext. Keep the key separate.
const payload = { iv: ivHex, ciphertext };
const receiver = new Aes128CBC(keyHex, payload.iv);
const plaintext = receiver.decrypt_base64_utf8(payload.ciphertext);

console.log(plaintext); // Hello, world!

The Node.js implementation returns values synchronously. It also uses the globals btoa and TextDecoder for its string helpers, so the runtime must provide them.

Browser quick start

Serve the browser script from your application and load it in a secure context, such as HTTPS or localhost, with Web Crypto support.

<script src="./libs/web/aes-utils.js"></script>
<script>
  async function main() {
    const toHex = (bytes) => Array.from(
      bytes,
      (byte) => byte.toString(16).padStart(2, '0')
    ).join('');

    const keyHex = toHex(crypto.getRandomValues(new Uint8Array(16)));
    const ivHex = toHex(crypto.getRandomValues(new Uint8Array(16)));
    const aes = new window.Aes128CBC(keyHex, ivHex);

    const ciphertext = await aes.encrypt_utf8_base64('Hello, browser!');
    const plaintext = await aes.decrypt_base64_utf8(ciphertext);

    console.log(plaintext); // Hello, browser!
  }

  main().catch(console.error);
</script>

Browser encryption and decryption methods return promises. Using await works with both implementations and is appropriate for shared application code.

Binary data

Use an ArrayBuffer for portable code that also matches the included TypeScript declarations:

async function binaryRoundTrip(aes) {
  const input = new Uint8Array([12, 34, 56, 32, 43, 23, 34]);
  const encrypted = await aes.encrypt(input.buffer);
  const decrypted = await aes.decrypt(encrypted);

  console.log(new Uint8Array(decrypted));
  // Uint8Array(7) [12, 34, 56, 32, 43, 23, 34]
}

At runtime, Node.js also accepts Buffer and Uint8Array inputs; the browser implementation accepts Web Crypto buffer sources. If you pass the underlying .buffer of a sliced typed array, it may contain bytes outside the intended view. Pass an ArrayBuffer containing exactly the bytes you want to encrypt.

API reference

new Aes128CBC(keyHexStr?, ivStr?)

| Parameter | Format | Purpose | | --- | --- | --- | | keyHexStr | 32 hexadecimal characters (16 bytes) | AES-128 key. This is a raw key, not a password. | | ivStr | 32 hexadecimal characters (16 bytes) | Initialization vector used for encryption and decryption. |

Both arguments are optional for compatibility with the existing implementation. Omitting an argument or passing undefined selects its hard-coded default. Explicit values must each contain exactly 32 hexadecimal characters (case-insensitive); empty strings, null, non-string values, invalid characters, and incorrect lengths throw TypeError. Supply an explicit secret key and a fresh IV in application code.

Methods

The result column describes the resolved value. Node.js returns it directly; browsers return Promise<result>.

| Method | Input | Result | Description | | --- | --- | --- | --- | | encrypt(data) | ArrayBuffer | ArrayBuffer | Encrypt binary data. | | decrypt(data) | ArrayBuffer | ArrayBuffer | Decrypt binary ciphertext. | | encrypt_utf8_base64(text) | string | string | Encode UTF-8 text, encrypt it, and return Base64 ciphertext. | | decrypt_base64_utf8(ciphertext) | string | string | Decode Base64 ciphertext, decrypt it, and return UTF-8 text. | | time_encrypt_utf8_base64(text) | string | string | Encrypt a JSON wrapper containing the text and two random integers. | | time_decrypt_base64_utf8(ciphertext) | string | string | Decrypt that wrapper and return its text. |

The time_* helpers use the JSON structure { t, s, c }, where s is the input text and t and c are integers from 0 to 999 generated with Math.random(). They do not add a timestamp, expiration check, or replay protection. The matching decrypt helper rejects an empty string because it requires a truthy s field.

The Node.js declarations describe synchronous AES results; the browser declarations describe promises. Import aes-128-cbc/browser for explicit browser types, or use a TypeScript resolver with the browser custom condition. RSA methods are asynchronous in both environments. Using await accommodates both AES implementations.

Ciphertext and interoperability

Both implementations use AES-CBC with PKCS#7 padding. The binary methods return raw ciphertext; the string helpers encode that ciphertext as Base64.

The output does not include the IV, key, or an authentication tag. To decrypt in another environment, preserve the exact key and IV along with the ciphertext's encoding. The time_* format must be decoded with the corresponding helper if you want the original text instead of the JSON wrapper.

Key and IV handling

  • Keep keys secret. The built-in default key is public and unsuitable for protecting application data.
  • Generate a fresh, unpredictable 16-byte IV for each encryption under the same key. Each instance retains its constructor IV, so create a new instance with a new IV for the next message.
  • Retain the IV with the ciphertext for decryption; the IV does not need to be secret.
  • AES-CBC does not authenticate ciphertext. This package does not detect tampering reliably or provide an authenticated message format. Successful decryption is not proof that a message is authentic.
  • The random fields in time_* do not replace a fresh IV or message authentication.

RSA utilities

AsymmetricCrypto uses RSA-OAEP with SHA-256 and PEM-encoded keys. It is available from both entries and supports the same asynchronous API in Node.js and browsers.

async function rsaRoundTrip(AsymmetricCrypto) {
  const { publicKey, privateKey } = await AsymmetricCrypto.generateKeyPair();
  const encrypted = await AsymmetricCrypto.encrypt(publicKey, 'Hello, RSA!');
  const decrypted = await AsymmetricCrypto.decrypt(privateKey, encrypted);
  console.log(decrypted); // Hello, RSA!
}

| Static method | Result | | --- | --- | | generateKeyPair(modulusLength = 2048) | Promise<{ publicKey: string; privateKey: string }> | | encrypt(publicKeyPem, text) | Promise<string> containing Base64 ciphertext | | decrypt(privateKeyPem, ciphertext) | Promise<string> containing plaintext | | importPublicKey(publicKeyPem) / importPrivateKey(privateKeyPem) | Promise<CryptoKey> | | getMaxEncryptLength(publicKeyPem) | Estimated maximum plaintext length in bytes | | derToPem(der, type) / pemToDer(pem) | PEM string / DER ArrayBuffer | | arrayBufferToBase64(buffer) / base64ToArrayBuffer(text) | Base64 string / ArrayBuffer | | validatePemFormat(pem, type) | Boolean indicating PEM text format; does not validate key material |

type is 'PUBLIC' or 'PRIVATE'. With the default 2048-bit key, plaintext is limited to 190 UTF-8 bytes. The existing length estimator assumes common 2048-, 3072-, and 4096-bit keys; it is not accurate for every custom modulus size. For larger payloads, encrypt the data with a suitable symmetric scheme and use RSA for its key.

Development

Run Node.js assertions for both classes and the package entries:

npm test

Run browser tests with a local static server, for example:

python3 -m http.server 8000 --bind 127.0.0.1

Open http://localhost:8000/test/test-browser.html. The page runs AES and RSA assertions against the browser's native Web Crypto API and displays each result. It includes a fixed Node.js AES ciphertext fixture to check interoperability. Test keys are generated at runtime.

With TypeScript 5 or newer available, check the Node and browser declarations:

tsc --noEmit --strict --module Node16 --moduleResolution Node16 --target ES2020 test/types.test.ts
tsc --noEmit --strict --module ESNext --moduleResolution Bundler --customConditions browser --target ES2020 test/types-browser.test.ts

The existing test/test-node-aes.js and test/test-web-aes.html remain available as usage examples.

License

ISC, as declared in package.json.