Skip to content
Crypto2026-06-237 min read

Online RSA Encryption/Decryption: Asymmetric Crypto and Digital Signatures

What Is RSA Encryption

RSA is the most widely used asymmetric encryption algorithm, invented by Rivest, Shamir, and Adleman in 1977. It uses a key pair: public key for encryption, private key for decryption.

How RSA Works

Key Pair Generation:
  Choose two large primes p, q
  Compute n = p × q
  Compute φ(n) = (p-1)(q-1)
  Choose e such that gcd(e, φ(n)) = 1
  Compute d such that e×d ≡ 1 (mod φ(n))

Public Key: (e, n)   ← Can be shared
Private Key: (d, n)   ← Must be kept secret

Encrypt: C = M^e mod n
Decrypt: M = C^d mod n

RSA vs AES

FeatureRSA (Asymmetric)AES (Symmetric)
Key countPair (public + private)Single shared key
SpeedSlow (1000x slower)Fast
Data sizeLimited (< key length)Unlimited
Typical useKey exchange, signaturesData encryption
Key length2048-4096 bits128-256 bits

Why You Need RSA Encryption

  1. Secure communication: Key exchange in HTTPS/TLS handshakes
  2. Digital signatures: Verify data integrity and source
  3. API authentication: JWT RS256 signature verification
  4. Key exchange: Securely transmit AES session keys
  5. Code signing: Verify software publisher identity

How to Use an Online Tool

Using ToolVault's RSA Encryption/Decryption Tool:

  1. Generate RSA key pair (2048/4096 bits)
  2. Encrypt data with public key
  3. Decrypt data with private key
  4. Create and verify digital signatures
  5. Import/export in PEM format

RSA in Code

JavaScript: Web Crypto API

// Generate RSA key pair
async function generateRSAKeyPair() {
  const keyPair = await crypto.subtle.generateKey(
    {
      name: 'RSA-OAEP',
      modulusLength: 2048,
      publicExponent: new Uint8Array([1, 0, 1]),
      hash: 'SHA-256',
    },
    true,
    ['encrypt', 'decrypt']
  );
  return keyPair;
}

// Encrypt
async function rsaEncrypt(publicKey, data) {
  const encoder = new TextEncoder();
  const encrypted = await crypto.subtle.encrypt(
    { name: 'RSA-OAEP' },
    publicKey,
    encoder.encode(data)
  );
  return new Uint8Array(encrypted);
}

// Decrypt
async function rsaDecrypt(privateKey, encryptedData) {
  const decrypted = await crypto.subtle.decrypt(
    { name: 'RSA-OAEP' },
    privateKey,
    encryptedData
  );
  return new TextDecoder().decode(decrypted);
}

Python: Using cryptography Library

from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes

# Generate key pair
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
)
public_key = private_key.public_key()

