skip to content

Cryptography (JCA/JCE)

The JCA/JCE design: provider-backed getInstance factories and engine classes for hashing, encryption, key generation, signatures and secure randomness, wired together by transformation strings. Interviewers care that you can pick the right engine and parameters, not that you can implement a cipher.

part ofJavaoverview, primer and where to startread it →
on this pageshow

explore

questions

page 1 of 2

When encrypting and decrypting with RSA in Java, which key do you init the Cipher with, and what is the role of ENCRYPT_MODE vs DECRYPT_MODE?

level: juniorimportance: must knowfreq 55%

answer

  1. public key encrypts, private key decrypts (for confidentiality)
  2. init(mode, key) before doFinal
  3. ENCRYPT_MODE + public; DECRYPT_MODE + private
  4. signing is the opposite direction - use Signature, not Cipher
  5. Cipher is stateful and not thread-safe

basics

~10 s

To encrypt, init the Cipher in ENCRYPT_MODE with the recipient's public key. To decrypt, init in DECRYPT_MODE with the matching private key. Public key locks, private key unlocks.

solid answer

~40 s

RSA uses a key pair. For confidentiality, the sender encrypts with the recipient's public key (cipher.init(Cipher.ENCRYPT_MODE, publicKey)) and only the holder of the private key can decrypt (cipher.init(Cipher.DECRYPT_MODE, privateKey)). The first argument to init is the operation mode constant, the second is the Key. A Cipher is stateful: you must call init before doFinal, and re-init to reuse it (it is also not thread-safe). The public-key-encrypts / private-key-decrypts direction is for encryption; the opposite direction (private signs, public verifies) is signing, which is done via the separate Signature class, not Cipher. A common mistake is encrypting with the private key to 'hide' data - that does not provide confidentiality because the public key is, by definition, public.

go deeper

for a junior

Knows public key encrypts and private key decrypts, and that you call init with a mode constant and a key before doFinal.

for a middle

Distinguishes encryption (public encrypts / private decrypts) from signing (private signs / public verifies via the Signature class), and knows Cipher is stateful.

for a senior

Explains why private-key 'encryption' gives no confidentiality, the WRAP/UNWRAP modes for key wrapping, and thread-safety constraints.

for a principal

Defines key-handling policy (where private keys live - HSM/KMS), key rotation, and which operations belong to Cipher vs Signature in the system design.

## The two keys and what each does RSA gives you a **key pair**: - a **public key** - safe to publish to anyone; - a **private key** - must stay secret with its owner. The math is set up so the two operations are inverses: data transformed with one key can only be reversed with the *other*. This gives two distinct use cases, and beginners often confuse them: 1. **Encryption (confidentiality):** encrypt with the **recipient's public key**, decrypt with the **recipient's private key**. Anyone can encrypt a message *to* you; only you can read it. 2. **Signing (authenticity):** the *opposite* direction - the owner transforms with their **private key**, anyone verifies with the **public key**. In Java this is the separate `java.security.Signature` class, **not** `Cipher`. ## Initializing the Cipher After `Cipher.getInstance(...)`, the Cipher is inert until you `init` it: ```java cipher.init(Cipher.ENCRYPT_MODE, recipientPublicKey); byte[] ct = cipher.doFinal(message); // ... on the recipient side ... cipher.init(Cipher.DECRYPT_MODE, recipientPrivateKey); byte[] pt = cipher.doFinal(ct); ``` The **first argument** is an `int` operation-mode constant: - `Cipher.ENCRYPT_MODE` - `Cipher.DECRYPT_MODE` - (also `WRAP_MODE` / `UNWRAP_MODE`, used to encrypt/decrypt *keys* - relevant for hybrid encryption.) The **second argument** is a `Key`. For RSA encryption it is typically a `PublicKey`; for decryption a `PrivateKey`. The JCE will reject an obviously wrong key type, but it cannot stop you from picking the *logically* wrong key (e.g., using your own private key when you meant the recipient's public key). ## Statefulness and threading A `Cipher` instance is **stateful** and **not thread-safe**. You must `init` before each independent operation, and you cannot share one instance across threads. Treat it as a short-lived, per-operation object. ## The classic confidentiality mistake Encrypting with your **private** key does **not** hide anything: because the public key is published, anyone can decrypt it. That operation is only meaningful as the basis of a *signature* (proving you, the private-key holder, produced it). So: to keep a secret, always encrypt with the **public** key of whoever should be able to read it.

  • If you want to prove you authored a message, which key and which class do you use?
    Sign with your private key using java.security.Signature; others verify with your public key. Cipher is for confidentiality, not signing.

