电子商务使用数据加密来保护数据库[转贴]

电子商务使用数据加密来保护数据库(一)[原创]

作者:鲤鱼网 EMAIL:[email protected] MSN:[email protected]

本文首先分析了数据库数据需要加密的原因,简要介绍了DES算法及Java密码体系和Java密码扩展,最后说明了利用DES加密算法保护数据库数据的方法及步骤。

Java语言是一种非常适用于网络编程的语言,它的基本结构与C++极为相似,但抛弃了C/C++中指针等内容,同时它吸收了Smalltalk、C+ +面向对象的编程思想。它具有简单性、鲁棒性、可移植性、动态性等特点。这些特点使得Java成为跨平台应用开发的一种规范,在世界范围内广泛流传。

数据库数据需要加密的原因

电子商务网站中,数据库的信息至关重要,尤其现在货物的实时交易,使得一些比较重要的信息不得不存储在数据库或者其它容易泄露或者不安全的地方(当然,也 没有绝对安全的),例如数字商品信息、银行卡账号等,一旦诸如黑客一般的网络高手成功入侵到我们的系统,如果我们的数据库信息没有加密,那么我们所有的东 西便拱手相送了,这不仅危害了商户的利益,更使得客户遭受损失,进一步也会影响中国电子商务的里程,所以数据库中一些重要信息的加密起到的很重要的作用。

Java密码体系和Java密码扩展

Java密码体系(JCA)和Java密码扩展(JCE)的设计目的是为Java提供与实现无关的加密函数API。它们都用factory方法来创建类 的例程,然后把实际的加密函数委托给提供者指定的底层引擎,引擎中为类提供了服务提供者接口在Java中实现数据的加密/解密,是使用其内置的JCE (Java加密扩展)来实现的。Java开发工具集1.1为实现包括数字签名和信息摘要在内的加密功能,推出了一种基于供应商的新型灵活应用编程接口。 Java密码体系结构支持供应商的互操作,同时支持硬件和软件实现。

Java密码学结构设计遵循两个原则:

(1)算法的独立性和可靠性。

(2)实现的独立性和相互作用性。

算法的独立性是通过定义密码服务类来获得。用户只需了解密码算法的概念,而不用去关心如何实现这些概念。实现的独立性和相互作用性通过密码服务提供器来 实现。密码服务提供器是实现一个或多个密码服务的一个或多个程序包。软件开发商根据一定接口,将各种算法实现后,打包成一个提供器,用户可以安装不同的提 供器。安装和配置提供器,可将包含提供器的ZIP和JAR文件放在CLASSPATH下,再编辑Java安全属性文件来设置定义一个提供器。Java运行 环境Sun版本时, 提供一个缺省的提供器Sun。

下面介绍DES算法及如何利用DES算法加密和解密类文件的步骤。

DES算法简介

DES(Data Encryption Standard)是发明最早的最广泛使用的分组对称加密算法。DES算法的入口参数有三个:Key、Data、Mode。其中Key为8个字节共64 位,是DES算法的工作密钥;Data也为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密。

DES算法工作流程如下:若Mode为加密模式,则利用Key 对数据Data进行加密, 生成Data的密码形式(64位)作为DES的输出结果;如Mode为解密模式,则利用Key对密码形式的数据Data进行解密,还原为Data的明码形 式(64位)作为DES的输出结果。在写入和读取的时候,使用一致的Key,在写入时Key对核心数据进行DES加密,然后存储在数据库中,数据要从数据 库取出时,用同样的Key对密码数据进行解密,便再现了明码形式的核心数据。这样,便保证了核心数据在数据库存储的安全性和可靠性。

利用DES算法加密的步骤

(1)生成一个安全密钥。在加密或解密任何数据之前需要有一个密钥。密钥是随同被加密的应用程序一起发布的一段数据,密钥代码如下所示。

【生成一个密钥代码】
// 生成一个可信任的随机数源
SecureRandom sr = new SecureRandom();
// 为我们选择的DES算法生成一个KeyGenerator对象
KeyGenerator kg = KeyGenerator.getInstance ("DES" );
Kg.init (sr);
// 生成密钥
Secret Key key = kg.generateKey();
// 将密钥数据保存为文件供以后使用,其中key Filename为保存的文件名
FileUtil.writeFile (keyFilename, key.getEncoded () );

