3.6 KiB
3.6 KiB
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 — throwsCRYPTO_RSA.UNSUPPORTED_HASHon unknown algorithmemsaPkcs1v15Encode(message, emLen, hash)— RFC 8017 §9.2 conformant encoder- Detects modulus-too-short conditions (
emLen < tLen + 11) and throwsCRYPTO_RSA.INVALID_KEY - Returns a fresh
Uint8Arrayof length exactlyemLen
Usage: Basic Example
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.
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 digestedemLen: number— the target encoded-message length, equal tobyteLength(n)hash: RsaHashAlgorithm—"SHA-1" | "SHA-256" | "SHA-384" | "SHA-512"- returns
Uint8Arrayof length exactlyemLen - throws
CryptoRsaError(CRYPTO_RSA.INVALID_KEY)whenemLen < tLen + 11(modulus too short for the chosen hash) - throws
CryptoRsaError(CRYPTO_RSA.UNSUPPORTED_HASH)on unknown algorithm
digestInfoPrefix(hash): Readonly<Uint8Array>
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, wherePSis at least 8 bytes of0xff(per RFC 8017 §9.2 step 3). ThetLen + 11floor encodes the 2-byte header (0x00 || 0x01), the 1-byte separator (0x00), and the 8-byte minimum forPS. - 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
emLenparameter is supplied by the caller (=byteLength(n)for RSASSA-PKCS1-v1_5). This module does not computeemLenfrom a key; that responsibility belongs to the higher-level signature scheme. - Encoding is deterministic — the same
(message, emLen, hash)triple always produces the sameEMbytes. - Hash dispatch goes through
digestWithfrommgf1.ts, so SHA-2 flows through@suaveplan/crypto-hashand SHA-1 through Noble.