# Encrypt
ciphertext = public_key.encrypt(
    b"Hello, RSA!",
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

# Decrypt
plaintext = private_key.decrypt(
    ciphertext,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

Padding is not optional detail — it is the security

Textbook RSA (exponentiate the message, done) is deterministically insecure: the same plaintext always yields the same ciphertext, and short messages fall to direct root extraction. Every real deployment uses a padding scheme, and the choice is a compatibility minefield. PKCS#1 v1.5 is the legacy default that still works everywhere but is vulnerable to Bleichenbacher-style padding-oracle attacks when the decryptor leaks failure details. OAEP (OAEPwithSHA-256andMGF1) is the modern answer — but Java's default OAEP parameters and OpenSSL's differ in MGF1 digest, producing ciphertexts each side cannot open. Rule: encrypt with a library default, decrypt with a different stack, fail — check the OAEP parameter bytes before blaming the key.

Key sizes: how we got to 2048 (and why 4096 is usually wrong)

Factoring records pushed the floor: 512-bit fell in 1999, 768-bit in 2009, and 1024-bit is within reach of nation-state budgets. 2048-bit offers ~112 bits of security and satisfies every current CA and standard. Jumping to 4096 bits quadruples decryption cost for about 20 extra bits — instead, switch algorithms: for new hybrid designs, EC (P-256) or SM2 delivers 128-bit security at a fraction of the key size and compute. Use 4096 only where a counterparty standard freezes you into RSA.

The hybrid reality

RSA encrypts at most one block (190-245 bytes at 2048-bit, depending on padding) — nobody encrypts a document with RSA directly. Every real system is an envelope: generate a random AES/SM4 session key, encrypt the payload with it, encrypt the session key with RSA. TLS, PGP, and our hybrid tools all follow this shape. Debugging "RSA payload too long" errors usually means someone skipped the envelope step.

PEM formats: SPKI vs PKCS#8 vs PKCS#1

The Generate tab emits PEM text blocks, but PEM is just an envelope — the DER structure inside decides whether other software can open it:

HeaderInner structureHoldsCompatibility
BEGIN PUBLIC KEYSPKI (X.509 SubjectPublicKeyInfo)Public keyUniversal
BEGIN RSA PUBLIC KEYPKCS#1 RSAPublicKeyPublic keyLegacy; Web Crypto rejects it
BEGIN PRIVATE KEYPKCS#8 PrivateKeyInfoPrivate keyUniversal
BEGIN RSA PRIVATE KEYPKCS#1 RSAPrivateKeyPrivate keyLegacy; Web Crypto rejects it
BEGIN ENCRYPTED PRIVATE KEYPKCS#8 wrapped with a passphraseEncrypted private keyDecrypt first

Conversion is a one-liner on the OpenSSL side: openssl pkcs8 -topk8 -nocrypt -in rsa.pem -out pkcs8.pem rewrites a PKCS#1 private key as PKCS#8. Keys exported from Java or Python as BEGIN PUBLIC KEY / BEGIN PRIVATE KEY paste straight into the tool — stray whitespace and CRLF line endings are stripped on import.

Troubleshooting common failures

"DataError" on decrypt (browser): the ciphertext was not produced by the matching public key, or it got truncated or altered. A single lost base64 character triggers this — check your copy/paste first.

Plaintext too long: with OAEP/SHA-256 the single-block limit is key bytes − 66. 2048-bit holds 190 bytes of UTF-8 (~63 CJK characters); 4096-bit holds 446. The tool's Encrypt tab now shows a live byte counter against the limit and disables the button past it — that is the hint to switch to hybrid encryption, not a bug.

"BEGIN RSA PRIVATE KEY" won't import: that is a PKCS#1 private key; Web Crypto only accepts PKCS#8 (BEGIN PRIVATE KEY). Convert with openssl pkcs8 -topk8 -nocrypt -in rsa.pem -out pkcs8.pem.

Cross-language mismatch (Java encrypts, browser can't decrypt): nine times out of ten the OAEP parameters differ. Java's RSA/ECB/OAEPWithSHA-256AndMGF1Padding still defaults MGF1 to SHA-1, while Web Crypto's hash: 'SHA-256' locks MGF1 to SHA-256 as well. On the Java side, pass new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT) explicitly.

FAQ

How to Choose RSA Key Length?

  • 2048 bits: Current standard, sufficiently secure
  • 3072 bits: Higher security requirements
  • 4096 bits: Maximum security level (lower performance) NIST recommends at least 2048 bits, 3072+ bits after 2030.

RSA vs ECC — Which Is Better?

ECC (elliptic curve) has shorter keys for the same security level (256-bit ECC ≈ 3072-bit RSA) and better performance. But RSA is more mature with better compatibility. New projects recommend ECC; existing systems keep RSA.

Why Can't RSA Directly Encrypt Large Files?

RSA has length limits (key length - padding overhead) and is slow. In practice, RSA encrypts AES keys, then AES encrypts the file (hybrid encryption). You can handle the symmetric AES side with our AES Encrypt/Decrypt tool.

Can I paste a PEM key with line breaks into the tool?

Yes. The 64-character line wrapping is a display convention; import strips all whitespace before base64-decoding. But check the header line: the public key must say BEGIN PUBLIC KEY and the private key BEGIN PRIVATE KEY — variants with RSA in the header are legacy PKCS#1, which Web Crypto does not support.

How many CJK characters fit in one 2048-bit RSA block?

The OAEP/SHA-256 limit is 190 bytes, about 63 CJK characters in UTF-8. The Encrypt tab shows a live "bytes / limit" counter and disables the button past the limit. For longer content, the right move is hybrid encryption, not a larger RSA key.

Triage notes

The error list is arranged by interop scenario: the cross-language mismatch gets an entry of its own with the assertion that nine times out of ten it is OAEP parameter drift — Java's OAEPWithSHA-256AndMGF1Padding still defaults MGF1 to SHA-1, while Web Crypto locks MGF1 to SHA-256 as well, and one digest field of difference makes the ciphertexts mutually unopenable. The PEM table distinguishes SPKI/PKCS#8 from legacy PKCS#1 by the header line, because Web Crypto will not accept the RSA-bearing headers — the most recognizable class of import failure. The annotation on 'payload too long' runs on the same logic: eight times out of ten someone skipped the envelope step, and the correct move is hybrid encryption, not a bigger key.


This field note comes from ToolVault. Browse more online tools on the homepage.