3.4 KiB
3.4 KiB
verify/pss
Purpose
RSASSA-PSS signature verification per RFC 8017 §8.1.2. Recovers the
encoded message via s^e mod n, then runs the EMSA-PSS verifier against
the digest of the message under the given (hash, mgfHash, saltLength)
triple.
Features
- RFC 8017 §8.1.2 conformant
- Uses
emsaPssVerifyfor the structural check (which usesconstantTimeEqualfor the salt+hash compare) - Returns
falseon rejection; throws only on signature length mismatch saltLengthdefaults tohashOutputLength(hash)mgfHashdefaults tohash- Modulus-length policy gates run on every call
- Records
crypto_rsa.verify_duration_ms{scheme="pss",hash,engine}and outcome counter on every call
Usage: Basic Example
import { rsaVerifyPss } from "@suaveplan/crypto-rsa/verify/pss";
import { rsaSignPss } from "@suaveplan/crypto-rsa/sign/pss";
const message = new TextEncoder().encode("hello");
const sig = rsaSignPss(privateKey, message, { hash: "SHA-256" });
console.log(rsaVerifyPss(publicKey, message, sig, { hash: "SHA-256" })); // true
Usage: Advanced Example
import { rsaVerifyPss } from "@suaveplan/crypto-rsa/verify/pss";
import { rsaSignPss } from "@suaveplan/crypto-rsa/sign/pss";
// Custom saltLength: must match the value used by the signer.
const sig = rsaSignPss(privateKey, message, { hash: "SHA-256", saltLength: 16 });
console.log(rsaVerifyPss(publicKey, message, sig, { hash: "SHA-256", saltLength: 16 })); // true
console.log(rsaVerifyPss(publicKey, message, sig, { hash: "SHA-256", saltLength: 32 })); // false
// mgfHash distinct from hash.
const xSig = rsaSignPss(privateKey, message, {
hash: "SHA-256",
mgfHash: "SHA-1",
});
console.log(
rsaVerifyPss(publicKey, message, xSig, {
hash: "SHA-256",
mgfHash: "SHA-1",
})
); // true
API Reference
rsaVerifyPss(key, message, signature, options): boolean
key: RsaPublicKey | RsaPrivateKeymessage: Uint8Arraysignature: Uint8Array— must be exactlybyteLength(n)longoptions.hash: RsaHashAlgorithmoptions.saltLength?: number— defaults tohashOutputLength(hash)options.mgfHash?: RsaHashAlgorithm— defaults tooptions.hashoptions.allowLegacy?: booleanoptions.allowOversize?: boolean- returns
trueon valid,falseon verify-level rejection - throws
CryptoRsaError(CRYPTO_RSA.INVALID_SIGNATURE)on signature length mismatch - throws
CryptoRsaError(CRYPTO_RSA.MODULUS_TOO_SHORT)/MODULUS_TOO_LARGE/UNSUPPORTED_HASH
Implementation Notes
s = os2ip(signature)is checked againsts < nbefore the modular exponentiation; signatures withs >= nare rejected withfalse.- The encoded message produced by
i2osp(s^e mod n, emLen)has lengthemLen = ceil((modulusBits - 1) / 8). This is one byte shorter than the signature itself whenmodulusBitsis a multiple of 8 — the high-order zero pad is stripped here and the leftmost-bit clearance rule inemsaPssVerifyenforces that the original encoding had the expected zero in that position. - The constant-time guarantee for the final salt+hash compare is
delivered by
emsaPssVerify's use ofconstantTimeEqual. The earlier structural checks (length mismatch,s >= n) are guarded by fast-fail paths that do NOT leak the secret-derived signal — they test only public inputs. - The
verify_duration_mshistogram is recorded on every code path (success, rejection, structural error).