How to encrypt and decrypt data with Hibernate

(Last Updated On: January 4, 2018)


Today, one of my Twitter followers sent me the following StackOverflow question, and, while answering it, I realized that it definitely deserves a post of its own.

In this post, I will explain how you can encrypt and decrypt data with Hibernate.

PostgreSQL crypto module

Because the StackOverflow question mentions PostgreSQL, we first need to enable the pgcrypto extension. For this purpose, we need to execute the following statement:


The pgcrypto will allow us to use the pgp_sym_encrypt and pgp_sym_decrypt functions.

Domain Model

Assuming we have the following entity:


The storage column needs to be encrypted upon being written and decrypted during a read operation.

@ColumnTransformer annotation to the rescue!

Luckily, Hibernate offers the @ColumnTransformer annotation which was added exactly for this type of scenarios.

Therefore, the Vault mapping looks like this:

@Entity(name = "Vault")
public class Vault {

    private Long id;

        read =  "pgp_sym_decrypt(" +
                "    storage, " +
                "    current_setting('encrypt.key')" +
        write = "pgp_sym_encrypt( " +
                "    ?, " +
                "    current_setting('encrypt.key')" +
                ") "
    @Column(columnDefinition = "bytea")
    private String storage;

    //Getter and setters omitted for brevity

Because hard-coding the encryption key in the mapping does not sound like a very good idea, we will use the PostgreSQL support for user-defined settings instead.

So, the encrypt.key is stored in postgresql.conf configuration file:

encrypt.key = 'Wow! So much security.'

Testing time

When persisting a Vault entity:

Vault user = new Vault();


Hibernate is going to encrypt the column, so if you select it with a native SQL query:

String encryptedStorage = (String) entityManager
    "select encode(storage, 'base64') " +
    "from Vault " +
    "where id = :id")
.setParameter("id", 1L)
.getSingleResult();"Encoded storage: {}", encryptedStorage);

You are going to see a value like this:

-- Encoded storage: ww0EBwMC3If4VmIUn2x+0j4BKrKR9j0GFpg87Qoz/v21etflhGPE6l9p7O5Sz9yOhynbvr+gwncW

However, when loading the entity with Hibernate:

Vault vault = entityManager.find( Vault.class, 1L );
assertEquals("my_secret_key", vault.getStorage());

The storage attribute is properly decrypted back to the original value.

If you enjoyed this article, I bet you are going to love my book as well.


As I explained in my book, High-Performance Java Persistence, if you don’t take advantage of the underlying JPA provider or relational database capabilities, you are going to lose lots of features, like easy-peasy encryption.

Subscribe to our Newsletter

* indicates required
10 000 readers have found this blog worth following!

If you subscribe to my newsletter, you'll get:
  • A free sample of my Video Course about running Integration tests at warp-speed using Docker and tmpfs
  • 3 chapters from my book, High-Performance Java Persistence, 
  • a 10% discount coupon for my book. 
Get the most out of your persistence layer!


10 thoughts on “How to encrypt and decrypt data with Hibernate

  1. Hello Vlad.
    Thank you very much for this article. I do have one question. Is there a way for me to encrypt data on specific Postgres schema only or for specific spring profiles?

    1. Yes, of course. But for that, you need to externalize the encryption mappings to orm.xml as explained in this article. The annotation mappings can stay without any encryption, and, justs for production, you can configure the Spring profiles to load the orm.xml file as well. In the same manner, you can target database schemas as well.

  2. @Vlad
    Thanks for the answer. I would like to ask a question linked to this answer. Instead of using this utility if we use Hibernate interceptors to do the encryption/decryption then do you think that would be less performant than using the @ColumnTransformer approach.

    The reason this is needed is that for different customers data needs to be encrypted using a different key, and i don’t see a mechanism how the keys for the customers can be resolved using the @ColumnTransformer approach

  3. Thanks for this article Vlad. Using this method, the encryption key will be hard-coded and embedded within the compiled application. An attacker who gained access to the DB AND application would still be able to decrypt the data. Of course, in many scenarios, that would be an acceptable risk.

    I’m interested in taking it one step further, so that the application has to dynamically fetch the encryption key from a web service on startup and store it in memory. This would allow the encryption key to be revoked in the event that e.g. the hardware is stolen.

    I’m guessing that in that scenario, I won’t be able to use @ColumnTransformer, and instead would implement it using a custom user-type (@Type) and handle the encryption/decryption in the java layer?

    1. In my article, the key was not hardcoded at all. In fact, it was stored in PostgreSQL configs. If an attacker breaks into your database OS server, it would be a disaster from a security perspective.

      1. He don’t need to broke your database OS. If he access to data he can read your key with a simple query “select current_setting(‘encrypt.key’) from foo”.

        In this solution the data and key are accessibles in same way so any crackers access to data can access to the key.

        I forgotten anything?

      2. If an attacker gets access to the database connection, it’s already too late since you either allowed SQL Injection attacks or exposed the database to the outside world.

        You can avoid storing the setting in postgresql.conf and just set it as a session variable at the connection pool level while letting the application to store and load the encryption key.

  4. Hello Vlad, great article.

    However, I guess it would be better to decrypt/encrypt data in one of JPA layers, as in your approach data is decrypted at db level and transported to application in plain text. What do you think ?


    1. Usually, you need several layers of protection, like encrypted hardware to ensure that backups don’t expose sensitive info, and also a SSL connection which solves the issue you mentioned here.

Leave a Reply

Your email address will not be published. Required fields are marked *