使用 Bouncy Castle 和 Java 简易加密在数据库中加密个人数据





5.00/5 (4投票s)
Bouncy Castle 使用简单的 JASYPT 框架提供对密码、社会安全号码、信用卡号等个人数据的加密/解密功能。

引言
本文介绍了如何通过 Hibernate 使用 Java 简化加密 (Jasypt) 和 Bouncy Castle 框架来存储加密/解密信用卡、密码和社会安全号码等信息。Java 简化加密允许开发人员以最小的努力将基本加密功能添加到他们的项目中,而无需深入了解加密工作原理。
背景
Jasypt 本身不实现也不分发任何形式的加密算法。它仅通过 Java Cryptography Extension 使用用户 Java 安装中已有的算法。Jasypt 具有以下特性:
- 高安全性、基于标准的加密技术,支持单向和双向加密。加密密码、文本、数字、二进制文件……
- 与 Hibernate 的透明集成。
- 适合集成到 Spring 应用程序中,并且可以透明地与 Spring Security 集成。
- 集成应用程序配置(例如数据源)的加密功能。
- 针对多处理器/多核系统中的高性能加密的特定功能。
- 用于任何 JCE 提供程序的开放 API。
- ……还有更多
Bouncy Castle 在加密方面提供强大的支持。Bouncy Castle 具有一些特性:
- 适用于 Java 和 C# 的轻量级加密 API。
- Java Cryptography Extension 和 Java Cryptography Architecture 的提供程序。
- JCE 1.2.1 的干净房间实现。
- 用于读取和写入编码 ASN.1 对象的库。
- 轻量级客户端 TLS API。
- 用于 Version 1 和 Version 3 X.509 证书、Version 2 CRL 和 PKCS12 文件的生成器。
- 用于 Version 2 X.509 属性证书的生成器。
- 用于 OpenPGP (RFC 2440) 的生成器/处理器。
- 适用于 JDK 1.4-1.6 和 Sun JCE 的签名 JAR 版本。
- 有关 Bouncy Castle 的更多信息。
系统要求
- 数据库,如 MySql、HSQL、Oracle 10g XE 或更高版本。本文中使用 Oracle 10g Express Edition。
- Spring 2.5
- Hibernate 3.3.2.GA
- Jasypt 1.5
- Bouncy Castle 1.4 或更高版本
- IDE,如 Eclipse、NetBeans 等。
所需的库
屏幕截图在此

实现
创建 PERSON 表
CREATE TABLE PERSON
(
ID NUMBER(19,0) PRIMARY KEY,
NAME VARCHAR2(50),
DOB DATE,
SSN VARCHAR2(50)
);
创建 ORACLE 序列
CREATE SEQUENCE PERSON_ID_SEQUENCE
START WITH 1000
INCREMENT BY 1
NOCACHE
NOCYCLE;
PERSON_ID_SEQUENCE
用于插入唯一的个人记录。
创建 Person 领域对象
创建 Person
类并实现 Serializable
接口,并实现 getter 和 setter 方法,如同 POJO 类一样。
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()
{
}
...
创建 Person Hibernate 映射文件
<?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
类是一个 Hibernate UserType
实现,它允许在持久化实体时透明地加密 String
值。其中 encryptorRegisteredName
以某种方式将一个加密器对象绑定到该名称。这可以通过两种方式完成,具体取决于我们是否使用 IoC 容器(如 Spring)。在本文中,它是通过 Spring 注入的。此处 SSN 属性类型为 jasypt,即 encryptedString
。因此,当属性为 jasypt 类型时,jasypt 加密/解密将基于注册提供程序,并将数据发送/接收到/从表中。请查看以下代码。
创建加密器对象和 Spring 中的 Bouncy Castle
applicationContext-jasypt.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>
上述文件定义了两个 Spring bean,第一个 bean 是 hibernateStringEncryptor
,第二个 bean 是 ssnBouncy
。
Spring hibernateStringEncryptor
bean 类型是 HibernatePBEStringEncryptor
类,该类作为 PBEStringEncryptor
的包装器,允许设置注册名称并对 HibernatePBEEncryptorRegistry
执行所需的注册操作。不一定要显式设置 PBEStringEncryptor
(使用 setEncryptor(PBEStringEncryptor)
)。如果未设置,内部将创建一个 StandardPBEStringEncryptor
对象,并可通过 setPassword(String)
/setPasswordCharArray(char[])
、setAlgorithm(String)
、setKeyObtentionIterations(int)
、setSaltGenerator(SaltGenerator)
、setProviderName(String)
、setProvider(Provider)
、setStringOutputType(String)
和 setConfig(PBEConfig)
方法进行配置。
该类主要用于 Spring Framework 或其他 IoC 容器(如果您不使用此类容器,请参阅 HibernatePBEEncryptorRegistry
)。需要执行的步骤如下:
- 创建此类的对象(声明它)。
- 设置其
registeredName
,以及其包装的加密器或其密码、算法、keyObtentionIterations
、saltGenerator
和config
属性。 - 在 Hibernate 映射中声明一个
typedef
,将其encryptorRegisteredName
参数设置为与为此对象在registeredName
中指定的值相同。
还有一个名为 PooledPBEStringEncryptor
的类,可以代替 HibernatePBEStringEncryptor
使用。PooledPBEStringEncryptor
是 PBEStringEncryptor
的池化实现,它实际上包含一个 StandardPBEStringEncryptor
对象数组,这些对象用于轮流处理加密和解密请求。这应该会提高多处理器系统的性能。
还有另一种配置 Jasypt 在 Hibernate 中的方法,即在 Hibernate 映射文件中添加以下代码。
代码在此
<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>
applicationContext-jasypt.xml 文件使用 bc.properties 文件,该文件包含 Bouncy Castle 算法、提供程序名称以及用于加密和解密的密码。属性包括:
encrypt.algorithm=PBEWITHSHA256AND256BITAES-CBC-BC
encrypt.providerName=BC
encrypt.password=abc123
applicationContext-jasypt.xml 的第二个 bean 是 ssnBouncy
。SSNBouncyCastleProvider
类在 Spring 初始化时通过调用来注册 BouncyCastleProvider
。BouncyCastleProvider
类是符合 JCE 标准的提供程序,它是基于轻量级 API 构建的包装器。使用提供程序接口处理加密算法的应用程序代码的好处是,实际使用的提供程序可以在运行时选择。这对于希望利用具有底层硬件进行加密计算的提供程序的应用程序,或者在具有加密出口管制的で环境下开发的应用程序来说非常有价值。
代码在此
package com.jasypt.bc;
import java.security.Security;
public class SSNBouncyCastleProvider
{
public void init()
{
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
}
创建 Spring 事务感知 JUNIT 测试用例
代码在此
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[]{});
}
...
}
上面的 PersonTestCase
类有两个方法:testSaveOrUpdatePerson
和 testRetrieveAllPersons
。第一个方法将 person
对象保存到 Person
表中,第二个方法从 Person
表中检索所有记录。在本文中,代码遵循分层架构,即所有 dao 类定义在 applicationContext-dao
中,所有 service 类定义在 applicationContext-service.xml 中,Jasypt 类和 BouncyCastle 注册类定义在 applicationContext-jasypt.xml 中,Hibernate 集成、Hibernate 配置、映射、事务 bean 定义在 applicationContext-resource.xml 文件中。最后,数据库属性定义在 database.properties 文件中。所有这些文件都可以在本文的附件中找到。
历史
- 首次提交于 2012 年 12 月 2 日