Introduction
This article explains how to store encrypt/decrypt credit cards, passwords, and SSN, etc. using Java Simplified Encryption(Jasypt) and Bouncy Castle framework through Hibernate. Java Simplified Encryption allows the developer to add basic encryption capabilities to his/her projects with minimum effort, and without the need of having deep knowledge on how cryptography works.
Background
Jasypt by itself does not implement nor distribute in any of its forms any cryptographic algorithms. It simply uses the algorithms already present in the users' Java installations via the Java Cryptography Extension. Jasypt has following features:
- High-security, standards-based encryption techniques, both for unidirectional and bidirectional encryption. Encrypt passwords, texts, numbers, binaries...
- Transparent integration with Hibernate.
- Suitable for integration into Spring-based applications and also transparently integrable with Spring Security.
- Integrated capabilities for encrypting the configuration of applications (i.e. datasources).
- Specific features for high-performance encryption in multi-processor/multi-core systems.
- Open API for use with any JCE provider.
- ...and much more
Bouncy Castle provides strongly in encryption and provides. Bouncy Castle has some features:
- A lightweight cryptography API for Java and C#.
- A provider for the Java Cryptography Extension and the Java Cryptography Architecture.
- A clean room implementation of the JCE 1.2.1.
- A library for reading and writing encoded ASN.1 objects.
- A light weight client-side TLS API.
- Generators for Version 1 and Version 3 X.509 certificates, Version 2 CRLs, and PKCS12 files.
- Generators for Version 2 X.509 attribute certificates.
- Generators/Processors for OpenPGP (RFC 2440).
- A signed jar version suitable for JDK 1.4-1.6 and the Sun JCE.
- For more information about Bouncy Castle.
System Requirements
- Database such as MySql, HSQL, Oracle 10g XE or later. I used Oracle 10g Express Edition in this article
- Spring 2.5
- Hibernate 3.3.2.GA
- Jasypt 1.5
- Bouncy Castle 1.4 or later
- IDE like Eclipse, NetBeans, etc.
Required Libraries
Screen shot here:
Implementation
Create PERSON Table
CREATE TABLE PERSON
(
ID NUMBER(19,0) PRIMARY KEY,
NAME VARCHAR2(50),
DOB DATE,
SSN VARCHAR2(50)
);
Create ORACLE Sequence
CREATE SEQUENCE PERSON_ID_SEQUENCE
START WITH 1000
INCREMENT BY 1
NOCACHE
NOCYCLE;
The PERSON_ID_SEQUENCE
use for inserting unique person records.
Create Person Domain Object
Create Person
class and implement Serializable
interface, and implement getter, and setter methods like POJO class.
package com.jasypt.domain.person;
import java.io.Serializable;
import java.util.Date;
public class Person implements Serializable
{
private Integer id;
private String name;
private Date date;
private String ssn;
public Person()
{
}
...
Create Person Hibernate Mapping File
="1.0"="UTF-8"
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<typedef name="encryptedString" class="org.jasypt.hibernate.type.EncryptedStringType">
<param name="encryptorRegisteredName">strongHibernateStringEncryptor</param>
</typedef>
<class name="com.jasypt.domain.person.Person" table="PERSON">
<id name="id" column="id" type="java.lang.Integer" >
<generator class="sequence">
<param name="sequence">PERSON_ID_SEQUENCE</param>
</generator>
</id>
<property name="name" type="java.lang.String" />
<property name="date" type="java.util.Date" column="DOB" />
<property name="ssn" type="encryptedString" />
</class>
</hibernate-mapping>
EncryptedStringType
class is a Hibernate UserType
implementation which allows transparent encryption of String
values during persistence of entities. Where encryptorRegisteredName
binds 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. In this article, it is injecting through spring. Here SSN property type is jasypt, i.e., encryptedString
. So when a property is jasypt type, then jasypt encrypt/decrypt is based on register provider and send/receive data from/to table. Check the code below.
Creating Encryptor Object, and Bouncy Castle in Spring
applicationContext-jasypt.xml
="1.0"="UTF-8"
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=" http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hibernateStringEncryptor"
class="org.jasypt.hibernate.encryptor.HibernatePBEStringEncryptor">
<property name="registeredName">
<value>strongHibernateStringEncryptor</value>
</property>
<property name="algorithm"><value>${encrypt.algorithm}</value></property>
<property name="providerName"><value>${encrypt.providerName}</value></property>
<property name="password"><value>${encrypt.password}</value></property>
</bean>
<bean id="ssnBouncy" class="com.jasypt.bc.SSNBouncyCastleProvider"
init-method="init" />
</beans>
The above file has two spring beans defined, the first bean is hibernateStringEncryptor
, and the second bean is ssnBouncy
.
Spring hibernateStringEncryptor
bean type is HibernatePBEStringEncryptor
class and this class acts as a wrapper on a PBEStringEncryptor
, allowing to be set a registered name and performing the needed registry operations against the HibernatePBEEncryptorRegistry
. It is not mandatory that a PBEStringEncryptor
be explicitly set with setEncryptor
(PBEStringEncryptor
). If not, a StandardPBEStringEncryptor
object will be created internally and it will be configurable with the setPassword
(String
)/setPasswordCharArray
(char[]
), setAlgorithm
(String
), setKeyObtentionIterations
(int
), setSaltGenerator
(SaltGenerator
), setProviderName
(String
), setProvider
(Provider
), setStringOutputType
(String
) and setConfig
(PBEConfig
) methods.
This class is mainly intended for use from Spring Framework or some other IoC container (if you are not using a container of this kind, please see HibernatePBEEncryptorRegistry
). The steps to be performed are the following:
- Create an object of this class (declaring it).
- Set its
registeredName
and, either its wrapped encryptor or its password, algorithm, keyObtentionIterations
, saltGenerator
and config
properties. - Declare a
typedef
in a Hibernate mapping giving its encryptorRegisteredName
parameter the same value specified to this object in registeredName
.
There is another class PooledPBEStringEncryptor
that can be used instead of HibernatePBEStringEncryptor
. PooledPBEStringEncryptor
Pooled implementation of PBEStringEncryptor
that in fact contains an array of StandardPBEStringEncryptor
objects which are used to attend encrypt and decrypt requests in round-robin. This should result in higher performance in multiprocessor systems.
There is another way to also configure Jasypt in hibernate, i.e., just add the following code in hibernate mapping file.
Code here
<typedef name="encryptedString" class="org.jasypt.hibernate.type.EncryptedStringType">
<param name="algorithm">PBEWITHSHA256AND256BITAES-CBC-BC</param>
<param name="providerName">BC</param>
<param name="password">abc123</param>
</typedef>
The applicationContext-jasypt.xml file uses bc.properties file and this file has a Bouncy Castle algorithm, provide name, and password for encryption, and decryption. The properties are:
encrypt.algorithm=PBEWITHSHA256AND256BITAES-CBC-BC
encrypt.providerName=BC
encrypt.password=abc123
The second bean of the applicationContext-jasypt.xml is ssnBouncy
. The SSNBouncyCastleProvider
class registers the BouncyCastleProvider
by calling spring initialization time. The BouncyCastleProvider
class JCE compliant provider that is a wrapper built on top of the light-weight API. The advantage for writing application code that uses the provider interface to cryptographic algorithms is that the actual provider used can be selected at run time. This is extremely valuable for applications that may wish to make use of a provider that has an underlying hardware for cryptographic computation, or where an application may have been developed in an environment with cryptographic export controls.
Code here
package com.jasypt.bc;
import java.security.Security;
public class SSNBouncyCastleProvider
{
public void init()
{
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
}
Create Spring Transaction Aware JUNIT Test Case
Code here
package com.jasypt.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.AbstractTransactionalSpringContextTests;
import com.jasypt.domain.person.Person;
import com.jasypt.service.PersonDetailsManager;
public class PersonTestCase extends AbstractTransactionalSpringContextTests
{
public static final String DATE_PATTERN = "MM/dd/yyyy";
@Autowired
private PersonDetailsManager personDetailsManager;
public void testSaveOrUpdatePerson() throws ParseException
{
Person p = new Person();
p.setName("Bob");
p.setSsn("123-45-1235");
p.setDate(convertDate("05/21/1970"));
personDetailsManager.savePerson(p);
//If you un-commit the line it will commit the transaction ;
//otherwise spring rollback every end of testcase.
//setComplete();
}
public void testRetrieveAllPersons()
{
List<Person> persons = personDetailsManager.getAllPersons();
for (Person p1:persons)
{
System.out.println(p1.getName()+ " "+p1.getSsn()+" "+p1.getDate());
}
}
protected String[] getConfigLocations()
{
List<String> configLocations = new ArrayList<String>(2);
configLocations.add("applicationContext-resource.xml");
configLocations.add("applicationContext-jasypt.xml");
configLocations.add("applicationContext-service.xml");
configLocations.add("applicationContext-dao.xml");
return configLocations.toArray(new String[]{});
}
...
}
The above PersonTestCase
class has two methods, testSaveOrUpdatePerson
and testRetrieveAllPersons
. The first method saves person
object into Person
table, and the second method retrieves all records from Person
table. In this article, the code followed in layered architecture, i.e., all dao classes defined in applicationContext-dao
, all service classes defined in applicationContext-service.xml, Jasypt classes, and BouncyCastle register classes defined in applicationContext-jasypt.xml, hibernate integration, hibernate configuration, mapping, transaction beans defined in applicationContext-resource.xml file. finally database properties are defined in database.properties file. All these file(s) can be found in the attachment of this article.
History
- Initial submission on 02/12/2012