skip to content

Why can't you encrypt arbitrarily large data directly with RSA in Java, and how does hybrid (envelope) encryption solve it?

level: seniorimportance: must knowfreq 58%

answer

  1. RSA = single block < modulus; OAEP-2048 ≈ 190 bytes max
  2. too-big input -> IllegalBlockSizeException
  3. never chunk-and-loop RSA over big data
  4. hybrid: AES for data, RSA wraps the AES key
  5. Java WRAP_MODE/UNWRAP_MODE; AES-GCM for the payload

basics

~20 s

RSA can only encrypt a small chunk smaller than the key size, so doFinal throws if your data is too big. The fix is hybrid encryption: encrypt the data with a fast random AES key, then RSA-encrypt only that small AES key.

solid answer

~40 s

RSA operates on a single block whose size is bounded by the modulus: with OAEP-SHA256 the maximum plaintext is roughly keyBytes - 2*hashLen - 2 (about 190 bytes for a 2048-bit key). Feeding more than that to doFinal throws an exception - RSA is not a stream cipher and you should never loop over chunks. The standard solution is hybrid / envelope encryption: generate a fresh random symmetric key (e.g. AES-256), encrypt the bulk data with AES-GCM (fast, any length, authenticated), then use RSA only to encrypt that small symmetric key. The recipient RSA-decrypts the AES key with their private key, then AES-decrypts the payload. Java supports this directly with Cipher.WRAP_MODE/UNWRAP_MODE to wrap a Key object. This is exactly why standards like CMS/PGP/TLS use asymmetric crypto only for key exchange, not for bulk data.

go deeper

for a junior

Knows RSA can only encrypt small data and that for big data you encrypt with a symmetric key and protect that key with RSA.

for a middle

Can state the size limit comes from the modulus minus padding and can sketch the AES-then-RSA-wrap hybrid flow.

for a senior

Computes the OAEP size limit, knows IllegalBlockSizeException, uses WRAP/UNWRAP with AES-GCM, and explains why chunking RSA is wrong.

for a principal

Justifies hybrid encryption as the protocol-wide pattern (TLS/PGP/JOSE), weighs RSA-OAEP vs ECIES/ECDH key agreement, and sets key sizes/algorithm policy for the org.

## The hard size limit **RSA is a single-block operation.** Internally it raises a number (your message, interpreted as an integer) to a power modulo a big number `n` called the **modulus**. The whole message must therefore be a number **smaller than the modulus**. The modulus size is the 'key size' - e.g. a **2048-bit RSA key** has a 256-byte modulus. Padding eats into that budget. With **OAEP-SHA256**, the maximum plaintext you can encrypt in one shot is roughly: ``` maxBytes = keySizeInBytes - 2 * hashLengthInBytes - 2 = 256 - 2*32 - 2 = 190 bytes (for RSA-2048 + SHA-256) ``` For PKCS#1 v1.5 it is `keyBytes - 11`. Either way it is **tiny**. If you pass more than the limit to `doFinal`, you get a `javax.crypto.IllegalBlockSizeException` ('Data must not be longer than ...'). **Crucial:** RSA is **not** a block/stream cipher - you must **not** chunk a large message into RSA-block-sized pieces and loop. That is slow (RSA is orders of magnitude slower than AES), bloats the ciphertext, and is cryptographically fragile. The size limit is a *signal* that you are using RSA wrong for bulk data. ## Hybrid (envelope) encryption - the correct pattern The universal solution, used by TLS, PGP, S/MIME, and JOSE: 1. **Generate a fresh random symmetric key** for this one message - e.g. a 256-bit AES key from `KeyGenerator`. 2. **Encrypt the bulk data with the symmetric key** using a fast, authenticated mode like **AES-GCM** (handles any length and detects tampering). 3. **Encrypt (wrap) only the small symmetric key with RSA** using the recipient's public key. 4. Send both: the RSA-encrypted symmetric key + the AES-encrypted payload (plus the GCM IV/nonce). Decryption reverses it: RSA-decrypt the symmetric key with the **private** key, then AES-decrypt the payload. Because RSA now only ever protects a ~32-byte key, the size limit never bites, and you get RSA's key-distribution benefit with AES's speed. ## Java support: WRAP_MODE / UNWRAP_MODE JCE has first-class support for this so you don't hand-marshal raw key bytes: ```java // Sender: wrap the AES key with RSA KeyGenerator kg = KeyGenerator.getInstance("AES"); kg.init(256); SecretKey aesKey = kg.generateKey(); Cipher rsa = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); rsa.init(Cipher.WRAP_MODE, recipientPublicKey); byte[] wrappedKey = rsa.wrap(aesKey); // RSA over the small key only Cipher aes = Cipher.getInstance("AES/GCM/NoPadding"); aes.init(Cipher.ENCRYPT_MODE, aesKey); byte[] iv = aes.getIV(); byte[] payload = aes.doFinal(largePlaintext); // AES over the bulk data // Recipient: unwrap then decrypt rsa.init(Cipher.UNWRAP_MODE, recipientPrivateKey); Key key = rsa.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY); aes.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(128, iv)); byte[] recovered = aes.doFinal(payload); ``` ## Why standards do this Asymmetric crypto is excellent at **key distribution** (no shared secret needed) but slow and size-limited. Symmetric crypto is fast and length-unlimited but needs a shared key. **Hybrid encryption uses each for what it is good at** - that is why essentially every real protocol uses RSA/ECDH only to establish a symmetric key and then encrypts the data symmetrically.

  • What is the maximum plaintext size for RSA-2048 with OAEP-SHA256, and what happens if you exceed it?
    About 190 bytes (256 - 2*32 - 2). Exceeding it makes doFinal throw IllegalBlockSizeException; RSA must not be chunked, use hybrid encryption.
  • Which Cipher modes does Java provide specifically for hybrid encryption?
    WRAP_MODE and UNWRAP_MODE - cipher.wrap(Key) RSA-encrypts a Key, cipher.unwrap(...) reconstructs it, so you don't hand-serialize raw key bytes.

saying these in an interview costs you the question

  • Looping RSA over fixed-size chunks to encrypt a large file
  • Believing RSA is a general-purpose stream/block cipher
  • Forgetting that padding reduces the usable plaintext size
  • Reusing one symmetric key forever instead of a fresh per-message key
  • Encrypting bulk data with AES-ECB or a static IV in the hybrid scheme

context