saying these in an interview costs you the question

  • Encrypting with the private key to 'protect' data (public key can decrypt it)
  • Confusing encryption (public encrypts) with signing (private signs)
  • Calling doFinal without init
  • Sharing a single Cipher instance across threads

context

open as a page

How do you create a Cipher for AES in Java, and what does the transformation string passed to Cipher.getInstance mean?

level: juniorimportance: must knowfreq 70%

basics

~10 s

You call Cipher.getInstance with a transformation string like "AES/GCM/NoPadding". It has three parts: the algorithm (AES), the mode (how blocks are chained, e.g. GCM or CBC), and the padding (e.g. PKCS5Padding or NoPadding).

open as a page

How do you generate a symmetric secret key in Java using KeyGenerator, and what does init() control?

level: juniorimportance: must knowfreq 60%

basics

~10 s

Ask KeyGenerator for an algorithm like AES, call init() with the key size (for example 256 bits), then generateKey(). It returns a SecretKey you use to encrypt and decrypt.

open as a page

How do you compute a cryptographic hash in Java using the MessageDigest API? Walk through the getInstance / update / digest lifecycle.

level: juniorimportance: must knowfreq 70%

basics

~10 s

Call MessageDigest.getInstance("SHA-256") to get an engine, feed bytes with update(...), then call digest() to get the final hash as a byte[]. digest() finishes the computation and resets the engine for reuse.

open as a page

How should you generate the salt for PBKDF2 in Java, and why does the choice of random source matter?

level: juniorimportance: must knowfreq 50%

basics

~20 s

Use java.security.SecureRandom to fill a fresh byte array (16 bytes) for each password. Don't use java.util.Random or Math.random - they're predictable. The salt is stored with the hash and doesn't need to be secret, just unique and random.

open as a page

Why is java.util.Random (or Math.random()) unsafe for generating security values like tokens or keys, and what should you use instead?

level: juniorimportance: must knowfreq 78%

basics

~10 s

java.util.Random and Math.random() are predictable: from a few outputs an attacker can compute the seed and predict all future values. For anything security-related (tokens, keys, salts) use java.security.SecureRandom, which is unpredictable.

open as a page

How do you create and verify a digital signature using Java's JCA Signature class?

level: juniorimportance: must knowfreq 55%

basics

~10 s

Get a Signature object with Signature.getInstance("SHA256withRSA"). To sign: call initSign(privateKey), update(data), then sign() to get the signature bytes. To verify: initVerify(publicKey), update(data), then verify(signatureBytes) returns true if it matches.

open as a page

What is a Cipher transformation string in Java, and what do its parts mean (e.g. "AES/GCM/NoPadding")?

level: juniorimportance: must knowfreq 70%

basics

~10 s

It is the text you pass to Cipher.getInstance to choose encryption. It has three parts separated by slashes: the algorithm, the mode of operation, and the padding, like "AES/GCM/NoPadding".

open as a page

How do you obtain and configure a Cipher for RSA in Java, and what does a transformation string like "RSA/ECB/OAEPWithSHA-256AndMGF1Padding" mean?

level: middleimportance: must knowfreq 60%

basics

~10 s

Call Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding") to get a Cipher, then cipher.init(...) with a key. The string names the algorithm (RSA), a mode, and the padding scheme used to make encryption safe.

open as a page

How do you initialize a Cipher for encryption with a raw AES key, and what is SecretKeySpec used for?

