diff --git a/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/CryptoDriver.java b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/CryptoDriver.java
new file mode 100644
index 0000000000..552bd5d474
--- /dev/null
+++ b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/CryptoDriver.java
@@ -0,0 +1,86 @@
+package com.baeldung.crypto;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.IvParameterSpec;
+import java.security.GeneralSecurityException;
+
+import com.baeldung.crypto.utils.CryptoUtils;
+
+public class CryptoDriver {
+
+ public byte[] ecbEncrypt(SecretKey key, byte[] data) throws GeneralSecurityException {
+ Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ return cipher.doFinal(data);
+ }
+
+ public byte[] ecbDecrypt(SecretKey key, byte[] cipherText) throws GeneralSecurityException {
+ Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+ cipher.init(Cipher.DECRYPT_MODE, key);
+ return cipher.doFinal(cipherText);
+ }
+
+ public byte[] cbcEncrypt(SecretKey key, IvParameterSpec iv, byte[] data) throws GeneralSecurityException {
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ cipher.init(Cipher.ENCRYPT_MODE, key, iv);
+ return cipher.doFinal(data);
+ }
+
+ public byte[] cbcDecrypt(SecretKey key, IvParameterSpec iv, byte[] cipherText) throws GeneralSecurityException {
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ cipher.init(Cipher.DECRYPT_MODE, key, iv);
+ return cipher.doFinal(cipherText);
+ }
+
+ public byte[] cfbEncrypt(SecretKey key, IvParameterSpec iv, byte[] data) throws GeneralSecurityException {
+ Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, key, iv);
+ return cipher.doFinal(data);
+ }
+
+ public byte[] cfbDecrypt(SecretKey key, IvParameterSpec iv, byte[] cipherText) throws GeneralSecurityException {
+ Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
+ cipher.init(Cipher.DECRYPT_MODE, key, iv);
+ return cipher.doFinal(cipherText);
+ }
+
+ public byte[] ofbEncrypt(SecretKey key, IvParameterSpec iv, byte[] data) throws GeneralSecurityException {
+ Cipher cipher = Cipher.getInstance("AES/OFB32/PKCS5Padding");
+ cipher.init(Cipher.ENCRYPT_MODE, key, iv);
+ return cipher.doFinal(data);
+ }
+
+ public byte[] ofbDecrypt(SecretKey key, IvParameterSpec iv, byte[] cipherText) throws GeneralSecurityException {
+ Cipher cipher = Cipher.getInstance("AES/OFB32/PKCS5Padding");
+ cipher.init(Cipher.DECRYPT_MODE, key, iv);
+ return cipher.doFinal(cipherText);
+ }
+
+ public byte[][] ctrEncrypt(SecretKey key, IvParameterSpec iv, byte[] data) throws GeneralSecurityException {
+ Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, key, iv);
+ return new byte[][] { cipher.getIV(), cipher.doFinal(data) };
+ }
+
+ public byte[] ctrDecrypt(SecretKey key, byte[] iv, byte[] cipherText) throws GeneralSecurityException {
+ Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
+ cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
+ return cipher.doFinal(cipherText);
+ }
+
+ public byte[][] gcmEncrypt(SecretKey key, byte[] iv, byte[] data) throws GeneralSecurityException {
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, iv));
+ byte[] ciphertext = cipher.doFinal(data);
+ return new byte[][] { iv, ciphertext };
+ }
+
+ public byte[] gcmDecrypt(SecretKey key, byte[] iv, byte[] ciphertext) throws GeneralSecurityException {
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ cipher.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(128, iv));
+ byte[] plaintext = cipher.doFinal(ciphertext);
+ return plaintext;
+ }
+}
diff --git a/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/utils/CryptoUtils.java b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/utils/CryptoUtils.java
new file mode 100644
index 0000000000..2d3df231ff
--- /dev/null
+++ b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/utils/CryptoUtils.java
@@ -0,0 +1,53 @@
+package com.baeldung.crypto.utils;
+
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+
+public class CryptoUtils {
+
+ public static SecretKey generateKey() throws GeneralSecurityException {
+ KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
+ keyGenerator.init(256);
+ return keyGenerator.generateKey();
+ }
+
+ public static IvParameterSpec getIV() {
+ SecureRandom secureRandom = new SecureRandom();
+ byte[] iv = new byte[128 / 8];
+ byte[] nonce = new byte[96 / 8];
+ secureRandom.nextBytes(nonce);
+ System.arraycopy(nonce, 0, iv, 0, nonce.length);
+ return new IvParameterSpec(nonce);
+ }
+
+ public static IvParameterSpec getIVSecureRandom(String algorithm) throws NoSuchAlgorithmException, NoSuchPaddingException {
+ SecureRandom random = SecureRandom.getInstanceStrong();
+ byte[] iv = new byte[Cipher.getInstance(algorithm)
+ .getBlockSize()];
+ random.nextBytes(iv);
+ return new IvParameterSpec(iv);
+ }
+
+ public static IvParameterSpec getIVInternal(Cipher cipher) throws InvalidParameterSpecException {
+ AlgorithmParameters params = cipher.getParameters();
+ byte[] iv = params.getParameterSpec(IvParameterSpec.class)
+ .getIV();
+ return new IvParameterSpec(iv);
+ }
+
+ public static byte[] getRandomIVWithSize(int size) {
+ byte[] nonce = new byte[size];
+ new SecureRandom().nextBytes(nonce);
+ return nonce;
+ }
+
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/CryptoDriverIVUnitTest.java b/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/CryptoDriverIVUnitTest.java
new file mode 100644
index 0000000000..f3bed310dd
--- /dev/null
+++ b/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/CryptoDriverIVUnitTest.java
@@ -0,0 +1,86 @@
+package com.baeldung.crypto;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import java.security.GeneralSecurityException;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import com.baeldung.crypto.utils.CryptoUtils;
+
+public class CryptoDriverIVUnitTest{
+ private CryptoDriver driver = new CryptoDriver();
+ private String TEST_DATA = "Encrypt this for testing";
+
+ @Test
+ public void givenString_whenAesEcb_thenSuccess() throws GeneralSecurityException {
+ SecretKey key = CryptoUtils.generateKey();
+ byte[] plaintext = TEST_DATA.getBytes();
+
+ byte[] ciphertext = driver.ecbEncrypt(key, plaintext);
+ byte[] decryptedtext = driver.ecbDecrypt(key, ciphertext);
+
+ Assertions.assertEquals(new String(decryptedtext), TEST_DATA);
+ }
+
+ @Test
+ public void givenString_whenAesCbc_thenSuccess() throws GeneralSecurityException {
+ SecretKey key = CryptoUtils.generateKey();
+ IvParameterSpec iv = CryptoUtils.getIVSecureRandom("AES");
+ byte[] plaintext = TEST_DATA.getBytes();
+
+ byte[] ciphertext = driver.cbcEncrypt(key, iv, plaintext);
+ byte[] decryptedtext = driver.cbcDecrypt(key, iv, ciphertext);
+
+ Assertions.assertEquals(new String(decryptedtext), TEST_DATA);
+ }
+
+ @Test
+ public void givenString_whenAesCfb_thenSuccess() throws GeneralSecurityException {
+ SecretKey key = CryptoUtils.generateKey();
+ IvParameterSpec iv = CryptoUtils.getIVSecureRandom("AES/CFB/NoPadding");
+ byte[] plaintext = TEST_DATA.getBytes();
+
+ byte[] ciphertext = driver.cfbEncrypt(key, iv, plaintext);
+ byte[] decryptedtext = driver.cfbDecrypt(key, iv, ciphertext);
+
+ Assertions.assertEquals(new String(decryptedtext), TEST_DATA);
+ }
+
+ @Test
+ public void givenString_whenAesOfb_thenSuccess() throws GeneralSecurityException {
+ SecretKey key = CryptoUtils.generateKey();
+ IvParameterSpec iv = CryptoUtils.getIVSecureRandom("AES/OFB32/PKCS5Padding");
+ byte[] plaintext = TEST_DATA.getBytes();
+
+ byte[] ciphertext = driver.ofbEncrypt(key, iv, plaintext);
+ byte[] decryptedtext = driver.ofbDecrypt(key, iv, ciphertext);
+
+ Assertions.assertEquals(new String(decryptedtext), TEST_DATA);
+ }
+
+ @Test
+ public void givenString_whenAesCtr_thenSuccess() throws GeneralSecurityException {
+ SecretKey key = CryptoUtils.generateKey();
+ IvParameterSpec iv = CryptoUtils.getIVSecureRandom("AES/CTR/NoPadding");
+ byte[] plaintext = TEST_DATA.getBytes();
+
+ byte[][] ciphertext = driver.ctrEncrypt(key, iv, plaintext);
+ byte[] decryptedtext = driver.ctrDecrypt(key, ciphertext[0], ciphertext[1]);
+
+ Assertions.assertEquals(new String(decryptedtext), TEST_DATA);
+ }
+
+ @Test
+ void givenString_whenAesGcm_thenSuccess() throws GeneralSecurityException {
+ SecretKey key = CryptoUtils.generateKey();
+ byte[] iv = CryptoUtils.getRandomIVWithSize(12);
+ byte[] plaintext = (TEST_DATA).getBytes();
+
+ byte[][] ciphertext = driver.gcmEncrypt(key, iv, plaintext);
+ byte[] decryptedtext = driver.gcmDecrypt(key, ciphertext[0], ciphertext[1]);
+
+ Assertions.assertEquals(new String(decryptedtext), TEST_DATA);
+ }
+}
diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml
index 872161c2bd..c3d17e7637 100644
--- a/core-java-modules/pom.xml
+++ b/core-java-modules/pom.xml
@@ -99,6 +99,7 @@
core-java-reflection-2
core-java-security
core-java-security-2
+ core-java-security-3
core-java-streams
core-java-streams-2
core-java-streams-3