package com.danielbohry.stocks.service; import com.danielbohry.stocks.exception.DecryptionKeyException; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; import java.util.Base64; @Service public class EncryptService { @Value("${encryption.key}") private String secret; private static final String ALGORITHM = "AES/CBC/PKCS5Padding"; private static final int IV_LENGTH = 16; private static final int AES_KEY_SIZE = 16; public String encrypt(String data) throws Exception { SecretKeySpec key = getSecretKey(); byte[] iv = new byte[IV_LENGTH]; new SecureRandom().nextBytes(iv); IvParameterSpec ivSpec = new IvParameterSpec(iv); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); byte[] combined = new byte[IV_LENGTH + encrypted.length]; System.arraycopy(iv, 0, combined, 0, IV_LENGTH); System.arraycopy(encrypted, 0, combined, IV_LENGTH, encrypted.length); return Base64.getEncoder().encodeToString(combined); } public String decrypt(String encryptedData) throws Exception { try { SecretKeySpec key = getSecretKey(); byte[] combined = Base64.getDecoder().decode(encryptedData); byte[] iv = new byte[IV_LENGTH]; byte[] encrypted = new byte[combined.length - IV_LENGTH]; System.arraycopy(combined, 0, iv, 0, IV_LENGTH); System.arraycopy(combined, IV_LENGTH, encrypted, 0, encrypted.length); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); byte[] decrypted = cipher.doFinal(encrypted); return new String(decrypted, StandardCharsets.UTF_8); } catch (BadPaddingException e) { throw new DecryptionKeyException("Cannot decrypt data", e); } } private SecretKeySpec getSecretKey() { byte[] keyBytes = new byte[AES_KEY_SIZE]; byte[] secretBytes = secret.getBytes(StandardCharsets.UTF_8); int length = Math.min(secretBytes.length, AES_KEY_SIZE); System.arraycopy(secretBytes, 0, keyBytes, 0, length); return new SecretKeySpec(keyBytes, "AES"); } }