Cryptography in Java: Encryption and Hashing – A Complete Guide
Cryptography is the fundamental foundation of modern application security. Java has a built-in powerful and flexible infrastructure for working with encryption and hashing — Java Cryptography Architecture (JCA) and Java Cryptography Extension (JCE). These libraries allow you to implement both symmetric (AES) and asymmetric (RSA) encryption, as well as cryptographic hashing (SHA-256). In this article, we will break down the key concepts and write working examples in pure Java (without third-party dependencies).
Basic Concepts and JCA/JCE Architecture
JCA provides a framework for working with cryptographic operations. The key idea is providers, which implement specific algorithms. By default, the JDK includes the SUN provider (for hashes) and SunJCE (for encryption). The main classes are located in the javax.crypto and java.security packages.
- Cipher — the main class for encryption and decryption.
- KeyGenerator — generation of symmetric keys.
- KeyPairGenerator — generation of key pairs for asymmetric encryption.
- MessageDigest — computation of hash sums.
- SecretKeySpec — representation of a symmetric key from a byte array.
Symmetric Encryption: AES
AES (Advanced Encryption Standard) is the most popular symmetric algorithm. It uses the same key for encryption and decryption. The recommended mode is GCM (authenticated encryption) or CBC with PKCS5Padding. Below is an example of encrypting a string using AES-256/GCM.
import javax.crypto.Cipher;import javax.crypto.KeyGenerator;import javax.crypto.SecretKey;import javax.crypto.spec.GCMParameterSpec;import java.security.SecureRandom;import java.util.Base64;
public class AESGCMExample { private static final int AES_KEY_SIZE = 256; private static final int GCM_IV_LENGTH = 12; private static final int GCM_TAG_LENGTH = 128;
public static SecretKey generateKey() throws Exception { KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(AES_KEY_SIZE, SecureRandom.getInstanceStrong()); return keyGen.generateKey(); }
public static String encrypt(String plaintext, SecretKey key) throws Exception { byte[] iv = new byte[GCM_IV_LENGTH]; SecureRandom.getInstanceStrong().nextBytes(iv); Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, iv); cipher.init(Cipher.ENCRYPT_MODE, key, spec); byte[] cipherText = cipher.doFinal(plaintext.getBytes()); byte[] encrypted = new byte[iv.length + cipherText.length]; System.arraycopy(iv, 0, encrypted, 0, iv.length); System.arraycopy(cipherText, 0, encrypted, iv.length, cipherText.length); return Base64.getEncoder().encodeToString(encrypted); }
public static String decrypt(String encryptedData, SecretKey key) throws Exception { byte[] decoded = Base64.getDecoder().decode(encryptedData); byte[] iv = new byte[GCM_IV_LENGTH]; System.arraycopy(decoded, 0, iv, 0, iv.length); byte[] cipherText = new byte[decoded.length - iv.length]; System.arraycopy(decoded, iv.length, cipherText, 0, cipherText.length); Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, iv); cipher.init(Cipher.DECRYPT_MODE, key, spec); return new String(cipher.doFinal(cipherText)); }
public static void main(String[] args) throws Exception { SecretKey key = generateKey()