Security: Transparent encryption of persisted data (with Jasypt UserTypes)

    This article discusses the setup needed to store sensitive data with hibernate in an encrypted manner. For this purpose, the open source library Jasypt (Java Simplified Encryption) is used.

    Jasypt can be found at: http://www.jasypt.org

    The objectives are:

    • Data has to be encrypted when stored into the database and decrypted when retrieved.
    • Encryption and decryption operations should be transparent for the application's business logic.
    • Encryption mechanisms should be implemented as a Hibernate UserType, and thus set up and configured at the Hibernate mapping files.

     

    Encryptable data types

    The following data types can be transparently encrypted by Jasypt:

     

    Java typeSQL typeJasypt Hibernate typeSpecific 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, TEXTEncryptedBooleanAsStringType
    DateVARCHAR, CLOB, TEXTEncryptedDateAsStringType
    CalendarVARCHAR, CLOB, TEXTEncryptedCalendarAsStringTypeOffers an additional storeTimeZone property

     

    Steps

     

    1. Configure a Jasypt encryptor

    First of all, you will have to instantiate a Jasypt encryptor for, let's say, Strings, so that it can be used for performing the encryption operations from inside the Hibernate type system. Once created, you will have to register the encryptor for Hibernate:

       ...
       /*
        * Create and configure the encryptor
        */
       StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
       encryptor.setAlgorithm("PBEWithMD5AndDES"); // not really needed as it is the default
       encryptor.setPassword(myPassword);
       
       /*
        * Register the encryptor for use from within Hibernate types
        */
       HibernatePBEEncryptorRegistry registry = HibernatePBEEncryptorRegistry.getInstance();
       registry.registerPBEStringEncryptor("hibernateStringEncryptor",encryptor);
       ...
    

    You will have to make sure that this code gets executed before the first encryption or decryption operation is performed by the Hibernate types (for instance, in a webapp, with a ContextListener).

     

    2. Map your encrypted attributes

    Now, you will only have to declare the new type and use if at your mappings:

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
     
    <hibernate-mapping package="com.myapp">
    
      <typedef name="encryptedString" class="org.jasypt.hibernate.type.EncryptedStringType">
          <param name="encryptorRegisteredName">hibernateStringEncryptor</param>
      </typedef>
    
    
      <class name="UserData" table="USER_DATA" >
    
        <id name="id" column="ID">
            <generator class="native" />
        </id>
    
        <property name="login" column="LOGIN" type="string" />
        <property name="name" column="NAME" type="encryptedString" />
        <property name="email" column="EMAIL" type="encryptedString" />
        <property name="address" column="ADDRESS" type="encryptedString" />
    
      </class>
        
    </hibernate-mapping>
    

     

    Alternative: Direct configuration of encryptor at mapping

    Alternatively, you might prefer not to create, configure and register a Jasypt encryptor beforehand, but instead leave it all to the UserType's responsibility. (Note that this will reduce the flexibility of configuration you can get from jasypt encryptors, and let you with a basic set of configuration parameters.)

    In this case, you may only have to configure your mapping like this:

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
     
    <hibernate-mapping package="com.myapp">
    
      <typedef name="encryptedString" class="org.jasypt.hibernate.type.EncryptedStringType">
          <param name="algorithm">PBEWithMD5AndDES</param>
          <param name="password">thisisatest</param>
          <param name="keyObtentionIterations">1000</param>
      </typedef>
      
    
      <class name="UserData" table="USER_DATA" >
    
        <id name="id" column="ID">
            <generator class="native" />
        </id>
    
        <property name="login" column="LOGIN" type="string" />
        <property name="name" column="NAME" type="encryptedString" />
        <property name="email" column="EMAIL" type="encryptedString" />
        <property name="address" column="ADDRESS" type="encryptedString" />
    
      </class>
        
    </hibernate-mapping>
    

    This way, when the first data storage or retrieval operation is performed, the UserType object will automatically instantiate a StandardPBEStringEncryptor object, configure it with the specified parameters, and use it.


     

    More information

    There is much more about using Jasypt for Hibernate transparent encryption, which you can read at: