RSA Sign and Verify with RSA-PSS
After reading this you will understand what an RSA-PSS signature proves, how the sign and verify operations use opposite keys, and how to avoid the mistakes that silently break signature security.
What a signature proves
A digital signature answers two questions at once: did this message come from the holder of a specific private key, and has anyone changed a single byte since it was signed. If either answer is no, verification fails.
Take a plain example. Suppose you publish the string ship it and sign it with your RSA private key. Anyone who has your public key can check the signature. If an attacker rewrites the message to ship it tomorrow, the signature no longer matches, and every honest verifier rejects it. The attacker cannot forge a new signature because that requires the private key, which never leaves your device.
This is the reverse of encryption. When you encrypt, you use the recipient's public key so only their private key can read the message. When you sign, you use your own private key so anyone with your public key can verify. Signing is not secrecy. The message stays in the clear; the signature is proof of origin and integrity.
Where RSA-PSS is used, and when to choose it
RSA signatures sit under a large part of the web. TLS server certificates are signed by a certificate authority so your browser trusts them. Software vendors sign installers so your operating system can refuse tampered binaries. JSON Web Tokens with the RS256 and PS256 algorithms use RSA signatures to prove a token was issued by an authentication server.
Two padding schemes exist. The older one is PKCS#1 v1.5, deterministic and still common in deployed protocols. The modern recommendation, defined in RFC 8017 (PKCS#1 v2.2) and required by many newer profiles, is RSA-PSS: Probabilistic Signature Scheme. PSS adds a random salt and a mask, so signing the same message twice gives two different signatures. This tool uses RSA-PSS.
If you are choosing a new signature algorithm and have no legacy constraint, prefer RSA-PSS over PKCS#1 v1.5. If signature size and speed matter, compare with ECDSA: a P-256 signature is 64 bytes, while a 2048-bit RSA signature is 256 bytes.
The math, one layer at a time
RSA rests on modular exponentiation with a public key (n, e) and a private exponent d, where n is the product of two large primes. The raw private operation on a value y is:
Here y is not the message. It is an encoded representation of the message hash. The corresponding public check raises the signature back up:
Because e and d are inverses modulo \varphi(n), the two operations undo each other. The verifier recomputes the expected encoding from the message and checks that it matches the recovered y.
PSS defines how the message becomes y. The steps, from RFC 8017, are:
- Hash the message: mHash = \text{SHA-256}(M), producing 32 bytes.
- Generate a random salt, typically 32 bytes for SHA-256.
- Form M' = \text{padding} \, \| \, mHash \, \| \, salt and hash it to get H.
- Build a data block DB containing the salt, mask it with a mask generation function seeded by H, and concatenate to form the encoded message EM.
- Interpret EM as the integer y and compute s = y^{d} \bmod n.
The random salt is why PSS is probabilistic. The security argument is tighter than for PKCS#1 v1.5: a forgery of PSS can be reduced to inverting RSA, which is why standards bodies favor it.
A worked example with the demo data
Signing and verifying the default message
The demo signs a short message with a 2048-bit key using RSA-PSS with SHA-256. Load the defaults and press the sign button, then trace what happens.
- The message bytes are hashed with SHA-256. For the message
Hello, RSA-PSS!the hash is 32 bytes, always the same for that exact input. - A fresh 32-byte salt is drawn. This is the reason your signature will differ from the one shown here and from any earlier run.
- PSS encoding builds a 256-byte encoded message, because a 2048-bit modulus is 2048 / 8 = 256 bytes wide.
- The private operation s = y^{d} \bmod n produces the 256-byte signature. Base64 encoded, that is about 344 characters.
- Verification takes the public key, recomputes the hash of the message, undoes the padding from s^{e} \bmod n, and reports valid or invalid.
Sign the same message twice and compare. The two signatures differ in every block, yet both verify against the one public key. That is PSS randomization working as designed.
Now change one character of the message, say to Hello, RSA-PSS?, and verify against the old signature. It fails. The hash changed completely (SHA-256 has an avalanche property, so a one-bit input change flips about half the 256 output bits), and the recovered encoding no longer matches.
Reading the result
Verification is binary. You get valid or invalid, with no in-between. There is no such thing as a signature that is 80 percent correct. Either the recomputed encoding matches to the last byte or it does not.
A valid result tells you three things together: the message is byte-for-byte what was signed, the signer held the private key matching this public key, and the algorithm and hash you verified with are the ones used to sign. An invalid result does not tell you which of those failed. It could be an altered message, a wrong public key, a mismatched hash function, or a corrupted signature.
Common mistakes
The failures below break real systems. None of them produce a visible error until an attacker exploits them.
- Signing without hashing first
- RSA can only sign a number smaller than the modulus. You never feed raw message bytes into the exponentiation. The hash is what gets encoded and signed. PSS handles the hashing, but if you build your own scheme, forgetting it is fatal.
- Mixing up which key does what
- You sign with the private key and verify with the public key. A frequent confusion comes from encryption, where the roles are reversed. If you try to verify with the private key or sign with the public key, the operation is meaningless.
- Trusting a public key you did not authenticate
- A signature only binds a message to a key. It says nothing about who owns that key. If you accept the attacker's public key as authentic, you will happily verify the attacker's forgeries. This is exactly the problem that certificate authorities and a chain of trust exist to solve.
- Reusing PKCS#1 v1.5 verification for PSS signatures
- The two padding schemes are not interchangeable. A PSS signature will not verify under PKCS#1 v1.5 and vice versa. The verifier must know which scheme, hash and salt length were used.
Never treat a valid signature as proof that the message is trustworthy or true. It only proves the message came unchanged from the key holder. If that key holder is malicious or compromised, the signature is still valid.
Related tools
To create the key pair this tool needs, use the RSA Key Pair Generator, which outputs 2048, 3072 or 4096-bit keys in PEM format. If you want confidentiality instead of authenticity, see RSA Encrypt and Decrypt, which uses the public key to encrypt and the private key to decrypt. For smaller and faster signatures on elliptic curves, compare with ECDSA Keys, Sign and Verify.
Frequently asked questions
Why does the signature change every time I sign the same message?
RSA-PSS adds a random salt, usually 32 bytes for SHA-256, before signing. That randomness produces a different 256-byte signature each run for a 2048-bit key. Every one of them verifies against the same public key. Deterministic PKCS#1 v1.5 signatures do not change, which is one reason PSS is preferred.
Can someone forge a signature without my private key?
Not for a properly sized key. Forging an RSA-PSS signature reduces to inverting the RSA function, which means factoring the modulus. Factoring a 2048-bit modulus is beyond any known practical attack. The realistic risks are a stolen private key or a verifier trusting the wrong public key, not the math being broken.
Is a signature the same as encryption?
No. Encryption hides a message so only the private key holder can read it. A signature leaves the message readable and adds proof of origin and integrity that anyone with the public key can check. They use opposite keys and solve opposite problems.
What hash should I use with RSA-PSS?
SHA-256 is the common default and pairs well with 2048 and 3072-bit keys. Use SHA-384 or SHA-512 for larger keys or stricter profiles. The signer and verifier must agree on the same hash, because the hash is part of the encoded value that gets checked.
How big is the signature?
Exactly the width of the modulus: 256 bytes for a 2048-bit key, 384 bytes for 3072-bit, 512 bytes for 4096-bit. The message length does not change the signature length, because only the fixed-size hash is signed.