BAEL-4487 Add Crypto Exceptions (#13183)

This commit is contained in:
Shaun Phillips 2022-12-28 07:52:02 +00:00 committed by GitHub
parent d01629a246
commit ab892ba982
13 changed files with 525 additions and 9 deletions

View File

@ -13,4 +13,4 @@ This module contains articles about core Java Security
- [Get a List of Trusted Certificates in Java](https://www.baeldung.com/java-list-trusted-certificates)
- [Security Context Basics: User, Subject and Principal](https://www.baeldung.com/security-context-basics)
- [The java.security.egd JVM Option](https://www.baeldung.com/java-security-egd)
- More articles: [[<-- prev]](/core-java-modules/core-java-security)
- More articles: [[<-- prev]](/core-java-modules/core-java-security) [[next -->]](/core-java-modules/core-java-security-3)

View File

@ -1,12 +1,11 @@
package com.baeldung.crypto;
import java.security.GeneralSecurityException;
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 {

View File

@ -0,0 +1,66 @@
package com.baeldung.crypto.exception;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import com.baeldung.crypto.utils.CryptoUtils;
public class BadPaddingExamples {
public static byte[] encryptAndDecryptUsingDifferentKeys(byte[] plainTextBytes)
throws InvalidKeyException, GeneralSecurityException {
SecretKey encryptionKey = CryptoUtils.getKeyForText("BaeldungIsASuperCoolSite");
SecretKey differentKey = CryptoUtils.getKeyForText("ThisGivesUsAnAlternative");
Cipher cipher = Cipher.getInstance("AES/ECB/ISO10126Padding");
cipher.init(Cipher.ENCRYPT_MODE, encryptionKey);
byte[] cipherTextBytes = cipher.doFinal(plainTextBytes);
cipher.init(Cipher.DECRYPT_MODE, differentKey);
return cipher.doFinal(cipherTextBytes);
}
public static byte[] encryptAndDecryptUsingDifferentAlgorithms(SecretKey key, IvParameterSpec ivParameterSpec,
byte[] plainTextBytes) throws InvalidKeyException, GeneralSecurityException {
Cipher cipher = Cipher.getInstance("AES/CBC/ISO10126Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec);
byte[] cipherTextBytes = cipher.doFinal(plainTextBytes);
cipher = Cipher.getInstance("AES/ECB/ISO10126Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(cipherTextBytes);
}
public static byte[] encryptAndDecryptUsingDifferentPaddings(SecretKey key, byte[] plainTextBytes)
throws InvalidKeyException, GeneralSecurityException {
Cipher cipher = Cipher.getInstance("AES/ECB/ISO10126Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherTextBytes = cipher.doFinal(plainTextBytes);
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(cipherTextBytes);
}
public static byte[] encryptAndDecryptUsingSamePaddingKeyAndAlgorithm(SecretKey key, byte[] plainTextBytes)
throws InvalidKeyException, GeneralSecurityException {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherTextBytes = cipher.doFinal(plainTextBytes);
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(cipherTextBytes);
}
}

View File

@ -0,0 +1,32 @@
package com.baeldung.crypto.exception;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import com.baeldung.crypto.utils.CryptoUtils;
public class IllegalBlockSizeExamples {
public static byte[] encryptWithoutPadding(SecretKey key, byte[] plainTextBytes) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(plainTextBytes);
}
public static byte[] decryptTextThatIsNotEncrypted(SecretKey key) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
// note that this text is not encrypted at any point in this method.
String sampleText = "https://www.baeldung.com/";
byte[] unencryptedCipherTextBytes = sampleText.getBytes();
return CryptoUtils.decryptWithPadding(key, unencryptedCipherTextBytes);
}
}

View File

@ -0,0 +1,23 @@
package com.baeldung.crypto.exception;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public class InvalidAlgorithmParameterExamples {
public static byte[] encryptUsingIv(SecretKey key, byte[] ivBytes, String plainText)
throws InvalidKeyException, GeneralSecurityException {
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec);
byte[] bytes = plainText.getBytes();
return cipher.doFinal(bytes);
}
}

View File

@ -0,0 +1,56 @@
package com.baeldung.crypto.exception;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import com.baeldung.crypto.utils.CryptoUtils;
public class InvalidKeyExamples {
public static byte[] decryptUsingCBCWithNoIV(SecretKey key, byte[] cipherTextBytes)
throws InvalidKeyException, GeneralSecurityException {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(cipherTextBytes);
}
public static byte[] decryptUsingCBCWithIV(SecretKey key, byte[] cipherTextBytes)
throws InvalidKeyException, GeneralSecurityException {
byte[] ivBytes = new byte[] { 'B', 'a', 'e', 'l', 'd', 'u', 'n', 'g', 'I', 's', 'G', 'r', 'e', 'a', 't', '!' };
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);
return cipher.doFinal(cipherTextBytes);
}
public static byte[] encryptWithKeyTooShort() throws InvalidKeyException, GeneralSecurityException {
SecretKey encryptionKey = CryptoUtils.getKeyForText("ThisIsTooShort");
String plainText = "https://www.baeldung.com/";
byte[] bytes = plainText.getBytes();
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, encryptionKey);
return cipher.doFinal(bytes);
}
public static byte[] encryptWithKeyTooLong() throws InvalidKeyException, GeneralSecurityException {
SecretKey encryptionKey = CryptoUtils.getKeyForText("ThisTextIsTooLong");
String plainText = "https://www.baeldung.com/";
byte[] bytes = plainText.getBytes();
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, encryptionKey);
return cipher.doFinal(bytes);
}
}

View File

@ -0,0 +1,29 @@
package com.baeldung.crypto.exception;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
public class NoSuchAlgorithmExamples {
public static Cipher getCipherInstanceWithBadAlgorithm()
throws NoSuchAlgorithmException, NoSuchPaddingException {
return Cipher.getInstance("ABC");
}
public static Cipher getCipherInstanceWithBadAlgorithmMode()
throws NoSuchAlgorithmException, NoSuchPaddingException {
return Cipher.getInstance("AES/ABC");
}
public static Cipher getCipherInstanceWithBadPadding()
throws NoSuchAlgorithmException, NoSuchPaddingException {
return Cipher.getInstance("AES/CBC/ABC");
}
public static Cipher getCipherInstanceWithValidAlgorithm()
throws NoSuchAlgorithmException, NoSuchPaddingException {
return Cipher.getInstance("AES/CBC/PKCS5Padding");
}
}

View File

@ -1,16 +1,21 @@
package com.baeldung.crypto.utils;
import java.nio.charset.StandardCharsets;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidParameterSpecException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class CryptoUtils {
@ -20,6 +25,21 @@ public class CryptoUtils {
return keyGenerator.generateKey();
}
public static SecretKey getKeyForText(String secretText) throws GeneralSecurityException {
byte[] keyBytes = secretText.getBytes(StandardCharsets.UTF_8);
return new SecretKeySpec(keyBytes, "AES");
}
/*
* Allows us to generate a deterministic key, for the purposes of producing
* reliable and consistent demo code & tests! For a random key, consider using
* the generateKey method above.
*/
public static SecretKey getFixedKey() throws GeneralSecurityException {
String secretText = "BaeldungIsASuperCoolSite";
return getKeyForText(secretText);
}
public static IvParameterSpec getIV() {
SecureRandom secureRandom = new SecureRandom();
byte[] iv = new byte[128 / 8];
@ -29,18 +49,17 @@ public class CryptoUtils {
return new IvParameterSpec(nonce);
}
public static IvParameterSpec getIVSecureRandom(String algorithm) throws NoSuchAlgorithmException, NoSuchPaddingException {
public static IvParameterSpec getIVSecureRandom(String algorithm)
throws NoSuchAlgorithmException, NoSuchPaddingException {
SecureRandom random = SecureRandom.getInstanceStrong();
byte[] iv = new byte[Cipher.getInstance(algorithm)
.getBlockSize()];
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();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
return new IvParameterSpec(iv);
}
@ -50,4 +69,20 @@ public class CryptoUtils {
return nonce;
}
public static byte[] encryptWithPadding(SecretKey key, byte[] bytes) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherTextBytes = cipher.doFinal(bytes);
return cipherTextBytes;
}
public static byte[] decryptWithPadding(SecretKey key, byte[] cipherTextBytes) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(cipherTextBytes);
}
}

View File

@ -0,0 +1,61 @@
package com.baeldung.crypto.exception;
import java.security.GeneralSecurityException;
import javax.crypto.BadPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.crypto.utils.CryptoUtils;
public class BadPaddingExamplesUnitTest {
private SecretKey key;
private IvParameterSpec ivParameterSpec;
private String plainText;
private byte[] plainTextBytes;
@Before
public void before() throws GeneralSecurityException {
key = CryptoUtils.getFixedKey();
byte[] ivBytes = new byte[] { 'B', 'a', 'e', 'l', 'd', 'u', 'n', 'g', 'I', 's', 'G', 'r', 'e', 'a', 't', '!' };
ivParameterSpec = new IvParameterSpec(ivBytes);
plainText = "https://www.baeldung.com/";
plainTextBytes = plainText.getBytes();
}
@Test
public void givenTwoDifferentAlgorithmPaddings_whenDecrypting_thenBadPaddingExceptionIsThrown()
throws GeneralSecurityException {
Assert.assertThrows(BadPaddingException.class,
() -> BadPaddingExamples.encryptAndDecryptUsingDifferentPaddings(key, plainTextBytes));
}
@Test
public void givenTwoDifferentKeys_whenDecrypting_thenBadPaddingExceptionIsThrown() throws GeneralSecurityException {
Assert.assertThrows(BadPaddingException.class,
() -> BadPaddingExamples.encryptAndDecryptUsingDifferentKeys(plainTextBytes));
}
@Test
public void givenTwoDifferentAlgorithms_whenDecrypting_thenBadPaddingExceptionIsThrown()
throws GeneralSecurityException {
Assert.assertThrows(BadPaddingException.class, () -> BadPaddingExamples
.encryptAndDecryptUsingDifferentAlgorithms(key, ivParameterSpec, plainTextBytes));
}
@Test
public void givenSameVariablesUsedForEncryptingAndDecrypting_whenDecrypting_thenNoExceptionIsThrown()
throws GeneralSecurityException {
byte[] decryptedBytes = BadPaddingExamples.encryptAndDecryptUsingSamePaddingKeyAndAlgorithm(key,
plainTextBytes);
Assert.assertEquals(plainText, new String(decryptedBytes));
}
}

View File

@ -0,0 +1,56 @@
package com.baeldung.crypto.exception;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.crypto.utils.CryptoUtils;
public class IllegalBlockSizeExamplesUnitTest {
private SecretKey key;
private byte[] plainTextBytes;
private String plainText;
@Before
public void before() throws GeneralSecurityException {
key = CryptoUtils.getFixedKey();
plainText = "https://www.baeldung.com/";
plainTextBytes = plainText.getBytes();
}
@Test
public void whenEncryptingPlainTextWithoutPadding_thenIllegalBlockSizeExceptionIsThrown()
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
BadPaddingException {
Assert.assertThrows(IllegalBlockSizeException.class,
() -> IllegalBlockSizeExamples.encryptWithoutPadding(key, plainTextBytes));
}
@Test
public void whenDecryptingCipherTextThatWasNotEncrypted_thenIllegalBlockSizeExceptionIsThrown()
throws GeneralSecurityException {
Assert.assertThrows(IllegalBlockSizeException.class,
() -> IllegalBlockSizeExamples.decryptTextThatIsNotEncrypted(key));
}
@Test
public void whenEncryptingAndDecryptingWithPadding_thenNoExceptionThrown() throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
byte[] cipherTextBytes = CryptoUtils.encryptWithPadding(key, plainTextBytes);
byte[] decryptedBytes = CryptoUtils.decryptWithPadding(key, cipherTextBytes);
Assert.assertEquals(plainText, new String(decryptedBytes));
}
}

View File

@ -0,0 +1,59 @@
package com.baeldung.crypto.exception;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.crypto.utils.CryptoUtils;
public class InvalidAlgorithmParameterExamplesUnitTest {
private SecretKey key;
private String plainText;
@Before
public void before() throws GeneralSecurityException {
key = CryptoUtils.getFixedKey();
plainText = "https://www.baeldung.com/";
}
@Test
public void givenIvIsTooShort_whenEncryptingUsingCBC_thenInvalidAlgorithmParameterExceptionIsThrown()
throws GeneralSecurityException {
byte[] ivBytes = new byte[] { 'B', 'a', 'e', 'l', 'd', 'u', 'n', 'g', 'I', 's', 'G', 'r', 'e', 'a', 't' };
Assert.assertThrows(InvalidAlgorithmParameterException.class,
() -> InvalidAlgorithmParameterExamples.encryptUsingIv(key, ivBytes, plainText));
}
@Test
public void givenIvIsTooLong_whenEncryptingUsingCBC_thenInvalidAlgorithmParameterExceptionIsThrown()
throws GeneralSecurityException {
byte[] ivBytes = new byte[] { 'B', 'a', 'e', 'l', 'd', 'u', 'n', 'g', 'I', 's', 'G', 'r', 'e', 'a', 't', '!',
'?' };
Assert.assertThrows(InvalidAlgorithmParameterException.class,
() -> InvalidAlgorithmParameterExamples.encryptUsingIv(key, ivBytes, plainText));
}
@Test
public void givenIvIsCorrectSize_whenEncryptingUsingCBC_thenNoExceptionIsThrown() throws GeneralSecurityException {
byte[] ivBytes = new byte[] { 'B', 'a', 'e', 'l', 'd', 'u', 'n', 'g', 'I', 's', 'G', 'r', 'e', 'a', 't', '!' };
byte[] cipherTextBytes = InvalidAlgorithmParameterExamples.encryptUsingIv(key, ivBytes, plainText);
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);
byte[] decryptedBytes = cipher.doFinal(cipherTextBytes);
Assert.assertEquals(plainText, new String(decryptedBytes));
}
}

