What this page does
RSA runs one way through a key pair: anyone holding the public key can seal something only the private half opens. That is what lets you receive a secret from somebody you have never exchanged one with.
hello → a3f1…c92b — one 256-byte block from a 2048-bit key, whether the message was 5 bytes or 190
It is not a bulk cipher: one pass carries one payload smaller than the modulus. So real systems seal an AES-GCM key with RSA-OAEP and seal the message with that key — this page does the first half, the AES tool the second. Everything runs in this tab through your browser's own Web Crypto; nothing you paste is uploaded.
Why OAEP is the only padding here
RSA on its own is a single modular exponentiation, and using it directly is unsafe in ways that have nothing to do with the key size — identical messages produce identical ciphertexts, and small messages under a small exponent can be recovered by taking a cube root. The padding is what fixes that, and it is not optional.
Two paddings exist. RSAES-PKCS1-v1_5 came first and is the one Bleichenbacher broke in 1998: an attacker who can tell a padding error apart from any other error recovers the plaintext, and twenty-five years of variants have followed. RSA-OAEP came second, is provably secure under stronger assumptions, and is what every current recommendation names.
Only RSA-OAEP is offered here, and that is a fact about the platform before it is a preference. RSAES-PKCS1-v1_5 is not in the Web Crypto specification, no browser has ever implemented it, and engines that once did now answer with a deprecation error. Shipping it would mean hand-rolling modular exponentiation and a padding scheme on a page whose whole premise is that it does not hand-roll ciphers.
RSA-OAEP is also randomised, which surprises people: encrypting the same message twice under the same key gives two different blocks. That is correct and necessary — a deterministic ciphertext tells an observer when you sent the same thing twice.
Which key goes in which box
Encrypting takes the public key; decrypting takes the private one. That is the whole rule, and the Key Type toggle exists so a mistake is named rather than turning into a failed operation with no explanation.
Under Decrypt the toggle is fixed at Private and says why. A public key cannot decrypt — this is not a policy but arithmetic: the number that reverses the public exponent is only in the private key.
The other direction is allowed and is a convenience worth having. If the only thing you have to hand is the private key, select Private under Encrypt and the public half is derived from it — the modulus and the public exponent are both already in there.
Every container is read: PEM under any of its four headers, the same bytes as base64 DER, or a JWK. PKCS#1 blocks are included even though Web Crypto cannot import one, because they are wrapped into the container it can before it ever sees them.
Every control on the page
Five settings and two boxes, and one of the settings has only one legal value.
| Control | What it does | Reach for it when |
|---|---|---|
| Encrypt / Decrypt | Which way the operation runs, and therefore which half of the pair it needs. | Encrypt to seal something; Decrypt to open what was sealed for you. |
| Key format | How the pasted key is written — a headered PEM block, one base64 DER line, or a JWK object. | Match whatever you copied. PEM is what a file holds; DER is what an environment variable holds; JWK is what a JOSE library hands you. |
| Key type | Which half is in the box. Fixed at Private under Decrypt, where nothing else can work. | Set it to Private under Encrypt when the private key is all you have; the public half is derived. |
| Padding scheme | How the message is prepared before the modular exponentiation. RSA-OAEP, and only RSA-OAEP. | Never — there is nothing else to pick, and the section above says why. |
| Hash algorithm | The digest RSA-OAEP builds its mask from. It also decides how much room is left for the message. | SHA-256 unless the system on the other side asks for more. Both ends must agree. |
| Key box | Takes the key exactly as pasted, or as an uploaded file. | Always. The block can be surrounded by a shell prompt or blank lines and still be read. |
| Payload box | The plaintext going in, or the ciphertext coming back — with a picker saying how it is written. | Use Hex or Base64 when the payload is bytes rather than text; UTF-8 for a message. |
| Result | The answer, in whichever encoding its own picker names, with the size limit and the failure reported underneath. | Read it, copy it, or download it. |
| Download / Save as bytes | Saves the result as the text on screen, or — after decrypting — as the raw bytes. | Save as bytes whenever the thing you decrypted was a file rather than a message. |
| Reset all | Clears the key, the payload and the result, and drops every imported key from memory. | Before working with somebody else's key, or to clear one off the screen. |
The size limit is the control nobody expects. RSA-OAEP spends two digests and a byte of the modulus on padding, so a 2048-bit key with SHA-256 carries 190 bytes and not one more. The figure is shown under the box before you hit it, and the refusal repeats it with what you actually typed.
Widening the digest narrows the message twice over: SHA-512 under the same 2048-bit key leaves 126 bytes. Under a 1024-bit key it leaves nothing at all — the padding needs 130 bytes inside a 128-byte modulus — and that combination gets its own refusal rather than being reported as a message that was too long.
The Key Type toggle is disabled rather than hidden under Decrypt. A control that vanishes reads as a bug; one that is visibly off with a sentence beside it teaches the rule.
PKCS#1 blocks are accepted even though Web Crypto cannot read one. They are wrapped back into the container it does read first, using the same code the key generator uses to unwrap them — which is checked byte for byte against a separate ASN.1 implementation.
Encrypting the same message twice gives two different results. That is RSA-OAEP working, not the tool being inconsistent.
Checking it against something that is not this page
Three checks, in the order they tend to fail:
- Decrypt it elsewhere.
openssl pkeyutl -decrypt -inkey private.pem -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -in ciphertext.binopens what this page wrote, once the base64 has been decoded to bytes. - Encrypt elsewhere and open it here. The same command with
-encryptand the public key produces a block this page reads — provided the hash matches on both sides, which is the thing that usually does not. - Check the key first, separately. If a key is refused here,
openssl pkey -in key.pem -noout -textwill say whether the block is intact before you go looking for a padding problem.
The digest is the commonest mismatch, because nothing in a ciphertext records which one was used. OpenSSL defaults rsa_oaep_md to SHA-1 when it is not given, which will never match anything this page produces — name it explicitly on both sides.
What people use this for
Wrapping a symmetric key. Generate an AES key, encrypt it here against the recipient's public key, and send the wrapped key alongside the AES-encrypted message. This is what virtually every real system built on RSA is doing.
Checking an integration. When a partner's service will not accept your ciphertext, encrypting the same payload here with the same key and hash tells you whether the problem is your code or your parameters.
Learning where the limits are. Watching five bytes become 256, and a 191-byte message be refused under a 2048-bit key, makes the shape of RSA concrete in a way a paragraph does not.
Frequently asked questions
Web Crypto, in this tab, and no request on this page carries it. There is no server-side step to opt out of — the page has nowhere to send it from, because the key exists only in the tab's memory and is gone when you close it.SHA-256 takes 190 bytes and no more, because RSA-OAEP spends the rest of the modulus on padding. The figure for your key is under the box, and the fix is not a bigger key but a different shape: encrypt a symmetric key with RSA, and the message with that.RSAES-PKCS1-v1_5 is not part of the Web Crypto specification and never has been, and the engines that once offered it now return a deprecation error. It is also the padding Bleichenbacher's attack targets, so its absence costs less than it looks.RSA-OAEP is randomised: it mixes a fresh random seed into every operation. That is deliberate and necessary — a deterministic ciphertext would let an observer tell when you sent the same thing twice. Every one of those different blocks decrypts back to the same message.RSA-OAEP had failed you would have got a refusal instead, so the bytes are genuinely what was sealed — they are just not text in the encoding selected. Switch the result encoding to Hex or Base64, or use Save as bytes if what you decrypted was a file.PEM under any of its four RSA headers, the same bytes as a single base64 DER line, or a JWK. PKCS#1 blocks work even though Web Crypto cannot import one directly — they are wrapped into a container it accepts on the way in. A key generated on the RSA Key Generator page will paste in whichever form you exported it.RSA-OAEP used, so a mismatch is silent until decryption fails — and OpenSSL defaults to SHA-1 when rsa_oaep_md is not given, which never matches anything this page writes. Name the digest explicitly on both sides before looking anywhere else.