# emsa-pkcs1-v1\_5 ## Purpose Implements EMSA-PKCS1-v1\_5-ENCODE from RFC 8017 §9.2 — the encoding method underlying RSASSA-PKCS1-v1\_5 signatures. This module also pins the four DigestInfo prefix byte sequences from §9.2 note 1 as named constants so consumers and tests can audit the bytes against the RFC. ## Features - Hard-coded `DIGEST_INFO_PREFIX_*` constants for SHA-1, SHA-256, SHA-384, SHA-512 - `digestInfoPrefix(hash)` lookup — throws `CRYPTO_RSA.UNSUPPORTED_HASH` on unknown algorithm - `emsaPkcs1v15Encode(message, emLen, hash)` — RFC 8017 §9.2 conformant encoder - Detects modulus-too-short conditions (`emLen < tLen + 11`) and throws `CRYPTO_RSA.INVALID_KEY` - Returns a fresh `Uint8Array` of length exactly `emLen` ## Usage: Basic Example ```ts import { emsaPkcs1v15Encode } from "@suaveplan/crypto-rsa/encoding/emsa-pkcs1-v1_5"; const message = new TextEncoder().encode("hello"); const em = emsaPkcs1v15Encode(message, 256, "SHA-256"); console.log(em.length); // 256 console.log(em[0], em[1]); // 0x00, 0x01 ``` ## Usage: Advanced Example The encoded message is the input to the RSA private-key operation in `rsaSignPkcs1v15`. To verify a signature, the same encoder is run on the candidate message and the result is constant-time compared against the public-key recovery of the signature. ```ts import { emsaPkcs1v15Encode, digestInfoPrefix } from "@suaveplan/crypto-rsa/encoding/emsa-pkcs1-v1_5"; import { toHex } from "@suaveplan/crypto-utils"; const prefix = digestInfoPrefix("SHA-256"); console.log(toHex(prefix as Uint8Array)); // 3031300d060960864801650304020105000420 const em1 = emsaPkcs1v15Encode(new Uint8Array([1, 2, 3]), 256, "SHA-256"); const em2 = emsaPkcs1v15Encode(new Uint8Array([1, 2, 3]), 256, "SHA-256"); // em1 and em2 are byte-identical (encoding is deterministic) ``` ## API Reference ### `emsaPkcs1v15Encode(message, emLen, hash): Uint8Array` - `message: Uint8Array` — the bytes that will be digested - `emLen: number` — the target encoded-message length, equal to `byteLength(n)` - `hash: RsaHashAlgorithm` — `"SHA-1" | "SHA-256" | "SHA-384" | "SHA-512"` - **returns** `Uint8Array` of length exactly `emLen` - **throws** `CryptoRsaError(CRYPTO_RSA.INVALID_KEY)` when `emLen < tLen + 11` (modulus too short for the chosen hash) - **throws** `CryptoRsaError(CRYPTO_RSA.UNSUPPORTED_HASH)` on unknown algorithm ### `digestInfoPrefix(hash): Readonly` Returns the immutable RFC 8017 §9.2 note 1 DigestInfo prefix for `hash`. ### `DIGEST_INFO_PREFIX_SHA1` / `_SHA256` / `_SHA384` / `_SHA512` Read-only `Uint8Array` constants holding the byte-exact DigestInfo prefix sequences from RFC 8017 §9.2 note 1. ## Implementation Notes - The encoded message structure is `0x00 || 0x01 || PS || 0x00 || T`, where `PS` is at least 8 bytes of `0xff` (per RFC 8017 §9.2 step 3). The `tLen + 11` floor encodes the 2-byte header (`0x00 || 0x01`), the 1-byte separator (`0x00`), and the 8-byte minimum for `PS`. - The DigestInfo prefix bytes are pinned as literal byte arrays — not ASN.1 encoder calls — so a single misbyte in the RFC table would be caught by the bytewise prefix tests against the RFC reference. - The `emLen` parameter is supplied by the caller (= `byteLength(n)` for RSASSA-PKCS1-v1\_5). This module does not compute `emLen` from a key; that responsibility belongs to the higher-level signature scheme. - Encoding is deterministic — the same `(message, emLen, hash)` triple always produces the same `EM` bytes. - Hash dispatch goes through `digestWith` from `mgf1.ts`, so SHA-2 flows through `@suaveplan/crypto-hash` and SHA-1 through Noble.