65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2012年2月13日

CPOL

5分钟阅读

viewsIcon

44450

downloadIcon

445

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

Sample Encryption Database table

引言

本文介绍了如何通过 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 等。

所需的库

屏幕截图在此

Sample Encryption Database table

实现

创建 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)。需要执行的步骤如下:

  1. 创建此类的对象(声明它)。
  2. 设置其 registeredName,以及其包装的加密器或其密码、算法、keyObtentionIterationssaltGeneratorconfig 属性。
  3. 在 Hibernate 映射中声明一个 typedef,将其 encryptorRegisteredName 参数设置为与为此对象在 registeredName 中指定的值相同。

还有一个名为 PooledPBEStringEncryptor 的类,可以代替 HibernatePBEStringEncryptor 使用。PooledPBEStringEncryptorPBEStringEncryptor 的池化实现,它实际上包含一个 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 是 ssnBouncySSNBouncyCastleProvider 类在 Spring 初始化时通过调用来注册 BouncyCastleProviderBouncyCastleProvider 类是符合 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 类有两个方法:testSaveOrUpdatePersontestRetrieveAllPersons。第一个方法将 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 日
© . All rights reserved.