RSA Sign = Decrypt When Keys Are Shared (Unrestricted Signing Oracle)
- •
What it is
- •
RSA signing () and RSA decryption () are the exact same mathematical operation — both just raise a value to the private exponent modulo . If a service exposes an unrestricted "sign anything you send me" endpoint using the same key pair also used to encrypt sensitive data, that signing endpoint doubles as a full decryption oracle: submit the ciphertext as the "message to sign," and the returned "signature" is exactly the decrypted plaintext.
- •
- •
When to apply
- •
A service offers both an encryption/ciphertext-generation feature and a general-purpose signing feature under the same RSA key, with no restriction on what can be submitted for signing (no format check, no "don't sign this" blocklist).
- •
- •
Math
- •
— identical operations under the same private key.
- •
- •
Worked example
- •
Fetch a ciphertext (via any "get_secret"-style endpoint using the target key), then submit itself to the "sign" endpoint; the returned value is — exactly the plaintext.
- •
- •
Python
- •
ciphertext = get_secret() # c = m^e mod N plaintext_int = sign(ciphertext) # returns c^d mod N == m
- •
- •
Related
- •
Cards
- •
Why does an unrestricted RSA signing endpoint double as a decryption oracle?
- •
Because signing (m^d mod N) and decryption (c^d mod N) are the exact same operation under the same key — there's no mathematical difference between them.
- •
- •
What's the practical fix for this vulnerability?
- •
Use separate key pairs for signing and encryption (standard RSA best practice), and/or restrict what a signing oracle will sign.
- •
- •