01 · Problem
What is it for?
Integrity verification and private-key confidentiality are different operations with different algorithms.
02 · Mental model
How should you think about it?
Sign a defined byte representation with a private key; verify it with the matching public key.
Signs JSON envelopes with RSA-SHA256 and encrypts key exports using AES-GCM. Keys are local to the signer. Production trust distribution, canonical serialization and rotation policy need an application design.
03 · Control flow
What happens in which order?
- Generate an RSA key pair.
- Construct a signature header.
- Serialize header and payload together.
- Sign with the private key.
- Reconstruct the same bytes and verify.
04 · Building blocks
The important contracts
Signature.signData / verifySignatureCreate and verify a JSON signature envelope.KeyPairEncryptionEncrypt exported private keys using scrypt and AES-256-GCM.PayloadSignerSign and verify exact serialized bytes.05 · Build it yourself
Implement a small core
Start with this small independent implementation, then use the steps below to make its contract explicit.
- Generate an RSA key pair.
- Construct a signature header.
- Serialize header and payload together.
- Sign with the private key.
- Reconstruct the same bytes and verify.
async function sign(payload: unknown, privateKey: CryptoKey) {
const bytes = new TextEncoder().encode(canonicalJson(payload));
const signature = await crypto.subtle.sign(
{ name: "RSA-PSS", saltLength: 32 },
privateKey,
bytes,
);
return new Uint8Array(signature);
}
async function verify(payload: unknown, value: BufferSource, publicKey: CryptoKey) {
const bytes = new TextEncoder().encode(canonicalJson(payload));
return crypto.subtle.verify({ name: "RSA-PSS", saltLength: 32 }, publicKey, value, bytes);
}06 · Verify
What should you test?
- Verify a valid signature and reject a modified payload.
- Test unknown key IDs and altered headers.
- Round-trip encrypted keys and reject wrong passwords or authentication tags.
Try it yourself
Turn the first verification claim into a failing test, implement the smallest fix, then add a boundary case.
Verify a valid signature and reject a modified payload.
Compare your approach
Your check should fail when the stated invariant is deliberately broken, and pass again after the fix. Keep setup deterministic and assert an observable result.
07 · Limits
Trade-offs and failure modes
- JSON serialization order is part of this envelope contract.
- RSA-OAEP is encryption, not a signature algorithm.
- Production key rotation and trust distribution require an explicit policy.
Keys are local to the signer. Production trust distribution, canonical serialization and rotation policy need an application design.
08 · Keep exploring
Source code and related ideas
yarn tsx packages/signature/examples/basic.ts