Skip to content

Commit

Permalink
feat(jans-core): add AES utility class #3215
Browse files Browse the repository at this point in the history
  • Loading branch information
yuriyz committed Dec 7, 2022
1 parent 28fad9f commit 1d71222
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 0 deletions.
6 changes: 6 additions & 0 deletions jans-core/util/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
</dependency>

<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
</dependency>

</dependencies>

</project>
68 changes: 68 additions & 0 deletions jans-core/util/src/main/java/io/jans/util/security/AESUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package io.jans.util.security;

import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Base64;

public class AESUtil {

public static final int IV_LENGTH = 16;
public static final int GCM_TAG_LENGTH = 16;

private AESUtil() {
}

public static SecretKey generateKey(int n) throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(n);
return keyGenerator.generateKey();
}

public static SecretKey getKeyFromPassword(String password, String salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), 65536, 256);
return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
}

public static IvParameterSpec generateIv() {
return generateIv(IV_LENGTH);
}

public static IvParameterSpec generateIv(int size) {
byte[] iv = new byte[size];
new SecureRandom().nextBytes(iv);
return new IvParameterSpec(iv);
}

public static GCMParameterSpec generateGcmSpec() {
return new GCMParameterSpec(GCM_TAG_LENGTH * 8, generateIv().getIV());
}

public static String encrypt(String algorithm, String input, SecretKey key, AlgorithmParameterSpec spec) throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {

Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
byte[] cipherText = cipher.doFinal(input.getBytes());
return Base64.getEncoder().encodeToString(cipherText);
}

public static String decrypt(String algorithm, String cipherText, SecretKey key, AlgorithmParameterSpec spec) throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
byte[] plainText = cipher.doFinal(Base64.getDecoder().decode(cipherText));
return new String(plainText);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package io.jans.util.security;

import org.testng.annotations.Test;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import static io.jans.util.security.AESUtil.generateGcmSpec;
import static org.testng.Assert.assertEquals;

/**
* @author Yuriy Z
*/
public class AESUtilTest {

@Test
public void cbc_whenEncryptAndDecrypt_shouldProduceCorrectOutput() throws NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException {
String input = "textToEncrypt";
SecretKey key = AESUtil.generateKey(128);
IvParameterSpec ivParameterSpec = AESUtil.generateIv();

String algorithm = "AES/CBC/PKCS5Padding";
String cipherText = AESUtil.encrypt(algorithm, input, key, ivParameterSpec);
String plainText = AESUtil.decrypt(algorithm, cipherText, key, ivParameterSpec);

assertEquals(input, plainText);
}

@Test
public void gcm_whenEncryptAndDecrypt_shouldProduceCorrectOutput() throws NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException {
String input = "textToEncrypt";
SecretKey key = AESUtil.generateKey(128);

String algorithm = "AES/GCM/NoPadding";
final GCMParameterSpec gcmSpec = generateGcmSpec();

String cipherText = AESUtil.encrypt(algorithm, input, key, gcmSpec);
String plainText = AESUtil.decrypt(algorithm, cipherText, key, gcmSpec);

assertEquals(input, plainText);
}
}

0 comments on commit 1d71222

Please sign in to comment.