level: middleimportance: must knowfreq 65%

basics

~20 s

After getInstance you call cipher.init(Cipher.ENCRYPT_MODE, key, params). The key is a SecretKey; SecretKeySpec wraps raw bytes (like a 16- or 32-byte array) into a SecretKey for AES. For decryption you use Cipher.DECRYPT_MODE with the same key.

open as a page

How do you generate an asymmetric key pair (e.g. RSA or EC) in Java, and how does it differ from generating a symmetric key?

level: middleimportance: must knowfreq 55%

basics

~10 s

Use KeyPairGenerator: getInstance("RSA"), initialize(2048), generateKeyPair(). You get a KeyPair with a public key (shareable) and a private key (secret). Symmetric uses KeyGenerator and produces one shared SecretKey instead.

open as a page

How do you persist and retrieve keys and certificates using a Java KeyStore, including protection parameters and aliases?

level: middleimportance: must knowfreq 58%

basics

~20 s

A KeyStore is a password-protected file of keys and certificates. You load() it (or load(null) for empty), store entries under a string alias with a password, then save with store(), and read them back with getKey(alias, password) or getCertificate(alias).

open as a page

Why should you compare two digests with MessageDigest.isEqual instead of Arrays.equals or ==?

level: middleimportance: must knowfreq 65%

basics

~20 s

MessageDigest.isEqual compares byte arrays in constant time, so it does not leak how many bytes matched. Arrays.equals returns early on the first mismatch, which an attacker can time to guess a secret byte by byte.

open as a page

Is MessageDigest.getInstance("SHA-256") an appropriate way to store user passwords? Explain.

level: middleimportance: must knowfreq 60%

basics

~10 s

No. SHA-256 via MessageDigest is fast and unsalted, so attackers can brute-force or use rainbow tables. Store passwords with a slow, salted, purpose-built KDF like bcrypt, scrypt, Argon2, or PBKDF2 instead.

open as a page

How do you derive a PBKDF2 hash of a password in Java using SecretKeyFactory and PBEKeySpec?

level: middleimportance: must knowfreq 70%

basics

~10 s

Get a SecretKeyFactory for "PBKDF2WithHmacSHA256", build a PBEKeySpec from the password chars, a random salt, an iteration count, and a key length, then call generateSecret(spec).getEncoded() to get the hash bytes.

open as a page

After deriving a PBKDF2 hash, what do you store, and how do you verify a password on login?

level: middleimportance: must knowfreq 62%

basics

~20 s

Store the salt, iteration count, algorithm, and the hash bytes (not the password). On login, re-derive the hash from the entered password using the stored salt and iterations, then compare it to the stored hash with a constant-time check.

open as a page

What happens if you construct or seed SecureRandom with a fixed seed, and why is that dangerous?

level: middleimportance: must knowfreq 60%

basics

~20 s

A fixed seed makes the output deterministic — the same 'random' values every run — which is fine for tests but disastrous for real secrets, because anyone with the seed (or who guesses it) can reproduce every token or key.

open as a page

How do you use SecureRandom to fill a key, IV, salt, or token buffer, and what should you avoid when doing so?

level: middleimportance: must knowfreq 70%

basics

~10 s

Create one SecureRandom, make a byte[] of the size you need, and call secureRandom.nextBytes(buffer). That fills it with unpredictable bytes. Avoid building random bytes from Random, timestamps, or fixed seeds.

open as a page

Why is calling Cipher.getInstance("AES") (a bare algorithm name) a security pitfall in Java?

level: middleimportance: must knowfreq 62%

basics

~20 s

Because Java then lets the provider pick the mode and padding for you. On the default JDK it picks ECB mode, which is insecure: identical plaintext blocks become identical ciphertext, leaking data. Always write the full "AES/mode/padding".

open as a page

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%

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.

open as a page

How do you perform authenticated encryption with AES-GCM in Java, and how is the authentication tag handled on encrypt and decrypt?

level: seniorimportance: must knowfreq 60%

basics

~20 s

