Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

Encrypt Personal Data in Database using Bouncy Castle and Java Simplified Encryption

5.00/5 (4 votes)
13 Feb 2012CPOL5 min read 44K   417  
Bouncy Castle provide encrypt/decrypt your personal data such as password, SSN, credit card numbers etc. using Simple JASYPT framework.
Sample Encryption Database table

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:

Sample Encryption Database table

Implementation

Create PERSON Table

SQL
CREATE TABLE PERSON
 (
  ID  NUMBER(19,0) PRIMARY KEY,
  NAME VARCHAR2(50),
  DOB DATE,
  SSN VARCHAR2(50)
 );

Create ORACLE Sequence

SQL
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.

Java
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

XML
<?xml version="1.0" encoding="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

XML
<?xml version="1.0" encoding="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:

  1. Create an object of this class (declaring it).
  2. Set its registeredName and, either its wrapped encryptor or its password, algorithm, keyObtentionIterations, saltGenerator and config properties.
  3. 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

XML
<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

Java
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

SQL
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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)