@push.rocks/smartcrypto
Cross-runtime cryptographic primitives for Node.js and browsers, including strict X25519 envelopes, AES-256-GCM authenticated encryption, DEK wrapping, and the existing RSA key APIs.
Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit community.foss.global/. This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a code.foss.global/ account to submit Pull Requests directly.
Install
pnpm add @push.rocks/smartcrypto
X25519 Envelope Profile
The fixed x25519-hkdf-sha256-aes-256-gcm-v1 profile seals a Uint8Array to one recipient. It uses a fresh ephemeral X25519 key and random 12-byte AES-GCM nonce for every seal. The exact context bytes are mandatory AAD and are also bound into HKDF through their SHA-256 digest.
import {
generateX25519KeyPair,
openX25519Envelope,
sealX25519Envelope,
} from '@push.rocks/smartcrypto';
const encoder = new TextEncoder();
const recipient = await generateX25519KeyPair();
const context = encoder.encode('tenant:example/secret:database-password');
const envelope = await sealX25519Envelope({
plaintext: encoder.encode('secret value'),
recipientPublicKey: recipient.publicKey,
recipientKeyId: 'recipient-key-2026-01',
context,
});
const plaintext = await openX25519Envelope({
envelope,
recipientPrivateKey: recipient.privateKey,
expectedRecipientKeyId: 'recipient-key-2026-01',
context,
});
generateX25519KeyPair() returns strict raw 32-byte public and private material. importX25519PublicKey(), exportX25519PublicKey(), importX25519PrivateKey(), and exportX25519PrivateKey() provide checked conversion to and from standard CryptoKey objects.
The envelope has exactly these fields:
interface IX25519EnvelopeV1 {
schemaVersion: 1;
profile: 'x25519-hkdf-sha256-aes-256-gcm-v1';
recipientKeyId: string;
ephemeralPublicKey: string;
nonce: string;
ciphertext: string;
tag: string;
contextDigest: string;
}
All binary envelope fields use canonical unpadded base64url. parseX25519Envelope() rejects extra fields, unknown versions and profiles, noncanonical encodings, incorrect fixed lengths, malformed key IDs, and ciphertexts larger than SMARTCRYPTO_MAX_CIPHERTEXT_BYTES.
AES-GCM And DEK Wrapping
aesGcmEncrypt() and aesGcmDecrypt() accept only Uint8Array data and exact 32-byte AES keys. AAD is always required, although an explicitly supplied empty Uint8Array is valid. Encryption returns separate nonce, ciphertext, and 16-byte tag fields.
import {
aesGcmDecrypt,
aesGcmEncrypt,
generateDek,
generateAes256GcmKey,
rewrapDek,
unwrapDek,
wrapDek,
} from '@push.rocks/smartcrypto';
const payloadAad = new TextEncoder().encode('payload binding');
const dek = generateDek();
const encryptedPayload = await aesGcmEncrypt({
key: dek,
plaintext: new TextEncoder().encode('payload'),
aad: payloadAad,
});
const oldKek = generateAes256GcmKey();
const newKek = generateAes256GcmKey();
const oldWrapAad = new TextEncoder().encode('old KEK binding');
const newWrapAad = new TextEncoder().encode('new KEK binding');
const wrappedDek = await wrapDek({ dek, kek: oldKek, wrapAad: oldWrapAad });
const rewrappedDek = await rewrapDek({
wrappedDek,
currentKek: oldKek,
currentWrapAad: oldWrapAad,
newKek,
newWrapAad,
});
const unwrappedDek = await unwrapDek({
wrappedDek: rewrappedDek,
kek: newKek,
wrapAad: newWrapAad,
});
const plaintext = await aesGcmDecrypt({
key: unwrappedDek,
encryptedData: encryptedPayload,
aad: payloadAad,
});
rewrapDek() only receives the wrapped DEK, so payload ciphertext, nonce, and tag remain unchanged during KEK rotation.
Errors
Cryptographic and validation failures use SmartCryptoError with a stable TSmartCryptoErrorCode. Messages, JSON output, Node inspection, stack metadata, and cause do not retain plaintext, keys, shared secrets, or ciphertext details.
RSA APIs
The existing Smartcrypto, KeyPair, PrivateKey, and PublicKey APIs remain available. RSA key generation and PEM conversion continue to use the existing behavior:
import { Smartcrypto } from '@push.rocks/smartcrypto';
const smartCrypto = new Smartcrypto();
const keyPair = await smartCrypto.createKeyPair();
const publicKeyPem = keyPair.publicKey.toPemString();
const privateKeyPem = keyPair.privateKey.toPemString();
PublicKey.fromCanonicalRsaPublicPemString() parses one canonical SPKI or PKCS#1 RSA public key with a modulus of at least 2048 bits. PublicKey.verifyRs256() verifies exact RSASSA-PKCS1-v1_5/SHA-256 signatures.
Runtime Support
The WebCrypto APIs are tested with Node.js 22 and current Chromium. Browsers require a secure context for WebCrypto.
License and Legal Information
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the license file.
Please note: The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
Company Information
Task Venture Capital GmbH
Registered at District Court Bremen HRB 35230 HB, Germany
For any legal inquiries or further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.