Java Cipher Class
The Cipher class in Java is a fundamental component of the Java Cryptography Architecture (JCA) and the Java Cryptography Extension (JCE). It is designed to provide a comprehensive framework for cryptographic operations, including encryption and decryption. The Cipher class facilitates the implementation of various cryptographic algorithms and supports different modes and padding schemes, making it a versatile tool for securing sensitive information.
Various Cipher Modes
Cipher modes of operation play a crucial role in modern cryptography, determining how block ciphers process and encrypt data. Each mode has distinct characteristics, strengths, and weaknesses, making them suitable for different scenarios. In this detailed introduction, we'll explore various cipher modes, shedding light on their mechanisms and considerations for their application.
- Electronic Codebook (ECB)
ECB is the most straightforward cipher mode, where each block of plaintext is independently encrypted using the same key. This mode is deterministic, meaning identical plaintext blocks yield identical ciphertext blocks.
Filename: ECBEncryptionDecryptionExample.java
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.util.Base64;
public class ECBEncryptionDecryptionExample {
public static void main(String[] args) throws Exception {
// Generate a secret key
SecretKey secretKey = generateSecretKey();
// Example plaintext message
String originalMessage = "Hello, ECB Mode!";
// Encrypt the message using ECB mode
byte[] encryptedBytes = encrypt(originalMessage, secretKey);
String encryptedMessage = Base64.getEncoder().encodeToString(encryptedBytes);
System.out.println("Encrypted Message: " + encryptedMessage);
// Decrypt the message using ECB mode
byte[] decryptedBytes = decrypt(encryptedBytes, secretKey);
String decryptedMessage = new String(decryptedBytes);
System.out.println("Decrypted Message: " + decryptedMessage);
}
private static SecretKey generateSecretKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128); // Key size for AES
return keyGenerator.generateKey();
}
private static byte[] encrypt(String message, SecretKey secretKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(message.getBytes());
}
private static byte[] decrypt(byte[] encryptedBytes, SecretKey secretKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(encryptedBytes);
}
}
Output:
Encrypted Message: z/L0yWkVXkRbz0aEh4JxEswsjzSsey27zAWu/l+yLgQ=
Decrypted Message: Hello, ECB Mode!
In this example, the generateSecretKey method creates a secret key using the AES algorithm. The encrypt method takes a plaintext message and encrypts it using the ECB mode. The decrypt method takes the encrypted bytes and decrypts them using the same ECB mode.
Advantages: Simplicity and parallelization. Each block can be encrypted independently, making it suitable for parallel processing.
Disadvantages: Lack of diffusion; identical blocks result in identical ciphertext, making it vulnerable to certain attacks. Not recommended for encrypting large amounts of data.
- Cipher Block Chaining (CBC)
Cipher Block Chaining (CBC) is a widely used block cipher mode of operation designed to add an element of diffusion and randomness to the encryption process. It is part of the fundamental cryptographic techniques and plays a crucial role in ensuring the confidentiality and integrity of transmitted or stored data.
Filename: CBCModeExample.java
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.util.Base64;
public class CBCModeExample {
public static void main(String[] args) throws Exception {
// Generate a secret key
SecretKey secretKey = generateSecretKey();
// Generate a random Initialization Vector (IV)
IvParameterSpec iv = generateIV();
// Example plaintext message
String originalMessage = "Hello, CBC Mode!";
// Encrypt the message using CBC mode
byte[] encryptedBytes = encrypt(originalMessage, secretKey, iv);
String encryptedMessage = Base64.getEncoder().encodeToString(encryptedBytes);
System.out.println("Encrypted Message: " + encryptedMessage);
// Decrypt the message using CBC mode
byte[] decryptedBytes = decrypt(encryptedBytes, secretKey, iv);
String decryptedMessage = new String(decryptedBytes);
System.out.println("Decrypted Message: " + decryptedMessage);
}
private static SecretKey generateSecretKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128); // Key size for AES
return keyGenerator.generateKey();
}
private static IvParameterSpec generateIV() {
// Generate a random Initialization Vector (IV)
byte[] ivBytes = new byte[16]; // IV size for AES is typically 16 bytes
// Fill the array with random bytes (in a real-world scenario, use a secure random number generator)
for (int i = 0; i < ivBytes.length; i++) {
ivBytes[i] = (byte) (Math.random() * 256);
}
return new IvParameterSpec(ivBytes);
}
private static byte[] encrypt(String message, SecretKey secretKey, IvParameterSpec iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
return cipher.doFinal(message.getBytes());
}
private static byte[] decrypt(byte[] encryptedBytes, SecretKey secretKey, IvParameterSpec iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
return cipher.doFinal(encryptedBytes);
}
}
Output:
Encrypted Message: W51Yus0VWSZGz2O1rTO/iqmW9lmbT+Ti89b5Q2naO/M=
Decrypted Message: Hello, CBC Mode!
In this example, the Cipher instance is initialized with the "AES/CBC/PKCS5Padding" algorithm, specifying CBC mode with PKCS5 padding. The initialization vector (IV) is randomly generated for each encryption and is necessary for the decryption process.
Advantages: Diffusion of plaintext changes, introducing randomness with the IV.
Disadvantages: Sequential processing as each block relies on the previous one. Vulnerable to padding oracle attacks if not used carefully.
- Cipher Feedback (CFB)
Cipher Feedback (CFB) is a mode of operation for block ciphers that transforms a block cipher into a self-synchronizing stream cipher. It provides a way to encrypt a stream of plaintext bits with a block cipher, allowing for the encryption of individual bits or bytes rather than fixed-size blocks. CFB mode offers advantages such as error propagation containment and the ability to process streaming data.
Filename: CFBModeExample.java
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.util.Base64;
public class CFBModeExample {
public static void main(String[] args) throws Exception {
// Generate a secret key
SecretKey secretKey = generateSecretKey();
// Generate a random Initialization Vector (IV)
IvParameterSpec iv = generateIV();
// Example plaintext message
String originalMessage = "Hello, CFB Mode!";
// Encrypt the message using CFB mode
byte[] encryptedBytes = encrypt(originalMessage, secretKey, iv);
String encryptedMessage = Base64.getEncoder().encodeToString(encryptedBytes);
System.out.println("Encrypted Message: " + encryptedMessage);
// Decrypt the message using CFB mode
byte[] decryptedBytes = decrypt(encryptedBytes, secretKey, iv);
String decryptedMessage = new String(decryptedBytes);
System.out.println("Decrypted Message: " + decryptedMessage);
}
private static SecretKey generateSecretKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128); // Key size for AES
return keyGenerator.generateKey();
}
private static IvParameterSpec generateIV() {
// Generate a random Initialization Vector (IV)
byte[] ivBytes = new byte[16]; // IV size for AES is typically 16 bytes
// Fill the array with random bytes (in a real-world scenario, use a secure random number generator)
for (int i = 0; i < ivBytes.length; i++) {
ivBytes[i] = (byte) (Math.random() * 256);
}
return new IvParameterSpec(ivBytes);
}
private static byte[] encrypt(String message, SecretKey secretKey, IvParameterSpec iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CFB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
return cipher.doFinal(message.getBytes());
}
private static byte[] decrypt(byte[] encryptedBytes, SecretKey secretKey, IvParameterSpec iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CFB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
return cipher.doFinal(encryptedBytes);
}
}
Output:
Encrypted Message: OpWNPVBFl8DjL430TmYcfnZhzgzYxk1TYIuxJW/qcW4=
Decrypted Message: Hello, CFB Mode!
In this example, the Cipher instance is initialized with the "AES/CFB/PKCS5Padding" algorithm, specifying CFB mode with PKCS5 padding. The Initialization Vector (IV) is randomly generated for each encryption and is necessary for the decryption process.
Advantages: Can operate on streaming data, and errors are confined to a few blocks.
Disadvantages: Requires synchronization, and sequential processing may impact performance.
- Output Feedback (OFB)
Output Feedback (OFB) is a block cipher mode of operation that transforms a block cipher into a synchronous stream cipher. Similar to Cipher Feedback (CFB) mode, OFB allows the encryption of individual bits or bytes rather than fixed-size blocks. OFB is known for its self-synchronizing property and the ability to support streaming encryption.
Filename: OFBModeExample.java
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.util.Base64;
public class OFBModeExample {
public static void main(String[] args) throws Exception {
// Generate a secret key
SecretKey secretKey = generateSecretKey();
// Generate a random Initialization Vector (IV)
IvParameterSpec iv = generateIV();
// Example plaintext message
String originalMessage = "Hello, OFB Mode!";
// Encrypt the message using OFB mode
byte[] encryptedBytes = encrypt(originalMessage, secretKey, iv);
String encryptedMessage = Base64.getEncoder().encodeToString(encryptedBytes);
System.out.println("Encrypted Message: " + encryptedMessage);
// Decrypt the message using OFB mode
byte[] decryptedBytes = decrypt(encryptedBytes, secretKey, iv);
String decryptedMessage = new String(decryptedBytes);
System.out.println("Decrypted Message: " + decryptedMessage);
}
private static SecretKey generateSecretKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128); // Key size for AES
return keyGenerator.generateKey();
}
private static IvParameterSpec generateIV() {
// Generate a random Initialization Vector (IV)
byte[] ivBytes = new byte[16]; // IV size for AES is typically 16 bytes
// Fill the array with random bytes (in a real-world scenario, use a secure random number generator)
for (int i = 0; i < ivBytes.length; i++) {
ivBytes[i] = (byte) (Math.random() * 256);
}
return new IvParameterSpec(ivBytes);
}
private static byte[] encrypt(String message, SecretKey secretKey, IvParameterSpec iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/OFB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
return cipher.doFinal(message.getBytes());
}
private static byte[] decrypt(byte[] encryptedBytes, SecretKey secretKey, IvParameterSpec iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/OFB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
return cipher.doFinal(encryptedBytes);
}
}
Output:
Encrypted Message: wC5bNKSIBKAgWhVSJ7K7LL2w94k3rrPFRmGWtznRHuU=
Decrypted Message: Hello, OFB Mode!
In this example, the Cipher instance is initialized with the "AES/OFB/PKCS5Padding" algorithm, specifying OFB mode with PKCS5 padding. The Initialization Vector (IV) is randomly generated for each encryption and is necessary for the decryption process.
Advantages: Can be parallelized, and errors do not propagate from one block to the next.
Disadvantages: Lack of diffusion; changes in the plaintext do not affect subsequent blocks.
- Counter (CTR)
Counter (CTR) mode is a widely used block cipher mode of operation that transforms a block cipher into a stream cipher. It allows for the encryption of individual bits or bytes, providing a parallelizable and efficient method for encrypting large amounts of data. CTR mode is known for its simplicity, versatility, and suitability for random-access requirements.
Filename: CTRModeExample.java
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.util.Base64;
public class CTRModeExample {
public static void main(String[] args) throws Exception {
// Generate a secret key
SecretKey secretKey = generateSecretKey();
// Generate a random Initialization Vector (IV)
IvParameterSpec iv = generateIV();
// Example plaintext message
String originalMessage = "Hello, CTR Mode!";
// Encrypt the message using CTR mode
byte[] encryptedBytes = encrypt(originalMessage, secretKey, iv);
String encryptedMessage = Base64.getEncoder().encodeToString(encryptedBytes);
System.out.println("Encrypted Message: " + encryptedMessage);
// Decrypt the message using CTR mode
byte[] decryptedBytes = decrypt(encryptedBytes, secretKey, iv);
String decryptedMessage = new String(decryptedBytes);
System.out.println("Decrypted Message: " + decryptedMessage);
}
private static SecretKey generateSecretKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128); // Key size for AES
return keyGenerator.generateKey();
}
private static IvParameterSpec generateIV() {
// Generate a random Initialization Vector (IV)
byte[] ivBytes = new byte[16]; // IV size for AES is typically 16 bytes
// Fill the array with random bytes (in a real-world scenario, use a secure random number generator)
for (int i = 0; i < ivBytes.length; i++) {
ivBytes[i] = (byte) (Math.random() * 256);
}
return new IvParameterSpec(ivBytes);
}
private static byte[] encrypt(String message, SecretKey secretKey, IvParameterSpec iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); // Corrected padding to NoPadding
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
return cipher.doFinal(message.getBytes());
}
private static byte[] decrypt(byte[] encryptedBytes, SecretKey secretKey, IvParameterSpec iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); // Corrected padding to NoPadding
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
return cipher.doFinal(encryptedBytes);
}
}
Output:
Encrypted Message: utPoyPwMQJW3SU3JzOnXOA==
Decrypted Message: Hello, CTR Mode!
In this example, the Cipher instance is initialized with the "AES/CTR/PKCS5Padding" algorithm, specifying CTR mode with PKCS5 padding. The Initialization Vector (IV) is randomly generated for each encryption and is necessary for the decryption process.
Advantages: Parallel processing is possible, supports random access to ciphertext.
Disadvantages: No error propagation; errors in one block do not affect subsequent blocks.
- Galois/Counter Mode (GCM)
Galois/Counter Mode (GCM) is a block cipher mode of operation that provides authenticated encryption and is widely used for securing data in modern cryptographic applications. GCM is an authenticated encryption with associated data (AEAD) mode, which means it not only encrypts the data but also provides integrity protection, ensuring that the data has not been tampered with.
Filename: GCMModeExample.java
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 GCMModeExample {
public static void main(String[] args) throws Exception {
// Generate a secret key
SecretKey secretKey = generateSecretKey();
// Generate a random Initialization Vector (IV)
byte[] iv = generateIV();
// Example plaintext message
String originalMessage = "Hello, GCM Mode!";
// Encrypt the message using GCM mode
byte[] encryptedBytes = encrypt(originalMessage, secretKey, iv);
String encryptedMessage = Base64.getEncoder().encodeToString(encryptedBytes);
System.out.println("Encrypted Message: " + encryptedMessage);
// Decrypt the message using GCM mode
byte[] decryptedBytes = decrypt(encryptedBytes, secretKey, iv);
String decryptedMessage = new String(decryptedBytes);
System.out.println("Decrypted Message: " + decryptedMessage);
}
private static SecretKey generateSecretKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128); // Key size for AES
return keyGenerator.generateKey();
}
private static byte[] generateIV() {
// Generate a random Initialization Vector (IV)
byte[] iv = new byte[12]; // IV size for GCM is typically 12 bytes
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(iv);
return iv;
}
private static byte[] encrypt(String message, SecretKey secretKey, byte[] iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, iv); // 128 is the authentication tag length
cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmParameterSpec);
return cipher.doFinal(message.getBytes());
}
private static byte[] decrypt(byte[] encryptedBytes, SecretKey secretKey, byte[] iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, iv); // 128 is the authentication tag length
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmParameterSpec);
return cipher.doFinal(encryptedBytes);
}
}
Output:
Encrypted Message: xhyghrVPr1GdlEW2eIDSgVXQ3icduxy+tf8CZgb9WQA=
Decrypted Message: Hello, GCM Mode!
In this example, the Cipher instance is initialized with the "AES/GCM/NoPadding" algorithm, specifying GCM mode with no padding. The Initialization Vector (IV) is randomly generated for each encryption and is necessary for both encryption and decryption.
Advantages: Efficient, parallel processing, and provides authentication.
Disadvantages: Resource-intensive; may not be suitable for resource-constrained environments.