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

2.7 KiB

handle/software

Purpose

Reference RsaKeyHandleProvider wrapping in-memory RsaPrivateKey values. Implements the same interface as a real HSM bridge but with zero hardware dependency, so consumers can develop and test handle-based code paths without an HSM. Production workloads typically replace this with their own provider (PKCS#11, AWS KMS, Apple Keychain via @suaveplan/macos-keychain, etc.).

Features

  • Implements every RsaKeyHandleProvider method
  • Stores keys in a process-local Map<string, RsaPrivateKey> keyed by handle id
  • Sign / decrypt route through nobleEngine so semantics match the rest of the package exactly
  • register(id, key) returns the matching RsaKeyHandle for ergonomic test setups

Usage: Basic Example

import {
    registerKeyHandleProvider,
    signWithHandle,
} from "@suaveplan/crypto-rsa/handle";
import { SoftwareRsaKeyHandleProvider } from "@suaveplan/crypto-rsa/handle";

const provider = new SoftwareRsaKeyHandleProvider();
registerKeyHandleProvider(provider);
const handle = provider.register("test-key", privateKey);
const sig = await signWithHandle(handle, message, {
    scheme: "pkcs1v15",
    hash: "SHA-256",
});

Usage: Advanced Example

Use the software provider to drive integration tests that exercise the handle-based code path of a downstream consumer (e.g. a JWS signer that accepts RsaKeyHandle instead of an in-memory key):

import { SoftwareRsaKeyHandleProvider } from "@suaveplan/crypto-rsa/handle";
import { registerKeyHandleProvider } from "@suaveplan/crypto-rsa/handle";

const provider = new SoftwareRsaKeyHandleProvider();
registerKeyHandleProvider(provider);
const handle = provider.register("k1", testKey);

// Downstream consumer uses the handle exactly as it would an HSM key.
const jws = await jwsSigner.sign(payload, handle);

API Reference

class SoftwareRsaKeyHandleProvider

  • name: "software" (readonly)
  • register(id: string, key: RsaPrivateKey): RsaKeyHandle
  • resolve(handle): Promise<RsaPrivateKey>
  • sign(handle, message, options): Promise<Uint8Array>
  • decrypt(handle, ciphertext, options): Promise<Uint8Array>

Implementation Notes

  • The provider is class-based (vs the module-singleton style of nobleEngine) so consumers can spin up multiple instances for parallel-test isolation. Each instance has its own internal Map.
  • Sign/decrypt delegate to nobleEngine directly — this provider is a pure JS reference; HSM-backed providers replace these methods with the appropriate crypto.subtle / PKCS#11 / KMS API calls.
  • The "handle id missing" failure throws a plain Error (NOT a CryptoRsaError) because the caller is the registry layer; the registry maps it to a typed error before reaching application code.