RSA Encrypt / Decrypt
Encrypt a short message with an RSA public key and decrypt it with the private key — RSA-OAEP, entirely on this device.
SHA-256 is the default and both sides must agree on it. SHA-1 is here for interop with systems that already use it. PKCS#1 v1.5 encryption padding is not offered because Web Crypto does not implement it.
- No key loaded yet
The result appears here when you run this direction.
No key handy? Generate a throwaway pair
Generated in this tab for trying this page out. It is never stored and never leaves the browser — use a key you manage for anything real.
The two PEM blocks appear here after you press Generate.
The two PEM blocks appear here after you press Generate.
Keys, messages and ciphertext are handled in this tab only. This page makes no network request of any kind — no fetch, no beacon, no image ping — and loads no third-party code.
Nothing on this page is remembered between visits: there is no saved key, no saved message and no saved ciphertext, because there is no storage key for them to go in.
A private key you paste is read in this tab and nothing else: it is not stored, not remembered between visits, and there is no field in a shared link that could carry it.
Press Encrypt twice on the same message and the two ciphertexts differ. OAEP is randomised, and both still decrypt to the same bytes.
A shared link carries the five settings above — direction, hash, demo key size and the two encodings. There is no field in it for a key, a message or a ciphertext.
Switching direction keeps everything on the page: the key pane now wants the other half of the pair.
RSA does not encrypt files. Real systems encrypt a random AES key with RSA and the file with that AES key. Encrypt the data half with AES
The same operation on the command line:
openssl pkeyutl -encrypt -pubin -inkey public.pem -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -in msg.txt -out msg.enc
Press ? for shortcuts
What you pasted looks like key material. It is not stored anywhere, and it cannot travel in a shared link.
Do it offline:$ openssl pkeyutl -encrypt -pubin -inkey public.pem -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -in msg.txt -out msg.enc
How to use it
- Choose Encrypt or Decrypt. Encrypt takes the public key, Decrypt takes the private half, and pasting the wrong one is named rather than silently swapped.
- Paste the key: an SPKI or PKCS#8 PEM block, a certificate, or a JWK. The badge names what was detected, and Generate a demo pair mints one.
- Type or paste the message. The counter reads bytes, and the chip beside it prints the exact ceiling for the key and hash you have loaded.
- Press Encrypt, or ⌘/Ctrl + Enter, then copy the block as Base64 or hex. Decrypt reverses it with the private key and the same hash.
RSA-OAEP encrypts one short message at a time: paste an RSA public key, type the message, and the ciphertext comes back exactly as long as the modulus. Paste the private key instead and the Decrypt tab reverses it. The ceiling is small and it is arithmetic — a 2048-bit key with SHA-256 carries 190 bytes. Nothing you paste leaves this device.
Examples
meet me at the usual placeDtdtK1tFH9pbLS9ym2hAL6lZ9saLneOGdFMIvnlFvLZyxDM3v1e5pD1Nm14/7oKX3okY5K09jqQfJFAZCOljUcnXX1Oah3hLqnbsFTDpSRkjLXFyn2TnUe5aLsYOev7HN1r2I/VYOctSEW7xMy0wzNWYJ7hOLACkmuiTFKb2rOJeOO5z8852JzM7ToqN+h6wwk7k1NHEr8pP8wH4PEw862PfoYOnumbatveRmgwUdoGsbM76ghMoN523sTOODg8hxg4XPwae2c6FgNikXKLflbJCBWKT+tIbK2deUGGurVgfL0f+qwHwmRPTngV/t1C8+UBP0Vrk/FSXfJzmq1UAvQ==Twenty-six plaintext bytes, 256 ciphertext bytes — the block is the modulus size whatever the message weighs. Run it again and the Base64 is different, which is the padding doing its job.
Sa9AwZsnqibWvX+AyIP2syj0tQfgsTaJMWpU63+KfCEGBe/jKsqNg+OPWqqcvz3FAI10A+VFIy2vIaRQ8hY7H9D2rW04j+0eZ82CX2HoFelJbQjNWpYgQuolnG1JhH/QO8Y5hG3J0HyUteudZVRn+l9Kkm4/RTwEUS0wt2pbw37UE+/0SeEBAZ/+qRS8DyN9SadyM9rDGVOw0n0SlFGPGjjZ7kyg7pe+Pk/9DLvc83CXtCvlQrcgv80Y0vOZ3P5LcSE8vhVxFK54eFiPZht1E62zGFDDP7VLkOMxp6awb0QHMB0dwGjPmkrz/M2YTBbKEHDotRdxPCYmB5nxikx5KA==hello, rsaopenssl produced this block, not this page, and it opens here unchanged. The flag that makes it work is rsa_oaep_md — leave it off and openssl quietly chooses SHA-1 instead.
An RSA-2048 key with SHA-256 stops at 190 bytes flat, and this sentence is exactly one byte past that line, so the page refuses it by arithmetic before Web Crypto is ever asked to encrypt it.This plaintext is 191 bytes. A 2048-bit RSA key with SHA-256 carries at most 190 bytes: k − 2·hLen − 2 = 256 − 2·32 − 2. Encrypt a symmetric key with RSA and the data itself with AES.Drop the final character and the same key encrypts it. The refusal prints the sum it comes from, so the number is checkable rather than asserted.
XqtwWb1dHS7Zhh7SIVlYiNYoQmKsb60SPfGkCyV/nHD4jpehbXbfmZlOtFCteMSzOLhwLspRfy9fYgVgGkNwmoUwTkVrTuyRO+tB4AE1BRwdRPIeyEg1q1GgQiULzpXBHKfUEdFmHe1r9uAcXn7ScjDb87Y9RMFFKKs4kldVIPFmvpVVG03itJMq7eYTBHorH5IcmxZIfUolMmnsmPxcelLJdL6YZ5k1iem4da6YiDYlp6yptiAtVrkEFXcXe6FH6FUa9h1keFcJkB/zUankX3iT2yfBiCkcxCjO8oDYbTic1wN+lpS7oPD2G5Q13UPDKvJUvxumYap3wJ+qb2v3hA==Decrypt failed: wrong key or mismatched OAEP hash (SHA-1 vs SHA-256). The platform cannot tell these apart.Same key, right length, hash set to SHA-256 while the block was made with SHA-1. Web Crypto answers with a bare OperationError; openssl calls it an oaep decoding error.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
RSA does not encrypt files
A few hundred bytes is the whole budget, so payloads are never encrypted with RSA directly. Encrypt a random AES key here, then the data with that key on the AES encryption page — the pairing TLS, JWE and age use.
The ceiling is a subtraction, not a policy
RFC 8017 §7.1 gives it as k − 2·hLen − 2, where k is the modulus in bytes. That is 190 bytes at 2048 bits with SHA-256, 318 at 3072 and 446 at 4096. SHA-1 is shorter, so each row gains 24 bytes.
SHA-1 is here for legacy interop
Web Crypto implements OAEP with SHA-1 natively, and a lot of deployed software still defaults to it, so the option exists to open what those systems produce. It is not a recommendation, and the page says so.
PKCS#1 v1.5 encryption padding is a platform fact
Web Crypto offers exactly one RSA encryption scheme, and it is OAEP. There is no switch here for the older v1.5 padding because no browser exposes one; if the far side needs it, use openssl.
The same message twice gives two different blocks
OAEP mixes fresh random bytes into every operation, so encrypting one message repeatedly produces ciphertext that never matches. Comparing two blocks tells you nothing; decrypting them both returns the same message.
A certificate can stand in for the public key
Paste a certificate and the public key is read straight out of it, with a note saying so. Nothing about the certificate is checked here — not its dates, not its chain, not revocation — none of that changes the key.
Common errors
This is a PKCS#1 block (-----BEGIN RSA PRIVATE KEY-----). Web Crypto imports SPKI ("PUBLIC KEY") and PKCS#8 ("PRIVATE KEY") only, which is a platform limit, not a policy. Convert it first: openssl pkcs8 -topk8 -nocrypt -in key.pem -out pkcs8.pem- The header openssl genrsa still writes by default. One conversion command later the same key imports; the public-side twin prints an openssl rsa line instead.
This is an encrypted PKCS#8 key (-----BEGIN ENCRYPTED PRIVATE KEY-----). Web Crypto has no importer for it and this tool never asks for your passphrase. Decrypt it locally first: openssl pkcs8 -in k.pem -out plain.pem- A passphrase box is the one thing this page will not grow. Strip the encryption where the passphrase already lives, then paste the plain block.
This is a public key, and decrypting needs the private key. Switch to Encrypt to use it, or paste the matching private key here.- The two halves look alike in a terminal and the mode is easy to leave behind. Nothing switches on your behalf, because that would discard the other pane.
This is an EC (elliptic-curve) key, not an RSA key. RSA-OAEP needs an RSA key — for elliptic-curve keys the browser offers signing and key agreement, never this kind of direct encryption.- P-256 and Ed25519 keys are refused by name rather than by relaying an opaque import error. Curve keys reach the same goal through key agreement instead.
This ciphertext is 5 bytes. A 2048-bit RSA key produces exactly 256 bytes per block, so these bytes were not produced by this key — check the encoding, and check that nothing was truncated on the way here.- Length is checked before the platform is asked, so a truncated paste or a hex block read as Base64 gets a specific answer, not the generic failure.
The Web Crypto API (crypto.subtle) is unavailable in this context — RSA-OAEP needs a secure (HTTPS) page. Do it with the CLI instead: openssl pkeyutl -encrypt -pubin -inkey public.pem -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -in msg.txt -out msg.enc- Browsers withhold crypto.subtle outside a secure context, so on plain http away from localhost there is nothing to call. The refusal hands over the command line instead.
FAQ
Will this open a block that openssl produced?
Yes, when both sides agree on the hash. The test suite decrypts blocks minted by LibreSSL 3.3.6 with pkeyutl and gets the original bytes back. The flag that matters is -pkeyopt rsa_oaep_md:sha256 — without it openssl pads with SHA-1 silently, and the result fails here with the mismatch message.
Where does the private key go after I paste it?
Into memory for as long as the tab is open, and nowhere else. It is shown masked until you press reveal, it is never written to storage, and a share link carries only the mode, hash, key size and two encoding choices — the state has no field a key could sit in.
Can this page sign a message, or read an encrypted mail file?
Neither. Signing and verifying are a different RSA operation and are not built here. OpenPGP messages and keyrings are a separate format with their own containers, which this page does not parse: it reads PEM keys, JWK keys and RSA-OAEP blocks, and that is the whole surface.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Run the current mode — encrypt, or decrypt
- ⌘/Ctrl + Shift + C
- Copy the output pane of the current direction
- ? or ⌘/Ctrl + /
- Show the keyboard shortcut help