Transparent Encryption with Ebean

Ebean v2.4 adds support for automatic Encryption/Decryption of properties. The result is that without changing your application code some of your properties on your entities can stored in encrypted form in the DB.

DB Encryption and "Java client Encryption"

  • The encryption can be performed by Database functions or on the Java side (Java client encryption).
  • Properties that are encrypted using Database functions can be used in Query WHERE clauses.
  • Properties that are encrypted using "Java client Encryption" can NOT be used in Query WHERE clauses.

DB Encryption of String and "Date" types

Currently DB Encryption for H2, Postgres, MySql and Oracle can be used on String types and "Date" types (java.sql.Date, Joda DateMidnight, Joda LocalDate).

Any type not supported by DB Encryption functions uses "Java client Encryption".

DB Encryption Functions

The default DB encryption decryption functions used are:

  • H2: ENCRYPT() and DECRYPT() with 'AES' option
  • MySql: AES_ENCRYPT() and AES_DECRYPT()
  • Postgres: requires pgcryto and uses PGP_SYM_ENCRYPT() and PGP_SYN_DECRYPT()
  • Oracle: requires dbms_crypto and uses custom functions for encryption and decryption

Encryptor (Java client encryption implementation)

When Java client encryption occurs the "Encryptor" interface is used. By default Ebean has a AES 128 bit based implementation but you can also configure Ebean to use your own implementation if you wish.

EncryptKeyManager

Whenever a property is encrypted or decrypted a "Key" must be used. Ebean will internally ask the EncryptKeyManager for a key given the table and column name.

You must supply an implementation of the EncryptKeyManager.

Deployment: @Encrypted and EncryptDeployManager

You can mark a property to be Encrypted programmatically via EncryptDeployManager, or put the @Encrypted annotation on the bean property or a combination of the two.

By default a property will use DB encryption if it is supported (based on its type - String or 'Dates' basically). If you want to ensure a property uses Java encryption you can specify dbEncryption=false on the annotation or EncryptDeploy. You may want to do this so that the CPU cycles for encryption/decryption occur on the Java process rather than the DB process.

Your application code does not change That's it. Your code to query, insert, update and delete etc does not change and Ebean automatically does the encryption/decryption behind the scenes.


// Use @Encrypted annotation to mark the encrypted properties

...
@Entity
@Table(name="pm_patient")
public class Patient {
    
    @Id
    Integer id;
    
    @Encrypted
    String name;
   
    // use client side encryption (not db functions) 
    @Lob
    @Encrypted(dbEncryption=false)
    String description;
    
    @Encrypted
    Date dob;
    ...

Limitations

  • Properties using Java client encryption can NOT be used in WHERE clauses
  • Only DB Encryption support built in for H2, Postgres, MySql and Oracle.
  • You can not use Encryption with positioned (1,2,3...) parameters. You must use named parameters or the criteria api to define queries.

Examples:


List<Patient> list  =
    Ebean.find(Patient.class)
        .select("id, name")
        .where().eq("name", "Rob")
        .findList();

Results in the following SQL:

<sql summary='Patient' >
select e.id as c0, pgp_sym_decrypt(e.name,?) as c1
from pm_patient e
where pgp_sym_decrypt(e.description,?) = ?
<sql>

Configuraton:

You can specify the EncryptKeyManager implementation in the ebean.properties file like below:


# ebean.properties - specify the Key Manager
ebean.encryptKeyManager=com.avaje.tests.basic.encrypt.BasicEncyptKeyManager

Or if you are programmatically configuring an EbeanServer using ServerConfig, set the EncryptKeyManager.


// programmatically configure an EbeanServer
// with an EncryptKeyManager

ServerConfig config = ServerConfig();
...
EncryptKeyManager keyManager = ...;
config.setEncryptKeyManager(encyptKeyManager());
...
EbeanServer server = EbeanServerFactory.create(config);

A EncryptKeyManager:

package com.avaje.tests.basic.encrypt;

import com.avaje.ebean.config.EncryptKey;
import com.avaje.ebean.config.EncryptKeyManager;

public class BasicEncyptKeyManager implements EncryptKeyManager {

    /**
     * Initialise the key manager.
     */
    public void initialise() {
        // can load keys or initialise source resources ... 
    }

    public EncryptKey getEncryptKey(String tableName, String columnName) {
       
        // get the key for the given table and column
        String keyValue = ...;
        return new BasicEncryptKey(keyValue);
    }

}

Internals

What Ebean is doing internally is detecting when an encrypted property is being used. Internally it will call the EncryptKeyManager with the table and column of the property to get the encryption key. This key is then added as a bind variable to the prepared statement.

As the key is added as a bind variable into the statement you can not use encryption with 'ordered' parameters because it can effectively change the position of other parameters. You can use 'named' parameters or the criteria api for building queries - but you can't use positioned (1,2,3,4..) parameters.

Introduction User Guide (pdf) Install/Configure Public JavaDoc Whitepapers
General Database Specific Byte Code Deployment Annotations Features
Top Bugs Top Enhancements
woResponse