Two Ways to Encrypt Fields in Spring Boot: @Convert and Oracle DBMS_CRYPTO
The article explains why encrypting sensitive fields such as phone numbers and ID cards is essential, then walks through two concrete implementations for Spring Boot 3.5.0—an application‑layer solution using @Convert with a custom AttributeConverter and a database‑layer solution using Oracle's DBMS_CRYPTO with @ColumnTransformer—complete with code, setup steps, and test results.
In many business scenarios, sensitive data like phone numbers, ID numbers, and bank cards appear in almost every table. If the database is compromised, plaintext data can cause serious security incidents. While access control is often added, protecting data at rest is frequently overlooked.
1. Application‑layer encryption with @Convert and AttributeConverter
By annotating entity fields with @Convert and providing a custom AttributeConverter, encryption and decryption are performed automatically during the JPA mapping process, keeping business code free of manual cryptographic calls.
@Entity
@Table(name = "T_USER")
public class User {
@Id
@Tsid
private Long id;
private String name;
private Integer age;
@Convert(converter = EncryptionConverter.class)
private String idCard;
@Convert(converter = EncryptionConverter.class)
private String phone;
}The converter delegates to an EncryptionService that uses AES with a fixed secret key.
@Component
@Converter
public class EncryptionConverter implements AttributeConverter<String, String> {
private final EncryptionService encryptionService;
public EncryptionConverter(EncryptionService encryptionService) {
this.encryptionService = encryptionService;
}
@Override
public String convertToDatabaseColumn(String s) {
return encryptionService.encrypt(s);
}
@Override
public String convertToEntityAttribute(String s) {
return encryptionService.decrypt(s);
}
} @Component
public class EncryptionService {
private static final String ALGORITHM = "AES";
private static final String SECRET = "1234567890123456";
public String encrypt(String value) {
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
SecretKeySpec keySpec = new SecretKeySpec(SECRET.getBytes(StandardCharsets.UTF_8), ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encrypted = cipher.doFinal(value.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encrypted);
} catch (Exception e) {
// handle exception
}
return null;
}
public String decrypt(String encryptedValue) {
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
SecretKeySpec keySpec = new SecretKeySpec(SECRET.getBytes(StandardCharsets.UTF_8), ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] decoded = Base64.getDecoder().decode(encryptedValue);
byte[] decrypted = cipher.doFinal(decoded);
return new String(decrypted, StandardCharsets.UTF_8);
} catch (Exception e) {
// handle exception
}
return null;
}
}A simple service saves and queries users, and unit tests demonstrate that encrypted values are persisted and correctly decrypted when read.
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void save(User user) {
this.userRepository.saveAndFlush(user);
}
public List<User> queryUsers() {
return this.userRepository.findAll();
}
// Unit tests
@Test
public void testSave() {
User user = new User("Pack", 33, "58737377373", "18988888888");
this.userService.save(user);
}
@Test
public void testQueryUsers() {
System.err.println(this.userService.queryUsers());
}Execution screenshots (shown below) confirm that the data stored in the database is encrypted and that the service returns the original plaintext values.
2. Database‑level encryption with Oracle DBMS_CRYPTO
This approach leverages Oracle's built‑in DBMS_CRYPTO package to perform AES‑CBC encryption/decryption inside the database. Two PL/SQL functions are created: one to encrypt a VARCHAR2 to RAW, another to decrypt RAW back to VARCHAR2.
-- AES‑CBC‑PKCS5 encryption function, plaintext VARCHAR2 → encrypted RAW
CREATE OR REPLACE FUNCTION encrypt_text(p_text VARCHAR2)
RETURN RAW AS
BEGIN
RETURN DBMS_CRYPTO.ENCRYPT(
src => UTL_RAW.CAST_TO_RAW(p_text),
typ => DBMS_CRYPTO.ENCRYPT_AES128 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5,
key => UTL_RAW.CAST_TO_RAW('1234567890123456')
);
END;
-- AES‑CBC‑PKCS5 decryption function, encrypted RAW → plaintext VARCHAR2
CREATE OR REPLACE FUNCTION decrypt_text(p_raw RAW)
RETURN VARCHAR2 AS
BEGIN
RETURN UTL_RAW.CAST_TO_VARCHAR2(
DBMS_CRYPTO.DECRYPT(
src => p_raw,
typ => DBMS_CRYPTO.ENCRYPT_AES128 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5,
key => UTL_RAW.CAST_TO_RAW('1234567890123456')
)
);
END;If the executing user is not SYS, the DBMS_CRYPTO package must be granted: GRANT EXECUTE ON SYS.DBMS_CRYPTO TO SCOTT; The entity is then modified to use @ColumnTransformer, which calls the encryption function on write and the decryption function on read.
public class User {
@Id @Tsid private Long id;
private String name;
private Integer age;
@ColumnTransformer(read = "decrypt_text(id_card)", write = "encrypt_text(?)")
private String idCard;
@ColumnTransformer(read = "decrypt_text(phone)", write = "encrypt_text(?)")
private String phone;
}The same unit tests from the first solution are executed; the resulting screenshots show that Oracle automatically encrypts the fields on insert and decrypts them on select, without any changes to the service layer.
Both approaches achieve field‑level encryption, but they have different trade‑offs: the @Convert solution works with any JPA‑compatible database and keeps encryption logic in the application, while the Oracle solution offloads the cryptographic work to the database, eliminates application changes, and ties the implementation to Oracle.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