(2)加密数据。得到密钥之后,接下来就可以用它加密数据。如下所示。

【用密钥加密原始数据】

// 产生一个可信任的随机数源
SecureRandom sr = new SecureRandom();
//从密钥文件key Filename中得到密钥数据
Byte rawKeyData [] = FileUtil.readFile (key Filename);
// 从原始密钥数据创建DESKeySpec对象
DESKeySpec dks = new DESKeySpec (rawKeyData);
// 创建一个密钥工厂,然后用它把DESKeySpec转换成Secret Key对象
SecretKeyFactory key Factory = SecretKeyFactory.getInstance("DES" );
Secret Key key = keyFactory.generateSecret( dks );
// Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance( "DES" );
// 用密钥初始化Cipher对象
cipher.init( Cipher.ENCRYPT_MODE, key, sr );
// 获取需要加密的数据str
Byte data [] = str.getBytes();
// 执行加密操作
Byte encryptedClassData [] = cipher.doFinal(data );
// 保存到数据库中

(3)解密数据。操作步骤如下所示。

【用密钥解密数据】

// 生成一个可信任的随机数源
SecureRandom sr = new SecureRandom();
// 从密钥文件中获取原始密钥数据
Byte rawKeyData[] = Util.readFile( keyFilename );
// 创建一个DESKeySpec对象
DESKeySpec dks = new DESKeySpec (rawKeyData);
// 创建一个密钥工厂,然后用它把DESKeySpec对象转换成Secret Key对象
SecretKeyFactory key Factory = SecretKeyFactory.getInstance( "DES" );
SecretKey key = keyFactory.generateSecret( dks );
// Cipher对象实际完成解密操作
Cipher cipher = Cipher.getInstance( "DES" );
// 用密钥初始化Cipher对象
Cipher.init( Cipher.DECRYPT_MODE, key, sr );
// 从数据库中获得经过加密的数据str
Byte encrypted Data [] = str.getBytes();
//执行解密操作
Byte decryptedData [] = cipher.doFinal( encryptedData );
// 然后将解密后的数据显示给客户。


我们需要开始在新系统里使用数据加密,如果不是在目前的系统里使用的话。我认为这是项很大的工程,这也就是为什么我说在新系统里使用数据加密,而不是在旧 系统里加上数据加密功能。最好方法就是从那些你最常使用的数据库的提供厂商那里开始:Oracle、IBM和微软。然后看看大量的第三方供应商和其他互联 网安全专家能够提供什么。无论你从哪里开始,最好都是今天开始,以免让自己成为明天牺牲品。


例如,我们创建一个类DESUtil.java

按照上次讲的,我要首先要创建一个密钥,所以先增加一个方法,用来创建DES密钥。为了使用方便,我们暂时把所有的方法写成静态方法。
//filename是要保存的文件路径
public static void createKey(String filename) throws Exception{
//生成一个可信任的随机数源
SecureRandom sr = new SecureRandom();
//为我们选择的DES算法生成一个KeyGenerator对象
KeyGenerator kg = KeyGenerator.getInstance("DES");
kg.init(sr);
//生成密钥
Key key = kg.generateKey();
//将密钥数据保存为文件供以后使用
writeFile(key,filename); //稍候讲解
}

好了,我们可以通过上面的方法生成密钥了。
因 为我们可能会在不同的地方调用加密或者解密的方法,所以我们必须把生成密钥的存储在一个文件中,推荐存储到应用的/WEB-INF/的某个目录下,因为那 个目录只由自己的程序调用,不能通过URL访问,所以更安全。接下来我们要写两个方法,一个将密钥存储到文件,另一个则是在加密或者解密的方法中读出密钥 进行加密或者解密。

//filename是密钥存储的路径,msg是我们用第一个方法生成的密钥
public static void writeFile(Key msg, String filePath) {
try {
File file = new File(filePath);
if (file.exists()) {
file.delete();
}
FileOutputStream wf = new FileOutputStream(file);
ObjectOutputStream out = new ObjectOutputStream(wf);
out.writeObject(msg);
out.close();
file = null;
wf = null;
} catch (IOException e) {
debug(e.getMessage());
}
}
//filename是密钥存储的路径
public static Key readFile(String filePath) {
Key key = null;
try {
File f = new File(filePath);
if (f.exists()) {
FileInputStream bw = new FileInputStream(f);
ObjectInputStream in = new ObjectInputStream(bw);
key = (Key)in.readObject();
in.close();
bw = null;
}
f = null;
} catch (Exception e) {
debug(e.getMessage());
}
return key;
}

