There are times when you want to encrypt a specific sensitive data on database, like field Salary or Account Number, so that nobody can see the value directly. And there are many approach available to achieve this, and one of it is by using encryption from application side.
For encryption on application level we can use manual encryption or can use Jasypt, which is a very convenient library for handling encryption on database level. On this example, we are using Jasypt.
First as always, a simple pom.xml file,
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.redhat.edw</groupId>
<artifactId>TestFieldEncryption2</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/>
</parent>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.jasypt</groupId>
<artifactId>jasypt</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>org.jasypt</groupId>
<artifactId>jasypt-hibernate5</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.1</version>
<executions>
<execution>
<id>default-deploy</id>
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
A main java class,
package com.redhat.edw;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Several java class for creating api and database query,
package com.redhat.edw.controller;
import com.redhat.edw.model.UserAccount;
import com.redhat.edw.repository.UserAccountRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class IndexController {
@Autowired
private UserAccountRepository userAccountRepository;
@GetMapping("/")
public List<UserAccount> showAll() {
return userAccountRepository.findAll();
}
@PostMapping("/")
public UserAccount save(@RequestBody UserAccount userAccount) {
return userAccountRepository.save(userAccount);
}
}
package com.redhat.edw.model;
import org.hibernate.annotations.Type;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "t_user_account")
public class UserAccount implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "user_id")
private Integer userId;
@Type(type="encryptedString")
@Column(name = "account_no", length = 300)
private String accountNo;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getAccountNo() {
return accountNo;
}
public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}
}
package com.redhat.edw.repository;
import com.redhat.edw.model.UserAccount;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserAccountRepository extends JpaRepository<UserAccount, Integer> {
}
Now start with the fun part, where we do all the encryption. First creating a Configuration class for handling encryption configuration
package com.redhat.edw.service;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.hibernate5.encryptor.HibernatePBEEncryptorRegistry;
import org.jasypt.iv.RandomIvGenerator;
import org.springframework.context.annotation.Configuration;
@Configuration
public class EncryptionConfig {
public EncryptionConfig() {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
encryptor.setPoolSize(4);
encryptor.setPassword("MY-PASSPASSPASS123");
encryptor.setAlgorithm("PBEWithMD5AndTripleDES");
encryptor.setIvGenerator(new RandomIvGenerator());
encryptor.setKeyObtentionIterations(1500);
HibernatePBEEncryptorRegistry registry = HibernatePBEEncryptorRegistry.getInstance();
registry.registerPBEStringEncryptor("myStringEncryptor", encryptor);
}
}
And then a standalone typedef,
@TypeDefs({
@TypeDef(
name="encryptedString",
typeClass= EncryptedStringType.class,
parameters= {
@Parameter(name="encryptorRegisteredName", value="myStringEncryptor")
}
)
})
package com.redhat.edw.model;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;
import org.jasypt.hibernate5.type.EncryptedStringType;
We can add new data by using a simple curl,
curl -L -X POST 'http://localhost:8080/' \
-H 'Content-Type: application/json' \
--data-raw '{
"accountNo":"1234567890",
"userId":"5"
}'
And querying using this curl command,
curl -L -X GET 'http://localhost:8080/'
A successful json response will looks like this,
[
{
"id": 4,
"userId": 4,
"accountNo": "1234567890"
},
{
"id": 3,
"userId": 1,
"accountNo": "1234567890"
},
{
"id": 5,
"userId": 3,
"accountNo": "1234567890"
},
{
"id": 6,
"userId": 5,
"accountNo": "1234567890"
}
]
Despite on database looks like this,

For full code, can access my Github page,
https://github.com/edwin/spring-boot-jpa-jasypt
Hi, when changing the password, (“MY-PASSPASSPASS123”) in this case, how do we decrypt encrypted info with the old password and encrypt them with a new password?
Hi, we can create a utility class to do decryption by using Jasypt. A StandardPBEStringEncryptor class from Jasypt is the first class i would try to do this.
Hey. Thanks for the tutorial. Is it possible to use JPQL queries with Jasypt? Let’s say create create findByAccountNo in your example? Or the only possibility is to fetch all to persistentence context and filter on Java side?
Hey. THis is an excellent concept and I have been using it for the past year. However, it does not work if you upgrade tp Spring Boot 3.0. Hibernate annotations used are no longer supported in Hibernate 6.0. Do you have any idea on how to achieve the same using a different methodology