Use "AES/GCM/NoPadding" with a GCMParameterSpec that sets the tag length (usually 128 bits) and a unique 12-byte nonce. On encrypt, doFinal appends the authentication tag to the ciphertext automatically. On decrypt, doFinal verifies the tag and throws AEADBadTagException if the data was tampered with.

open as a page

How do you supply algorithm parameters (the IV/nonce) to a Java Cipher, and how do IvParameterSpec and GCMParameterSpec differ?

level: seniorimportance: must knowfreq 55%

basics

~10 s

You pass parameters as a third argument to cipher.init. For CBC/CTR you use IvParameterSpec(iv). For GCM you use GCMParameterSpec(tagLengthBits, nonce), which also sets the authentication tag length. The IV/nonce must be unique per encryption.

open as a page

How do you serialize an RSA public/private key to bytes and reconstruct it in Java using KeyFactory, X509EncodedKeySpec and PKCS8EncodedKeySpec?

level: middleimportance: should knowfreq 45%

basics

~10 s

Call key.getEncoded() to get the standard byte form. Wrap public-key bytes in X509EncodedKeySpec and private-key bytes in PKCS8EncodedKeySpec, then use KeyFactory.getInstance("RSA").generatePublic/generatePrivate to turn them back into Key objects.

open as a page

What is the difference between Cipher.update and Cipher.doFinal, and when do you use each?

level: middleimportance: should knowfreq 45%

basics

~20 s

update feeds part of the data into the cipher and may return some processed bytes, but it doesn't finish the operation. doFinal processes the last chunk, applies padding (or the GCM tag), and completes. For small data you just call doFinal once.

open as a page

How do you reuse a MessageDigest instance, and what do reset(), update(), and the two digest() overloads do to its internal state?

level: middleimportance: should knowfreq 45%

basics

~20 s

A MessageDigest holds running state. update() adds bytes to it; digest() finishes the hash and then auto-resets, so you can hash another message right away. reset() throws away any buffered bytes without producing a hash.

open as a page

What does an algorithm string like "SHA256withRSA" mean, and why must it match your key type?

level: middleimportance: should knowfreq 45%

basics

~20 s

"SHA256withRSA" means: hash the data with SHA-256, then sign that hash with RSA. The "...withRSA" part decides which key type you need — an RSA key. Use "...withECDSA" with an EC key. Mixing them throws InvalidKeyException.

open as a page

How does the update() method work in the Signature lifecycle, and what are the rules when feeding data in multiple chunks?

level: middleimportance: should knowfreq 35%

basics

~20 s

update() feeds the bytes to be signed or verified into the Signature object. You can call it many times to stream large data in chunks; the bytes are accumulated in order. The verifier must feed exactly the same bytes in the same order, then call sign() or verify().

open as a page

When choosing between AES-CBC and AES-GCM in Java, what are the trade-offs, and what must you add to CBC to make it safe?

level: seniorimportance: should knowfreq 40%

basics

~20 s

GCM gives encryption plus built-in integrity in one step and is the default choice. CBC only encrypts — it has no integrity check — so by itself it is vulnerable to tampering and padding-oracle attacks. If you must use CBC, you have to add a separate MAC (encrypt-then-MAC). Both need a unique IV per message.

open as a page

What role does SecureRandom play in key generation, and what are the pitfalls of seeding it incorrectly?

level: seniorimportance: should knowfreq 45%

basics

~10 s

SecureRandom supplies the unpredictable random bytes that keys are built from. If the randomness is predictable, attackers can guess your keys. Use SecureRandom (a strong generator), never new Random(), and let it self-seed.

open as a page

How does provider selection work for MessageDigest.getInstance, and how would you design hashing code to stay algorithm- and provider-agile?

level: seniorimportance: should knowfreq 35%

basics

~20 s

getInstance("SHA-256") asks the JCA to find any installed provider that supplies that algorithm, picking the highest-priority one. You can also pin a provider by name. Keep the algorithm name in config rather than hard-coded so you can change it without touching code.

open as a page

showing 1–30 of 40