Files
skills/docs/security-stack/crypto/crypto-browser/src/rsa/rsa.md
2026-05-29 08:20:56 +01:00

5.3 KiB
Raw Blame History

rsa

(no submodules)

Purpose

Provides a high-level rsa namespace object wrapping RSA cryptographic operations from crypto.subtle. Supports three algorithm variants — RSA-PSS, RSA-OAEP, and RSASSA-PKCS1-v1_5 — for signing/verification and asymmetric encryption/decryption. Keys are represented as standard DER byte arrays (SPKI for public keys, PKCS8 for private keys), which are universally portable across platforms and easy to store and transmit.

RSA is provided alongside the elliptic-curve engines for interoperability with legacy systems, PKI infrastructure, and protocols that require RSA (e.g., certain TLS cipher suites, JWT RSA algorithms, legacy JOSE). For new designs, Ed25519 and ECDH-X25519 are preferred.

Features

  • generateKeypair(algorithm, modulusLength?) — generates an RSA keypair; default 2048-bit modulus, configurable up to 4096 bits
  • sign(algorithm, privateKey, message) — RSA-PSS or RSASSA-PKCS1-v1_5 signature generation
  • verify(algorithm, publicKey, signature, message) — RSA signature verification
  • encrypt(publicKey, plaintext) — RSA-OAEP encryption (public-key encryption)
  • decrypt(privateKey, ciphertext) — RSA-OAEP decryption
  • SHA-256 hash used for all operations
  • RSA-PSS uses 32-byte salt length
  • All methods guard with assertWebCryptoAvailable()
  • Typed BrowserCryptoError for all failure paths

Usage: Basic Example

import { rsa } from "@suaveplan/crypto-browser/rsa/rsa";

// Generate and use RSA-PSS for signing
const { publicKey, privateKey } = await rsa.generateKeypair("RSA-PSS");
const message = new TextEncoder().encode("document to sign");

const signature = await rsa.sign("RSA-PSS", privateKey, message);
const valid = await rsa.verify("RSA-PSS", publicKey, signature, message);
console.log(valid); // true

Usage: Advanced Example

import { rsa, type RsaAlgorithm } from "@suaveplan/crypto-browser/rsa/rsa";
import { BrowserCryptoError } from "@suaveplan/crypto-browser/errors";

// RSA-OAEP for encrypting a small payload (e.g., a symmetric key)
async function wrapAesKey(
  recipientPublicKey: Uint8Array,
  aesKey: Uint8Array  // must be <= ~190 bytes for RSA-2048
): Promise<Uint8Array> {
  try {
    return await rsa.encrypt(recipientPublicKey, aesKey);
  } catch (err) {
    if (err instanceof BrowserCryptoError) {
      console.error(`Crypto failure: ${err.code}`);
    }
    throw err;
  }
}

async function unwrapAesKey(
  recipientPrivateKey: Uint8Array,
  wrappedKey: Uint8Array
): Promise<Uint8Array> {
  return await rsa.decrypt(recipientPrivateKey, wrappedKey);
}

// 4096-bit keypair for higher-security contexts
const { publicKey, privateKey } = await rsa.generateKeypair("RSA-OAEP", 4096);

API Reference

rsa.generateKeypair(algorithm, modulusLength?): Promise<{ publicKey, privateKey }>

Generates an RSA keypair.

Parameter Type Default Description
algorithm RsaAlgorithm — "RSA-PSS" | "RSA-OAEP" | "RSASSA-PKCS1-v1_5"
modulusLength number 2048 Key bit length (2048 or 4096 recommended)

Returns: Promise<{ publicKey: Uint8Array; privateKey: Uint8Array }> — SPKI/PKCS8 DER bytes.

Throws: BrowserCryptoError — BROWSER_CRYPTO.KEY.GENERATION_FAILED.


rsa.sign(algorithm, privateKey, message): Promise<Uint8Array>

Signs a message. Use with "RSA-PSS" or "RSASSA-PKCS1-v1_5".

Parameter Type Description
algorithm RsaAlgorithm Must match keypair generation algorithm
privateKey Uint8Array PKCS8 DER private key
message Uint8Array Message to sign

Returns: Promise<Uint8Array> — signature bytes.

Throws: BrowserCryptoError — BROWSER_CRYPTO.OPERATION.FAILED.


rsa.verify(algorithm, publicKey, signature, message): Promise<boolean>

Parameter Type Description
algorithm RsaAlgorithm Must match signing algorithm
publicKey Uint8Array SPKI DER public key
signature Uint8Array Signature bytes
message Uint8Array Original message

Returns: Promise<boolean>.


rsa.encrypt(publicKey, plaintext): Promise<Uint8Array>

RSA-OAEP encryption. For RSA-2048, plaintext must be ≤ 190 bytes (2048-bit modulus minus OAEP overhead).


rsa.decrypt(privateKey, ciphertext): Promise<Uint8Array>

RSA-OAEP decryption.


type RsaAlgorithm

"RSA-PSS" | "RSA-OAEP" | "RSASSA-PKCS1-v1_5"

Implementation Notes

All RSA operations use SHA-256 as the hash algorithm, which is the most widely supported and appropriate choice for 2048- and 4096-bit RSA. RSA-PSS uses a 32-byte (256-bit) salt, matching the hash output length, which is the PKCS#1v2.2 recommendation.

The encrypt() and decrypt() methods are hardcoded to RSA-OAEP — only RSA-OAEP provides semantic security for asymmetric encryption. RSA-PSS and RSASSA-PKCS1-v1_5 are signing-only algorithms and cannot be used with encrypt/decrypt.

Key generation for RSA-2048 typically takes 50–200 ms in crypto.subtle; RSA-4096 can take 500–2000 ms. This is significantly slower than elliptic-curve key generation (< 5 ms). All operations use await and do not block the main thread.