这里我们直接把密钥对象整个存到了文件中,当然也可以用字节的方式存储,但是中间可以会有些小麻烦噢!

好了,现在密钥的问题也解决了,我们接下来的工作就是写加密和解决的方法了。

//str 要加密的字节数组
public static byte[] DataEncrypt(byte[] str,String filename) throws Exception{
//
SecretKey key = (SecretKey)readFile(filename);
//Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance("DES");
//用密钥初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, key);
//执行加密操作
byte[] encryptedData = cipher.doFinal(str);
//
return encryptedData;
}
//str 要解密的字节数组
public static byte[] DataDecrypt(byte[] str,String filename) throws Exception{
//
SecretKey key = (SecretKey)readFile(filename);
//Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance("DES");
//用密钥初始化Cipher对象
cipher.init(Cipher.DECRYPT_MODE, key);
//执行加密操作
byte[] encryptedData = cipher.doFinal(str);
//
return encryptedData;
}


简单吧,我们已经成功的创建了DES加密,解密的类了。测试一下吧!

public static void main(String[] args) {
String filename = "c:/des.key";
String str = "0109103746028";
System.out.print("source="+str);
try {
DESUtil.createKey(filename);
//
byte[] enstr = DESUtil.DataEncrypt(str.getBytes(),filename);
str = new String(enstr);//加密后的字串
System.out.print("encrypt=" + str);
//
byte[] destr = DESUtil.DataDecrypt(str.getBytes(),filename);
str = new String(destr);//解密后的字串
System.out.print("decrypt=" + str);
} catch (Exception e) {
e.printStackTrace();
}
debug("ok");
}

如果没有定错的话,一定报错了: javax.crypto.BadPaddingException: Given final block not properly padded
怎么回事,都是按照你的写的,怎么会不对呢?仔细分析一下,不难发现,该异常是在解密的时候抛出的,加密的方法没有问题。

但 是两个方法的唯一差别是Cipher对象的模式不一样,这就排除了程序写错的可能性。再看一下异常的揭示信息,大概的意思是:提供的字块不符合填补的。什 么意思???原来在用DES加密的时候,最后一位长度不足64的,它会自动填补到64,那么在我们进行字节数组到字串的转化过程中,可以把它填补的不可见 字符改变了,所以引发系统抛出异常。问题找到,怎么解决呢?大家还记得邮件传输通常会把一些信息编码保存,对了,就是Base64,那样保证了信息的完整 性,所以我们就是利用一下下了。为了方便使用,我们再写一个新的方法封装一下原来的方法:
//
public static String DataEncrypt(String str){
String encrypt = null;
try{
byte[] ret = DataEncrypt(str.getBytes("UTF-8"),filename);
encrypt = new String(Base64.encode(ret),"UTF-8");
}catch(Exception e){
System.out.print(e);
encrypt = str;
}
return encrypt;
}
//
public static String DataDecrypt(String str){
String decrypt = null;
try{
byte[] ret = DataDecrypt(Base64.decode(str.getBytes("UTF-8")),filename);
decrypt = new String(ret,"UTF-8");
}catch(Exception e){
System.out.print(e);
decrypt = str;
}
return decrypt;
}

我们把方法的参数改成了字串,但是为什么要用UTF-8呢?不指定它的字节格式不行吗?大家知道,UTF-8是国际通用的字符编码,用它传输任何字串都不会有问题,通过它也可以很完美的解决J2EE的中文问题!所以我们最好用UTF-8编码,以减少不必要的麻烦。

注意,上面方法中当加密或者解密过程中,程序抛出异常,将返回原值,使得在调用方法失败时更方便的找出错误。

大家也可以利用其它的密钥,进行不同地方的加密解埽?

总结:DES是一个相对比较老的加密算法,对于现在也不是最安全的,所以大家也可以利用别的加密算法进行加密解密,以得到更安全的系统。

你可能感兴趣的:(数据结构,编程,算法,应用服务器,电子商务)