package com.srsystem.util; import jakarta.persistence.AttributeConverter; import jakarta.persistence.Converter; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.security.SecureRandom; import java.util.Base64; @Component @Converter public class PhoneEncryptionConverter implements AttributeConverter { private static final String AES = "AES"; private static final String AES_GCM = "AES/GCM/NoPadding"; private static final int GCM_IV_LENGTH = 12; private static final int GCM_TAG_LENGTH = 128; private static SecretKey secretKey; private static final SecureRandom secureRandom = new SecureRandom(); public PhoneEncryptionConverter(@Value("${app.encryption.phone-key}") String key) { byte[] keyBytes = key.getBytes(); if (keyBytes.length < 16) { byte[] padded = new byte[16]; System.arraycopy(keyBytes, 0, padded, 0, Math.min(keyBytes.length, 16)); keyBytes = padded; } secretKey = new SecretKeySpec(keyBytes, AES); } @Override public String convertToDatabaseColumn(String plaintext) { if (plaintext == null) return null; try { byte[] iv = new byte[GCM_IV_LENGTH]; secureRandom.nextBytes(iv); Cipher cipher = Cipher.getInstance(AES_GCM); cipher.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(GCM_TAG_LENGTH, iv)); byte[] ciphertext = cipher.doFinal(plaintext.getBytes()); byte[] combined = new byte[GCM_IV_LENGTH + ciphertext.length]; System.arraycopy(iv, 0, combined, 0, GCM_IV_LENGTH); System.arraycopy(ciphertext, 0, combined, GCM_IV_LENGTH, ciphertext.length); return Base64.getEncoder().encodeToString(combined); } catch (Exception e) { throw new RuntimeException("Phone encryption failed", e); } } @Override public String convertToEntityAttribute(String encrypted) { if (encrypted == null) return null; try { byte[] combined = Base64.getDecoder().decode(encrypted); byte[] iv = new byte[GCM_IV_LENGTH]; byte[] ciphertext = new byte[combined.length - GCM_IV_LENGTH]; System.arraycopy(combined, 0, iv, 0, GCM_IV_LENGTH); System.arraycopy(combined, GCM_IV_LENGTH, ciphertext, 0, ciphertext.length); Cipher cipher = Cipher.getInstance(AES_GCM); cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(GCM_TAG_LENGTH, iv)); return new String(cipher.doFinal(ciphertext)); } catch (Exception e) { return encrypted; } } }