Miscreant.js
TypeScript implementation of Miscreant: misuse-resistant encryption library with AES-SIV (RFC 5297) and AES-PMAC-SIV support
Install / Use
/learn @miscreant/Miscreant.jsREADME
miscreant.js [![Latest Version][npm-shield]][npm-link] [![Build Status][build-image]][build-link] [![MIT licensed][license-image]][license-link] [![Gitter Chat][gitter-image]][gitter-link]
The best crypto you've never heard of, brought to you by [Phil Rogaway]
JavaScript-compatible TypeScript implementation of Miscreant: Advanced symmetric encryption library which provides the [AES-SIV] ([RFC 5297]), [AES-PMAC-SIV], and [STREAM] constructions. These algorithms are easy-to-use (or rather, hard-to-misuse) and support encryption of individual messages or message streams.
AES-SIV provides [nonce-reuse misuse-resistance] (NRMR): accidentally reusing a nonce with this construction is not a security catastrophe, unlike it is with more popular AES encryption modes like [AES-GCM]. With AES-SIV, the worst outcome of reusing a nonce is an attacker can see you've sent the same plaintext twice, as opposed to almost all other AES modes where it can facilitate [chosen ciphertext attacks] and/or full plaintext recovery.
Help and Discussion
Have questions? Want to suggest a feature or change?
- [Gitter]: web-based chat about miscreant projects including miscreant.js
- [Google Group]: join via web or email ([miscreant-crypto+subscribe@googlegroups.com])
Security Notice
Though this library is written by cryptographic professionals, it has not undergone a thorough security audit, and cryptographic professionals are still humans that make mistakes.
USE AT YOUR OWN RISK
Installation
Via npm:
npm install miscreant
Via Yarn:
yarn install miscreant
Import Miscreant into your project with:
import * as miscreant from "miscreant";
Import
Import Miscreant into your project with the following:
import * as miscreant from "miscreant";
API: Symmetric Encryption (AEAD)
The Authenticated Encryption with Associated Data API, or AEAD API, is the recommended API for encrypting and
decrypting data with Miscreant. It accepts a nonce, optional associated data (i.e. data you'd like to authenticate
along with the encrypted message), and a message to encrypt.
When decrypting, the same nonce and associated data must be supplied as were passed at the time of encryption. If anything is amiss, e.g. if the ciphertext has been tampered with, the cipher will detect it and throw an error.
miscreant.AEAD.importKey()
The miscreant.AEAD.importKey() method creates a new instance of an AES-SIV AEAD encryptor/decryptor.
Syntax
miscreant.AEAD.importKey(keyData, algorithm[, provider = new miscreant.WebCryptoProvider()])
Parameters
- keyData: a [Uint8Array] containing the encryption key to use. Key must be 32-bytes (for AES-128) or 64-bytes (for AES-256), as SIV uses two distinct AES keys to perform its operations.
- algorithm: a string describing the algorithm to use. The following algorithms are supported:
"AES-SIV": CMAC-based construction described in [RFC 5297]. Slower but standardized and more common."AES-PMAC-SIV": PMAC-based construction. Supports potentially faster implementations, but is non-standard and only available in Miscreant libraries.
- provider: a cryptography provider that implements Miscreant's [ICryptoProvider] interface.
Return Value
The miscreant.AEAD.importKey() method returns a [Promise] that, when fulfilled, returns an AEAD encryptor/decryptor.
Example
import * as miscreant from "miscreant";
let keyData = new Uint32Array(32);
// Assuming window.crypto.getRandomValues is available
window.crypto.getRandomValues(keyData);
let key = await miscreant.AEAD.importKey(keyData, "AES-PMAC-SIV");
seal()
The seal() method encrypts a message along with an optional associated data value which will be authenticated along with the message.
Syntax
key.seal(plaintext, nonce[, associatedData = ""])
Parameters
- plaintext: [Uint8Array] data to be encrypted.
- nonce: a single-use value which MUST be unique per encrypted message. Can be any length, and use any uniqueness strategy you like, e.g. a counter or a cryptographically secure random number generator.
- associatedData: (optional) [Uint8Array] that will be authenticated along with the message (but not encrypted).
Return Value
The seal() method returns a [Promise] that, when fulfilled, returns a [Uint8Array] containing the resulting ciphertext.
Example
import * as miscreant from "miscreant";
let keyData = new Uint8Array(32);
// Assuming window.crypto.getRandomValues is available
window.crypto.getRandomValues(keyData);
let key = await miscreant.SIV.importKey(keyData, "AES-PMAC-SIV");
// Encrypt plaintext
let plaintext = new Uint8Array([2,3,5,7,11,13,17,19,23,29]);
let nonce = new Uint8Array(16);
window.crypto.getRandomValues(nonce);
let ciphertext = await key.seal(plaintext, nonce);
open()
The open() method decrypts a message which has been encrypted using AES-SIV or AES-PMAC-SIV.
Syntax
key.open(ciphertext, nonce[, associatedData = ""])
Parameters
- ciphertext: [Uint8Array] containing an encrypted message.
- nonce: [Uint8Array] supplied when the message was originally encrypted.
- associatedData: (optional) [Uint8Array] supplied when the message was originally encrypted.
Return Value
The open() method returns a [Promise] that, when fulfilled, returns a [Uint8Array] containing the decrypted plaintext.
Exceptions
If the message has been tampered with or is otherwise corrupted, the promise will be rejected with an IntegrityError.
Example
import * as miscreant from "miscreant";
let keyData = new Uint8Array(32);
// Assuming window.crypto.getRandomValues is available
window.crypto.getRandomValues(keyData);
let key = await miscreant.SIV.importKey(keyData, "AES-PMAC-SIV");
// Encrypt plaintext
let plaintext = new Uint8Array([2,3,5,7,11,13,17,19,23,29]);
let nonce = new Uint8Array(16);
window.crypto.getRandomValues(nonce);
let ciphertext = await key.seal(plaintext, nonce);
// Decrypt ciphertext
var decrypted = await key.open(ciphertext, nonce);
STREAM API
Miscreant implements an interface that permits incremental processing of encrypted data based on the [STREAM] construction, which is provably secure against a wide range of attacks including truncation and reordering attacks.
The API is provided in the form of miscreant.StreamEncryptor and miscreant.StreamDecryptor classes, which each take
a per-STREAM key and nonce, and from there operate a message-at-a-time on input plaintext/ciphertext along with
optional per-message associated data (i.e. data you'd like to authenticate along with the encrypted message).
miscreant.StreamEncryptor.importKey()
The miscreant.StreamEncryptor.importKey() method creates a new instance of a STREAM encryptor, capable of encrypting a stream of authenticated messages and ensuring their integrity, ordering, and termination.
Syntax
miscreant.StreamEncryptor.importKey(keyData, nonceData, algorithm[, provider = new miscreant.WebCryptoProvider()])
Parameters
- keyData: a [Uint8Array] containing the encryption key to use. Key must be 32-bytes (for AES-128) or 64-bytes (for AES-256), as SIV uses two distinct AES keys to perform its operations.
- nonceData: a 64-bit (8-byte) [Uint8Array] which MUST be unique to this message stream (for a given key).
- algorithm: a string describing the algorithm to use. The following algorithms are supported:
"AES-SIV": CMAC-based construction described in [RFC 5297]. Slower but standardized and more common."AES-PMAC-SIV": PMAC-based construction. Supports potentially faster implementations, but is non-standard and only available in Miscreant libraries.
- provider: a cryptography provider that implements Miscreant's [ICryptoProvider] interface.
Return Value
The miscreant.StreamEncryptor.importKey() method returns a [Promise] that, when fulfilled, returns a StreamEncryptor object.
Example
import * as miscreant from "miscreant";
let keyData = new Uint32Array(32);
let nonceData = new Uint8Array(8);
// Assuming window.crypto.getRandomValues is available
window.crypto.getRandomValues(keyData);
window.crypto.getRandomValues(nonceData);
let encryptor = await miscreant.StreamEncryptor.importKey(keyData, nonceData, "AES-PMAC-SIV");
seal()
The seal() method of miscreant.StreamEncryptor encrypts a message, and also takes an optional associated data
value which will be authenticated along with the message (but not encrypted).
Note that unlike the AEAD API, STREAM encodes the position of the message into the message stream, so the order
in which seal() is called is significant.
Syntax
encryptor.seal(plaintext, [lastBlock = false[, associatedData = ""]])
Parameters
- plaintext: [Uint8Array] data to be encrypted.
- lastBlock: (optional; default: false) is this the last block in the stream?
- associatedData: (optional) [Uint8Array] that will be authenticated along with the message (but not encrypted).
Return Value
The seal() method returns a [Promise] that, when fulfilled, returns a [Uint8Array] containing the resulting ciphertext.
Example
import * as miscreant from "miscreant";
let keyData = new Uint32Array(32);
let nonceData = new Uint8Array(8);
// Assuming window.crypto.getRandomValues is available
window.crypto.getRandomValues(keyData);
window.crypto.getRandomValues(nonceData);
let encryptor = await miscreant.StreamEncryptor.importKey(keyData, nonceData, "AES-PMAC-SIV");
// Encrypt plaintext
let msg1 = new Uint8Array([1,2]);
let msg2 = new Uint8Array([3,4,5]);
let msg3 = new Uint8Array([6,7,8,9]);
Related Skills
healthcheck
352.2kHost security hardening and risk-tolerance configuration for OpenClaw deployments
prose
352.2kOpenProse VM skill pack. Activate on any `prose` command, .prose files, or OpenProse mentions; orchestrates multi-agent workflows.
Writing Hookify Rules
111.1kThis skill should be used when the user asks to "create a hookify rule", "write a hook rule", "configure hookify", "add a hookify rule", or needs guidance on hookify rule syntax and patterns.
Agent Development
111.1kThis skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
