Jasypt provides the jasypt-hibernate3, jasypt-hibernate4 and jasypt-hibernate5 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.
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.
Java type | SQL type | Jasypt Hibernate type (org.jasypt.hibernate*.type) | Specific features |
---|---|---|---|
String | VARCHAR, CLOB, TEXT | EncryptedStringType | |
byte[] | VARBINARY, BLOB | EncryptedBinaryType | Honors hibernate.jdbc.use_streams_for_binary. |
Byte | VARCHAR, CLOB, TEXT | EncryptedByteAsStringType | |
Short | VARCHAR, CLOB, TEXT | EncryptedShortAsStringType | |
Integer | VARCHAR, CLOB, TEXT | EncryptedIntegerAsStringType | |
Long | VARCHAR, CLOB, TEXT | EncryptedLongAsStringType | |
BigInteger | NUMERIC, NUMBER | EncryptedBigIntegerType | |
BigInteger | VARCHAR, CLOB, TEXT | EncryptedBigIntegerAsStringType | |
Float | VARCHAR, CLOB, TEXT | EncryptedFloatAsStringType | |
Double | VARCHAR, CLOB, TEXT | EncryptedDoubleAsStringType | |
BigDecimal | NUMERIC, NUMBER | EncryptedBigDecimalType | Needs an additional decimalScale property. |
BigDecimal | VARCHAR, CLOB, TEXT | EncryptedBigDecimalAsStringType | |
Boolean | VARCHAR, CLOB, TEXT | EncryptedBoleanAsStringType | |
Date | VARCHAR, CLOB, TEXT | EncryptedDateAsStringType | |
Calendar | VARCHAR, CLOB, TEXT | EncryptedCalendarAsStringType | Offers 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).
Setting jasypt to encrypt data with hibernate requires two separate actions:
The Hibernate mapping file can be configured in two different ways:
<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).
<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>
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.
<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>
StandardPBEStringEncryptor strongEncryptor = new StandardPBEStringEncryptor(); ... HibernatePBEEncryptorRegistry registry = HibernatePBEEncryptorRegistry.getInstance(); registry.registerPBEStringEncryptor("strongHibernateStringEncryptor", strongEncryptor);
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; }
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:
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.