CINXE.COM
Encryption | Ebean
<!doctype html> <html lang="en"> <head> <title>Encryption | Ebean</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="shortcut icon" href="/images/favicon.ico"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto|Source+Sans+Pro|Ubuntu&display=swap"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous"> <link rel="stylesheet" href="/css/reset3.css"> <link rel="stylesheet" href="/css/site3.css"> <link rel="stylesheet" href="/css/pygments3.css"> </head> <body> <div id="main"> <div id="banner"> <header> <nav id="top"> <h1 id="breadcrumb"> <a class="nav-logo" href="/"><img src="/images/logo-200.png" height="35"></a> <a href="/docs">Documentation</a><span class="sep"> / </span><a href="/docs/features/">Features</a><span class="sep"> / </span><span class="last">Encryption</span> </h1> <ul> <li><a onclick="toggleTheme();" title="switch dark light theme"><i class="fas fa-adjust"></i></a></li> </ul> </nav> </header> </div> <div class="grid grid-docs"> <aside> <nav class="side"> <ul> <li class="nav0 "> <a href="/docs/getting-started">Getting started</a> </li> <li class="nav0 "> <a href="/docs/intro">Introduction</a> </li> <li class="nav0 active"> <a class="active" href="/docs">Documentation</a> <ul> <li class="nav1 "> <a href="/docs/best-practice">Best practice</a> </li> <li class="nav1 "> <a href="/docs/query">Query</a> </li> <li class="nav1 "> <a href="/docs/persist">Persist</a> </li> <li class="nav1 "> <a href="/docs/transactions">Transactions</a> </li> <li class="nav1 "> <a href="/docs/mapping">Mapping</a> </li> <li class="nav1 "> <a href="/docs/ddl-generation">DDL & Migrations</a> </li> <li class="nav1 "> <a href="/docs/logging">Logging</a> </li> <li class="nav1 "> <a href="/docs/testing">Testing</a> </li> <li class="nav1 "> <a href="/docs/read-replicas">Read Replicas</a> </li> <li class="nav1 "> <a href="/docs/database">Database platforms</a> </li> <li class="nav1 "> <a href="/docs/multi-database">Multiple databases</a> </li> <li class="nav1 "> <a href="/docs/kotlin">Kotlin</a> </li> <li><a href="/docs/tuning">Tuning</a></li> <li class="nav1 active"> <a class="active" href="/docs/features">Features</a> <ul class="nav"> <li > <a href="/docs/features/l2cache">L2 Cache</a> </li> <li > <a href="/docs/features/elasticsearch">Elasticsearch</a> </li> <li > <a href="/docs/features/json-in-db">@DbJson</a> </li> <li > <a href="/docs/features/softdelete">Soft Delete</a> </li> <li class="active"> <a class="active" href="/docs/features/encryption">Encryption</a> <ul class="nav nav-scroll"> <li > <a href="#client-encryption">Client side</a> </li> <li > <a href="#db-encryption">Database side</a> </li> <li > <a href="#types">Supported types</a> </li> <li > <a href="#limitations">Limitations</a> </li> <li > <a href="#configuration">Configuration</a> </li> <li > <a href="#internals">Internals</a> </li> </ul> </li> <li > <a href="/docs/features/who">@WhoModified / @WhoCreated</a> </li> <li > <a href="/docs/features/history">SQL2011 History</a> </li> <li > <a href="/docs/features/changelog">ChangeLog</a> </li> <li > <a href="/docs/features/readauditing">Read auditing</a> </li> <li > <a href="/docs/features/eventlistening">Event Listening</a> </li> </ul> </li> </ul> </li> <li class="nav0 "> <a href="/support">Getting help</a> </li> <li class="nav0 "> <a target="_blank" href="/apidoc/13">API Javadoc</a> </li> <li class="nav0 "> <a href="/videos">Videos</a> </li> <li class="nav0 "> <a href="/docs/upgrading">Upgrading</a> </li> <li class="nav0 "> <a href="/releases">Releases</a> </li> </ul> </nav> </aside> <article> <form action="https://www.google.com/search" method="get" class="inline-form"> <input type="hidden" name="as_sitesearch" value="ebean.io"> <div id="page-search"> <div class="input-group"> <input class="frm" name="q" id="searchinput" type="text" placeholder="Search... (press 's' to focus)" data-placeholder-focus="Search... (use '↑', '↓' and '⏎' to select results)" data-placeholder-blur="Search... (press 's' to focus)" autocomplete="off"> <div class="input-group-btn"> <button class="frm" type="submit"><i class="fas fa-search"></i></button> </div> </div> <div id="page-search-results" style="display: none;"> <ul id="search-results-container" class="search-results"><li class=" active"><a href="/docs" title="Docs"><span style="color:#777;">Docs</span> Documentation </a></li><li class=""><small style="color:#999;">And 101 more...</small></li></ul> </div> </div> </form> <h2 id="encryption">Encryption</h2> <p> Ebean has support for transparent Encryption/Decryption of specific properties. We make mark the properties we want encrypted with <code>@Encrypted</code> and these properties will be automatically encrypted and decrypted as needed. </p> <p> 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 <code>where</code> and <code>order by</code> clause. Effectively the encryption of the property is fully transparent to the application. </p> <p> When we use client/application side encryption/decryption then we should only use the <b>EQ</b> (equal to) operator in the <code>where</code> clause. </p> <h2 id="client-encryption">Client/Application encryption</h2> <p> When using client/application encryption the properties are encrypted/decrypted by a Java function - an implementation of the <code>io.ebean.config.Encryptor</code> interface. The default implementation uses AES 128 bit based implementation and we can also configure Ebean to use another implementation. </p> <p> Properties encrypted with client/application encryption should <b>ONLY</b> be used with <b>EQ (equal to)</b> operator in <code>where</code> clauses - other operators should not be used with client side encrypted properties. </p> <div class="syntax java"><div class="highlight"><pre><span></span><span class="kn">package</span> <span class="nn">io.ebean.config</span><span class="o">;</span> <span class="cm">/**</span> <span class="cm"> * Used for Java side encryption of properties when DB encryption is not used.</span> <span class="cm"> *</span> <span class="cm"> * By default this is used on non-varchar types such as Blobs.</span> <span class="cm"> */</span> <span class="kd">public</span> <span class="kd">interface</span> <span class="nc">Encryptor</span> <span class="o">{</span> <span class="cm">/**</span> <span class="cm"> * Encrypt the data using the key.</span> <span class="cm"> */</span> <span class="kt">byte</span><span class="o">[]</span> <span class="nf">encrypt</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">data</span><span class="o">,</span> <span class="n">EncryptKey</span> <span class="n">key</span><span class="o">);</span> <span class="cm">/**</span> <span class="cm"> * Decrypt the data using the key.</span> <span class="cm"> */</span> <span class="kt">byte</span><span class="o">[]</span> <span class="nf">decrypt</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">data</span><span class="o">,</span> <span class="n">EncryptKey</span> <span class="n">key</span><span class="o">);</span> <span class="cm">/**</span> <span class="cm"> * Encrypt the formatted string value using a key.</span> <span class="cm"> */</span> <span class="kt">byte</span><span class="o">[]</span> <span class="nf">encryptString</span><span class="o">(</span><span class="n">String</span> <span class="n">formattedValue</span><span class="o">,</span> <span class="n">EncryptKey</span> <span class="n">key</span><span class="o">);</span> <span class="cm">/**</span> <span class="cm"> * Decrypt the data returning a formatted string value using a key.</span> <span class="cm"> */</span> <span class="n">String</span> <span class="nf">decryptString</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">data</span><span class="o">,</span> <span class="n">EncryptKey</span> <span class="n">key</span><span class="o">);</span> <span class="o">}</span> </pre></div> </div> <h2 id="db-encryption">Database encryption</h2> <p> When using Database side encryption/decryption we use database stored procedures to encrypt and decrypt the properties. For example with Postgres Ebean uses <code>pgp_sym_encrypt()</code> and <code>pgp_sym_decrypt()</code>. </p> <h4>Database encryption functions</h4> <p> The default DB encryption decryption functions used for each platform are: </p> <ul> <li><b>Postgres, YugabyteDB</b> - pgp_sym_decrypt(), pgp_sym_encrypt()</li> <li><b>MySql, MariaDB</b> - aes_encrypt(), aes_decrypt()</li> <li><b>SQL Server</b> - DecryptByPassPhrase(), EncryptByPassPhrase()</li> <li><b>Oracle</b> - requires dbms_crypto and uses custom functions for encryption and decryption</li> <li><b>H2</b> - encrypt() and decrypt() with 'AES' option</li> </ul> <h2 id="types">Supported types</h2> <p> The following are the types supported by database encryption. Any type not supported by database encryption will use client/application encryption. </p> <ul> <li>Enum (if based on VARCHAR)</li> <li>String (VARCHAR, CHAR, CLOB, LONGVARCHAR)</li> <li>Date types - LocalDate, Date, Joda LocalDate</li> <li>Timestamp types - Timestamp, Instant, OffsetDateTime, ZonedDateTime</li> </ul> <p> Important: The following types are currently not supported: </p> <ul> <li>primitive types</li> <li>Timestamps</li> </ul> <h2 id="encryptKeyManager">EncryptKeyManager</h2> <p> 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. </p> <p> We must supply an implementation of the EncryptKeyManager. </p> <div class="syntax java"><div class="highlight"><pre><span></span><span class="kn">package</span> <span class="nn">io.ebean.config</span><span class="o">;</span> <span class="cm">/**</span> <span class="cm"> * Determine keys used for encryption and decryption.</span> <span class="cm"> */</span> <span class="nd">@FunctionalInterface</span> <span class="kd">public</span> <span class="kd">interface</span> <span class="nc">EncryptKeyManager</span> <span class="o">{</span> <span class="cm">/**</span> <span class="cm"> * Initialise the EncryptKeyManager.</span> <span class="cm"> *</span> <span class="cm"> * This gives the EncryptKeyManager the opportunity to get keys etc.</span> <span class="cm"> */</span> <span class="k">default</span> <span class="kt">void</span> <span class="nf">initialise</span><span class="o">()</span> <span class="o">{}</span> <span class="cm">/**</span> <span class="cm"> * Return the key used to encrypt and decrypt a property mapping to the given</span> <span class="cm"> * table and column.</span> <span class="cm"> */</span> <span class="n">EncryptKey</span> <span class="nf">getEncryptKey</span><span class="o">(</span><span class="n">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="n">String</span> <span class="n">columnName</span><span class="o">);</span> <span class="o">}</span> </pre></div> </div> <h2 id="encrypted">@Encrypted</h2> <p> Mark a property to be encrypted with the <code>@Encrypted</code> annotation. By default the property will be <code>dbEncryption = true</code> and we explicitly set that false for client/application side encryption. </p> <div class="syntax java"><div class="highlight"><pre><span></span><span class="c1">// use database side encryption</span> <span class="nd">@Encrypted</span> <span class="n">String</span> <span class="n">name</span><span class="o">;</span> <span class="c1">// use client side encryption (not db functions)</span> <span class="nd">@Encrypted</span><span class="o">(</span><span class="nx">dbEncryption</span><span class="o">=</span><span class="kc">false</span><span class="o">)</span> <span class="n">String</span> <span class="n">description</span><span class="o">;</span> </pre></div> </div> <h4>Example</h4> <div class="syntax java"><div class="highlight"><pre><span></span><span class="c1">// Use @Encrypted annotation to mark the encrypted properties</span> <span class="nd">@Entity</span> <span class="nd">@Table</span><span class="o">(</span><span class="nx">name</span><span class="o">=</span><span class="s">"patient"</span><span class="o">)</span> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">Patient</span> <span class="o">{</span> <span class="nd">@Id</span> <span class="kt">long</span> <span class="n">id</span><span class="o">;</span> <span class="c1">// database side encryption</span> <span class="nd">@Encrypted</span> <span class="n">String</span> <span class="n">name</span><span class="o">;</span> <span class="c1">// client side encryption</span> <span class="nd">@Lob</span> <span class="nd">@Encrypted</span><span class="o">(</span><span class="nx">dbEncryption</span><span class="o">=</span><span class="kc">false</span><span class="o">)</span> <span class="n">String</span> <span class="n">description</span><span class="o">;</span> <span class="nd">@Encrypted</span> <span class="n">LocalDate</span> <span class="n">dob</span><span class="o">;</span> <span class="o">...</span> </pre></div> </div> <h2 id="limitations">Limitations</h2> <ul> <li> Properties using Java client encryption should only use <b>EQ</b> (equal to) operator in WHERE clauses </li> <li> DB Encryption support built in for H2, Postgres, YugabyteDB, MySql, MariaDB, Sql Server and Oracle. </li> <li> We can not use Encryption with positioned (1,2,3...) parameters. We must use named parameters or the criteria api to define queries. </li> </ul> <h3>Examples:</h3> <div class="syntax java"><div class="highlight"><pre><span></span><span class="n">List</span><span class="o"><</span><span class="n">Patient</span><span class="o">></span> <span class="n">list</span> <span class="o">=</span> <span class="k">new</span> <span class="n">QPatient</span><span class="o">()</span> <span class="o">.</span><span class="na field">name</span><span class="o">.</span><span class="na">eq</span><span class="o">(</span><span class="s">"Rob"</span><span class="o">)</span> <span class="o">.</span><span class="na">findList</span><span class="o">();</span> </pre></div> </div> <p> Results in the following Postgres SQL: </p> <div class="syntax sql"><div class="highlight"><pre><span></span><span class="k">select</span> <span class="n">t0</span><span class="p">.</span><span class="n">id</span><span class="p">,</span> <span class="n">pgp_sym_decrypt</span><span class="p">(</span><span class="n">t0</span><span class="p">.</span><span class="n">name</span><span class="p">,</span><span class="o">?</span><span class="p">)</span> <span class="k">from</span> <span class="n">patient</span> <span class="n">t0</span> <span class="k">where</span> <span class="n">pgp_sym_decrypt</span><span class="p">(</span><span class="n">t0</span><span class="p">.</span><span class="n">name</span><span class="p">,</span><span class="o">?</span><span class="p">)</span> <span class="o">=</span> <span class="o">?</span> </pre></div> </div> <h2 id="configuration">Configuration</h2> <p> Specify the EncryptKeyManager implementation in the ebean.properties file like below: </p> <div class="syntax properties"><div class="highlight"><pre><span></span><span class="na">ebean.encryptKeyManager</span><span class="o">=</span><span class="s">org.example.BasicEncyptKeyManager</span> </pre></div> </div> <p> Programmatically configure using DatabaseConfig. </p> <div class="syntax java"><div class="highlight"><pre><span></span><span class="n">DatabaseConfig</span> <span class="n">config</span> <span class="o">=</span> <span class="n">DatabaseConfig</span><span class="o">();</span> <span class="o">...</span> <span class="n">EncryptKeyManager</span> <span class="n">keyManager</span> <span class="o">=</span> <span class="o">...;</span> <span class="n">config</span><span class="o">.</span><span class="na">setEncryptKeyManager</span><span class="o">(</span><span class="n">keyManager</span><span class="o">);</span> <span class="o">...</span> <span class="n">Database</span> <span class="n">database</span> <span class="o">=</span> <span class="n">DatabaseFactory</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="n">config</span><span class="o">);</span> </pre></div> </div> <p> An example EncryptKeyManager is: </p> <div class="syntax java"><div class="highlight"><pre><span></span><span class="kn">package</span> <span class="nn">org.example.encrypt</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">io.ebean.config.EncryptKey</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">io.ebean.config.EncryptKeyManager</span><span class="o">;</span> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">BasicEncyptKeyManager</span> <span class="kd">implements</span> <span class="n">EncryptKeyManager</span> <span class="o">{</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">initialise</span><span class="o">()</span> <span class="o">{</span> <span class="c1">// can load keys or initialise source resources ...</span> <span class="o">}</span> <span class="kd">public</span> <span class="n">EncryptKey</span> <span class="nf">getEncryptKey</span><span class="o">(</span><span class="n">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="n">String</span> <span class="n">columnName</span><span class="o">)</span> <span class="o">{</span> <span class="c1">// get the key for the given table and column</span> <span class="n">String</span> <span class="n">keyValue</span> <span class="o">=</span> <span class="o">...;</span> <span class="k">return</span> <span class="k">new</span> <span class="n">BasicEncryptKey</span><span class="o">(</span><span class="n">keyValue</span><span class="o">);</span> <span class="o">}</span> <span class="o">}</span> </pre></div> </div> <h2 id="internals">Internals</h2> <p> 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. </p> <p> 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. </p> </article> </div> </div> <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> <script src="/js/site3.js"></script> <script src="/js/search3.js"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=UA-75181644-1"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-75181644-1'); </script> </body> </html>