View File

@ -0,0 +1,62 @@
package com.baeldung.crypto.exception;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.crypto.utils.CryptoUtils;
public class InvalidKeyExamplesUnitTest {
private SecretKey key;
private String plainText;
private byte[] cipherTextBytes;
@Before
public void before() throws GeneralSecurityException {
key = CryptoUtils.getFixedKey();
byte[] ivBytes = new byte[] { 'B', 'a', 'e', 'l', 'd', 'u', 'n', 'g', 'I', 's', 'G', 'r', 'e', 'a', 't', '!' };
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec);
plainText = "https://www.baeldung.com/";
byte[] plainTextBytes = plainText.getBytes();
cipherTextBytes = cipher.doFinal(plainTextBytes);
}
@Test
public void givenTextEncryptedWithCBC_whenDecryptingWithNoIv_thenInvalidKeyExceptionIsThrown() {
Assert.assertThrows(InvalidKeyException.class,
() -> InvalidKeyExamples.decryptUsingCBCWithNoIV(key, cipherTextBytes));
}
@Test
public void givenTextEncryptedWithCBC_whenDecryptingWithIv_thenTextIsDecrypted()
throws InvalidKeyException, GeneralSecurityException {
byte[] decryptedBytes = InvalidKeyExamples.decryptUsingCBCWithIV(key, cipherTextBytes);
Assert.assertEquals(plainText, new String(decryptedBytes));
}
@Test
public void whenKeyIsTooShort_thenInvalidKeyExceptionIsThrown() {
Assert.assertThrows(InvalidKeyException.class, () -> InvalidKeyExamples.encryptWithKeyTooShort());
}
@Test
public void whenKeyIsTooLong_thenInvalidKeyExceptionIsThrown() {
Assert.assertThrows(InvalidKeyException.class, () -> InvalidKeyExamples.encryptWithKeyTooLong());
}
}

