TextEncryptorConverter.java
package com.nonononoki.alovoa.component;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import com.nonononoki.alovoa.model.DatabaseRuntimeException;
import jakarta.persistence.AttributeConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class TextEncryptorConverter implements AttributeConverter<String, String> {
@Value("${app.text.key}")
private String key;
@Value("${app.text.salt}")
private String salt;
private static final String TRANSFORMATION = "AES/CBC/PKCS5PADDING";
private static IvParameterSpec ivSpec;
private static SecretKeySpec keySpec;
private static Cipher enCipher;
private static Cipher deCipher;
private synchronized IvParameterSpec getIvSpec() {
if (ivSpec == null) {
ivSpec = new IvParameterSpec(salt.getBytes(StandardCharsets.UTF_8));
}
return ivSpec;
}
private synchronized SecretKeySpec getKeySpec() {
if (keySpec == null) {
keySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
}
return keySpec;
}
private synchronized Cipher getEnCipher() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException {
if (enCipher == null) {
enCipher = Cipher.getInstance(TRANSFORMATION);
enCipher.init(Cipher.ENCRYPT_MODE, getKeySpec(), getIvSpec());
}
return enCipher;
}
private synchronized Cipher getDeCipher() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException {
if (deCipher == null) {
deCipher = Cipher.getInstance(TRANSFORMATION);
deCipher.init(Cipher.DECRYPT_MODE, getKeySpec(), getIvSpec());
}
return deCipher;
}
public synchronized String encode(String attribute)
throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException,
NoSuchPaddingException, InvalidAlgorithmParameterException {
if(attribute == null) {
return null;
}
byte[] ba = getEnCipher().doFinal(attribute.getBytes(StandardCharsets.UTF_8));
return Base64.getUrlEncoder().encodeToString(ba);
}
public synchronized String decode(String dbData)
throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException,
NoSuchPaddingException, InvalidAlgorithmParameterException {
if(dbData == null) {
return null;
}
return new String(getDeCipher().doFinal(Base64.getUrlDecoder().decode(dbData)), StandardCharsets.UTF_8);
}
@Override
public String convertToDatabaseColumn(String attribute) throws DatabaseRuntimeException {
try {
return encode(attribute);
} catch (Exception e) {
throw new DatabaseRuntimeException(e);
}
}
@Override
public String convertToEntityAttribute(String dbData) throws DatabaseRuntimeException {
try {
return decode(dbData);
} catch (Exception e) {
throw new DatabaseRuntimeException(e);
}
}
}