Encryption
Ebean has support for transparent Encryption/Decryption of specific properties.
We make mark the properties we want encrypted with @Encrypted
and these properties will be automatically encrypted and decrypted as needed.
Encryption/decryption can occur either on the client/application side or by
the database. When we use database encryption then we can use these properties
in queries as part of the where
and order by
clause.
Effectively the encryption of the property is fully transparent to the application.
When we use client/application side encryption/decryption then we should only use the
EQ (equal to) operator in the where
clause.
Client/Application encryption
When using client/application encryption the properties are encrypted/decrypted by
a Java function - an implementation of the io.ebean.config.Encryptor
interface.
The default implementation uses AES 128 bit based implementation and we can also configure
Ebean to use another implementation.
Properties encrypted with client/application encryption should ONLY be used with EQ (equal to) operator
in where
clauses - other operators should not be used with client side encrypted properties.
package io.ebean.config;
/**
* Used for Java side encryption of properties when DB encryption is not used.
*
* By default this is used on non-varchar types such as Blobs.
*/
public interface Encryptor {
/**
* Encrypt the data using the key.
*/
byte[] encrypt(byte[] data, EncryptKey key);
/**
* Decrypt the data using the key.
*/
byte[] decrypt(byte[] data, EncryptKey key);
/**
* Encrypt the formatted string value using a key.
*/
byte[] encryptString(String formattedValue, EncryptKey key);
/**
* Decrypt the data returning a formatted string value using a key.
*/
String decryptString(byte[] data, EncryptKey key);
}
Database encryption
When using Database side encryption/decryption we use database stored procedures to encrypt and decrypt
the properties. For example with Postgres Ebean uses pgp_sym_encrypt()
and
pgp_sym_decrypt()
.
Database encryption functions
The default DB encryption decryption functions used for each platform are:
- Postgres, YugabyteDB - pgp_sym_decrypt(), pgp_sym_encrypt()
- MySql, MariaDB - aes_encrypt(), aes_decrypt()
- SQL Server - DecryptByPassPhrase(), EncryptByPassPhrase()
- Oracle - requires dbms_crypto and uses custom functions for encryption and decryption
- H2 - encrypt() and decrypt() with 'AES' option
Supported types
The following are the types supported by database encryption. Any type not supported by database encryption will use client/application encryption.
- Enum (if based on VARCHAR)
- String (VARCHAR, CHAR, CLOB, LONGVARCHAR)
- Date types - LocalDate, Date, Joda LocalDate
- Timestamp types - Timestamp, Instant, OffsetDateTime, ZonedDateTime
Important: The following types are currently not supported:
- primitive types
- Timestamps
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.
We must supply an implementation of the EncryptKeyManager.
package io.ebean.config;
/**
* Determine keys used for encryption and decryption.
*/
@FunctionalInterface
public interface EncryptKeyManager {
/**
* Initialise the EncryptKeyManager.
*
* This gives the EncryptKeyManager the opportunity to get keys etc.
*/
default void initialise() {}
/**
* Return the key used to encrypt and decrypt a property mapping to the given
* table and column.
*/
EncryptKey getEncryptKey(String tableName, String columnName);
}
@Encrypted
Mark a property to be encrypted with the @Encrypted
annotation.
By default the property will be dbEncryption = true
and we
explicitly set that false for client/application side encryption.
// use database side encryption
@Encrypted
String name;
// use client side encryption (not db functions)
@Encrypted(dbEncryption=false)
String description;
Example
// Use @Encrypted annotation to mark the encrypted properties
@Entity
@Table(name="patient")
public class Patient {
@Id
long id;
// database side encryption
@Encrypted
String name;
// client side encryption
@Lob
@Encrypted(dbEncryption=false)
String description;
@Encrypted
LocalDate dob;
...
Limitations
- Properties using Java client encryption should only use EQ (equal to) operator in WHERE clauses
- DB Encryption support built in for H2, Postgres, YugabyteDB, MySql, MariaDB, Sql Server and Oracle.
- We can not use Encryption with positioned (1,2,3...) parameters. We must use named parameters or the criteria api to define queries.
Examples:
List<Patient> list =
new QPatient()
.name.eq("Rob")
.findList();
Results in the following Postgres SQL:
select t0.id, pgp_sym_decrypt(t0.name,?)
from patient t0
where pgp_sym_decrypt(t0.name,?) = ?
Configuration
Specify the EncryptKeyManager implementation in the ebean.properties file like below:
ebean.encryptKeyManager=org.example.BasicEncyptKeyManager
Programmatically configure using DatabaseConfig.
DatabaseConfig config = DatabaseConfig();
...
EncryptKeyManager keyManager = ...;
config.setEncryptKeyManager(keyManager);
...
Database database = DatabaseFactory.create(config);
An example EncryptKeyManager is:
package org.example.encrypt;
import io.ebean.config.EncryptKey;
import io.ebean.config.EncryptKeyManager;
public class BasicEncyptKeyManager implements EncryptKeyManager {
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
Ebean is detecting when an encrypted property is being used. 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 we can not use encryption with 'positioned' parameters because it can effectively change the position of other parameters. We can use named parameters or the criteria api for building queries but, we can't use positioned (1,2,3,4..) parameters.