View File

@ -0,0 +1,38 @@
package com.baeldung.crypto.exception;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import org.junit.Assert;
import org.junit.Test;
public class NoSuchAlgorithmExamplesUnitTest {
@Test
public void whenInitingCipherWithUnknownAlgorithm_thenNoSuchAlgorithmExceptionIsThrown()
throws GeneralSecurityException {
Assert.assertThrows(NoSuchAlgorithmException.class,
() -> NoSuchAlgorithmExamples.getCipherInstanceWithBadAlgorithm());
}
@Test
public void whenInitingCipherWithUnknownAlgorithmMode_thenNoSuchAlgorithmExceptionIsThrown()
throws GeneralSecurityException {
Assert.assertThrows(NoSuchAlgorithmException.class,
() -> NoSuchAlgorithmExamples.getCipherInstanceWithBadAlgorithmMode());
}
@Test
public void whenInitingCipherWithUnknownPadding_thenNoSuchAlgorithmExceptionIsThrown()
throws GeneralSecurityException {
Assert.assertThrows(NoSuchAlgorithmException.class,
() -> NoSuchAlgorithmExamples.getCipherInstanceWithBadPadding());
}
@Test
public void whenInitingCipherWithValidAlgorithm_thenCipherInstanceIsReturned() throws GeneralSecurityException {
Assert.assertTrue(NoSuchAlgorithmExamples.getCipherInstanceWithValidAlgorithm() instanceof Cipher);
}
}