Integrating Jasypt with Hibernate 3.x or 4.x

Jasypt provides the jasypt-hibernate3 and jasypt-hibernate4 artifacts for Hibernate integration. Since jasypt 1.9.0, these artifacts must be added to your classpath separately.

These integration libraries include several Hibernate UserType implementations that allow one or several of the properties in a mapped Hibernate entity to be declared as being of an encrypted type. Types allowed to be stored as encrypted include strings, binaries (byte arrays), numeric types, booleans and dates.

Jasypt also provides two Connection Provider (org.hibernate.connection.ConnectionProvider) implementations which let the user declare the datasource parameters in an encrypted manner.

Transparent data encryption with Jasypt and Hibernate

Thanks to the use of custom UserType implementations, jasypt allows your applications to store encrypted data for their hibernate mapped entities, but in a completely transparent way for the application's logic.

This can be useful for encrypting personal data, private messages, etc, so that it is avoided that anyone with read access to the "critical" tables can read all of its contents.

For encryption at Hibernate, jasypt uses its password-based encryption capabilities, and any encryptor object implementing PBEStringEncryptor, PBEByteEncryptor, PBEBigIntegerEncryptor or PBEBigDecimalEncryptor can be used to encrypt data, even encryptors created by the user.

But encryption sets a limitation on your Hibernate usage: security standards establish that two different encryption operations on the same data should not return the same value (due to the use of a random salt). Because of this, none of the fields that are set to be encrypted when persisted can be a part of a WHERE clause in your search queries for the entity they belong to.

Encryption types

Java typeSQL typeJasypt Hibernate type (org.jasypt.hibernate*.type)Specific features
StringVARCHAR, CLOB, TEXTEncryptedStringType
byte[]VARBINARY, BLOBEncryptedBinaryTypeHonors hibernate.jdbc.use_streams_for_binary.
ByteVARCHAR, CLOB, TEXTEncryptedByteAsStringType
ShortVARCHAR, CLOB, TEXTEncryptedShortAsStringType
IntegerVARCHAR, CLOB, TEXTEncryptedIntegerAsStringType
LongVARCHAR, CLOB, TEXTEncryptedLongAsStringType
BigIntegerNUMERIC, NUMBEREncryptedBigIntegerType
BigIntegerVARCHAR, CLOB, TEXTEncryptedBigIntegerAsStringType
FloatVARCHAR, CLOB, TEXTEncryptedFloatAsStringType
DoubleVARCHAR, CLOB, TEXTEncryptedDoubleAsStringType
BigDecimalNUMERIC, NUMBEREncryptedBigDecimalTypeNeeds an additional decimalScale property.
BigDecimalVARCHAR, CLOB, TEXTEncryptedBigDecimalAsStringType
BooleanVARCHAR, CLOB, TEXTEncryptedBoleanAsStringType
DateVARCHAR, CLOB, TEXTEncryptedDateAsStringType
CalendarVARCHAR, CLOB, TEXTEncryptedCalendarAsStringTypeOffers an additional storeTimeZone property.

