Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
# `policy/modulus`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Modulus-length policy gate enforced at every public-API entry point in
`@suaveplan/crypto-rsa`. Combines a default-2048-bit floor (with optional
1024-bit legacy carve-out) and a default-16384-bit ceiling (with optional
oversized opt-in) so consumers cannot accidentally accept dangerously short
keys or get DoS'd by attacker-supplied oversized keys.
The 2048-bit default tracks NIST SP 800-131A Rev. 2's transition from
112-bit to 128-bit security strength; 1024 bits delivers 80-bit strength
which is broken offline and survives only for legacy WebAuthn TPM
endorsement keys (see proposal §Why and CLAUDE.md). The 16384-bit ceiling
matches the largest modulus a service is realistically expected to verify;
beyond that the per-verify modpow cost (cubic in bit length) becomes a
viable DoS vector.
## Features
- `enforceMinBitLength(key, { allowLegacy? })` — strict default 2048-bit floor.
- `enforceMaxBitLength(key, { allowOversize? })` — strict default 16384-bit ceiling.
- Hard sub-1024-bit reject regardless of `allowLegacy`.
- Both throw `CryptoRsaError` with structured `context` for telemetry.
## Usage: Basic Example
```ts
import { enforceMinBitLength } from "@suaveplan/crypto-rsa/policy";
enforceMinBitLength(publicKey); // throws if bitLength < 2048
```
## Usage: Advanced Example
```ts
import {
enforceMaxBitLength,
enforceMinBitLength,
} from "@suaveplan/crypto-rsa/policy";
// WebAuthn TPM legacy path: 1024 bits permitted.
enforceMinBitLength(tpmEndorsementKey, { allowLegacy: true });
// Offline tooling that processes 32 768-bit keys.
enforceMaxBitLength(researchKey, { allowOversize: true });
```
## API Reference
### `enforceMinBitLength(key, options?: { allowLegacy?: boolean }): void`
Throws `CryptoRsaError(CRYPTO_RSA.MODULUS_TOO_SHORT)` with `context: { bitLength, floor }`
when `key.bitLength < floor`. `floor` is `2048` by default, `1024` under
`allowLegacy: true`. Sub-1024-bit keys are always rejected.
### `enforceMaxBitLength(key, options?: { allowOversize?: boolean }): void`
Throws `CryptoRsaError(CRYPTO_RSA.MODULUS_TOO_LARGE)` with `context: { bitLength, ceiling }`
when `key.bitLength > 16384`. `allowOversize: true` short-circuits the check.
## Implementation Notes
The hard sub-1024-bit floor is enforced even when `allowLegacy: true` because
512-bit and 768-bit moduli have been factored on commodity hardware and there
is no realistic legacy use-case that still relies on them.
The ceiling check returns early when `allowOversize: true` rather than scaling
the comparison; this keeps the hot path branch-predictable and the policy
scope obvious to readers.