When storing an encrypted field, note that you will need a higher amount of space to store the result of the encryption than the space you would need to store the unencrypted piece of data. This is specially important when encrypting with EncryptedBigIntegerType or EncryptedBigDecimalType, as NUMBER and NUMERIC fields are defined by means of digits, not bytes, and thus the difference of size will be much higher than intuitively expected (normally you won't use a field smaller than a NUMERIC(60) to store an encrypted normal-size BigInteger).

Configuration

Setting jasypt to encrypt data with hibernate requires two separate actions:

  1. Configuring the Hibernate mapping.
  2. Providing the encryptor to Hibernate.
Configuring the Hibernate mapping

The Hibernate mapping file can be configured in two different ways:

  1. By extension, declaring the encryptor parameters in the mapping itself (password, algorithm, providerName, etc). This is not very recommended (the mapping file does not seem like a right place for a password) but can be useful in some situations. When this method is selected, the encryptor implementation used is always a StandardPBEStringEncryptor.
      <hibernate-mapping package="myapp">
        ...
        <typedef name="encryptedString" class="org.jasypt.hibernate4.type.EncryptedStringType">
          <param name="algorithm">PBEWithMD5AndTripleDES</param>
          <param name="password">jasypt</param>
          <param name="keyObtentionIterations">1000</param>
        </typedef>
        ...
        <class name="UserData" table="USER_DATA">
          ...
          <property name="address" column="ADDRESS" type="encryptedString" />
          ...
        <class>
        ...
      <hibernate-mapping>

    Note: only "password" is a required parameter.
    If this configuration method is used, it is not necessary to provide an encryptor to Hibernate (like explained below).

  2. By using a registered encryptor, which will be registered with a specific name. This way, all we will have to use in the mapping file is this name (encryptorRegisteredName).
      <hibernate-mapping package="myapp">
        ...
        <typedef name="encrypted" class="org.jasypt.hibernate4.type.EncryptedStringType">
          <param name="encryptorRegisteredName">strongHibernateStringEncryptor</param>
        </typedef>
        ...
        <class name="UserData" table="USER_DATA">
          ...
          <property name="address" column="ADDRESS" type="encrypted" />
          ...
        <class>
        ...
      <hibernate-mapping>
Providing the encryptor to Hibernate

If we have chosen to use the encryptorRegisteredName parameter in our Hibernate mapping file, we will need to bind somehow an encryptor object to that name. This can be done in two different manners, depending on whether we are using an IoC container like Spring or not.

Using this way of configuring encryption allows us to use pool-based versions of the encryptor (like org.jasypt.encryption.pbe.PooledPBEStringEncryptor), which will enhance performance in multi-processor/multi-core systems.

  • Using Spring we simply need to create our encryptor, and then a HibernatePBEEncryptor object to wrap it and set a registered name for it:
      <bean id="strongEncryptor"
        class="org.jasypt.encryption.pbe.PooledPBEStringEncryptor">
        <property name="algorithm">
            <value>PBEWithMD5AndTripleDES</value>
        </property>
        <property name="password">
            <value>jasypt</value>
        </property>
        <property name="poolSize">
            <value>4</value>
        </property>
      </bean>
      
      <bean id="hibernateStringEncryptor"
        class="org.jasypt.hibernate4.encryptor.HibernatePBEStringEncryptor">
        <property name="registeredName">
            <value>strongHibernateStringEncryptor</value>
        </property>
        <property name="encryptor">
            <ref bean="strongEncryptor" />
        </property>
      </bean>

    Also, we can do it all in the hibernateStringEncryptor declaration, if we don't want to use the strongEncryptor outside of Hibernate and we are OK with the standard encryptor implementation. Also be aware that this approach uses a StandardPBEStringEncryptor instead of a pool-based one, and so performace could be affected in multi-processor systems:

      <bean id="hibernateStringEncryptor"
        class="org.jasypt.hibernate4.encryptor.HibernatePBEStringEncryptor">
        <property name="registeredName">
            <value>strongHibernateStringEncryptor</value>
        </property>
        <property name="algorithm">
            <value>PBEWithMD5AndTripleDES</value>
        </property>
        <property name="password">
            <value>jasypt</value>
        </property>
      </bean>
  • Without Spring, we will have to use the HibernatePBEEncryptorRegistry singleton directly, registering our encryptor at application initialization like this (for example, inside a ServletContextListener for a webapp):
      StandardPBEStringEncryptor strongEncryptor = new StandardPBEStringEncryptor();
      ...
      HibernatePBEEncryptorRegistry registry =
          HibernatePBEEncryptorRegistry.getInstance();
      registry.registerPBEStringEncryptor("strongHibernateStringEncryptor", strongEncryptor);
Using annotations

Alternatively, we may have chosen to use annotations for mapping our entities instead of separate XML mapping files. If it has been so, we can still use jasypt to encrypt our data.

All we will have to do is, first, define the encryption type with a @TypeDef annotation, which could be either inside the persisted entity class or inside a @TypeDefs declaration in a separate package-info.java file:

@TypeDef(
    name="encryptedString", 
    typeClass=EncryptedStringType.class, 
    parameters= {
        @Parameter(name="encryptorRegisteredName", value="myHibernateStringEncryptor")
    }
)

...and then simply map our property with the already declared type:

    @Type(type="encryptedString")
    public String getAddress() {
        return address;
    }

Encrypting the database password in hibernate.cfg.xml

For those applications that define datasources in Hibernate's hibernate.cfg.xml file, Jasypt provides two Connection Provider (org.hibernate.connection.ConnectionProvider) implementations which let the user declare the datasource parameters (driver, url, username and password) in an encrypted manner:

  • org.jasypt.hibernate3|hibernate4.connectionprovider.EncryptedPasswordDriverManagerConnectionProvider, which extends Hibernate's Driver Manager connection provider (a very simplistic pool implementation).
  • org.jasypt.hibernate3|hibernate4.connectionprovider.EncryptedPasswordC3P0ConnectionProvider, which extends Hibernate's C3P0-based connection provider.

They are used like this in hibernate.cfg.xml:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE hibernate-configuration PUBLIC 
   "-//Hibernate/Hibernate Configuration DTD//EN" 
   "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
    
<hibernate-configuration>
  <session-factory>
    
    <property name="connection.provider_class">
      org.jasypt.hibernate4.connectionprovider.EncryptedPasswordDriverManagerConnectionProvider
    </property>
    <property name="connection.encryptor_registered_name">
      configurationHibernateEncryptor
    </property>
    
    <property name="connection.url">jdbc:mysql://localhost/reportsdb</property>
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="connection.username">reportsUser</property>
    <property name="connection.password">ENC(G6N718UuyPE5bHyWKyuLQSm02auQPUtm)</property>
    <property name="connection.pool_size">12</property>

    <property name="show_sql">true</property>
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    
    <!-- Mappings etc... -->
        
   </session-factory>
</hibernate-configuration>

In this configuration, Hibernate is told to use Jasypt's DriverManager-based connection provider and is passed a set of configuration parameters which contain an encrypted value, the connection.password property. Then, Hibernate is also told about which is the encryptor object to be used for decrypting the encrypted parameters (connection.encryptor_registered_name).

This encryptor object should have been registered beforehand as a Hibernate Encryptor, as explained in the 'Transparent data encryption' section.