Java加密扩展(JCE)现在已经成为Java SDK 1.4的核心组成部分。JCE基本上是一组提供加密框架和实现、密钥生成和协商以及消息认证代码(MAC)算法的Java包。
不过你可得注意了,虽然JCE目前是Java SDK 1.4核心组成包,不过我们将演示如何用Java SDK 1.2 或者更高版本对其进行配置。此外,本文还要讨论如何在动态安装的情况下使用安全供应者。最后我会演示创建密钥和密码的过程,以及如何实施基本的数据加密和解密。
--------------------------------------------------------------------------------
什么是安全供应者?
安全供应者就是承担特定安全机制的实现。有些供应者是完全免费的,而另一些供应者则需要付费。提供安全供应者的公司有IBM、Bouncy Castle和RSA等。今后我们将对Bouncy Castle的RSA实现做阐述。Sun 提供了如何实现你自己供应者的细节。
--------------------------------------------------------------------------------
静态安装
在使用或安装JCE之前,你必须首先从Sun的网站获取相关的Java库。JCE包含了Sun自产的安全供应者SunJCE。为了在你的默认供应者列表中静态添加SunJCE,你需要编辑安全属性文件;
<java-home>;/jre/lib/security/java.security (Win32)
<java-home>;/jre/lib/security/java.security (UNIX)
比方说,假如你在Windows计算机的C:/jdk1.3文件夹下面安装了JDK,那么你需要编辑如下文件:
C:/jdk1.3/jre/lib/security/java.security
为了安装SunJCE你还得在以上文件中添加以下代码行:
security.provider.n=com.sun.crypto.provider.SunJCE
请用正确的供应者替代以上代码中的 n。
程序清单A 演示了如何查看安装供应者的信息。程序清单B所示的输出结果显示了供应者的支持信息,比如可用算法等。
动态安装
程序清单C 所示为运行时动态装载供应者的情况。必须指出,当你在调用Security.addProvider(…)的时候,供应者对整个JVM可用。
如上所述,当你在安装供应者的时候,你必须提供一个数字表示其优先级。在调用实现时, JVM会根据优先级搜索整个安装的安全供应者并用找到的第1个供应者实现请求的算法。你还可以通过在方法调用中包含其他参数的方法显式地调用给定的供应者,以后我们可以了解这一点。
实现细节
JCE API由很多类和接口组成。它们具有若干种算法和安全特性。本文首先讨论常用的对称算法数据加密标准DES(Data Encryption Standard)。
产生密钥
程序清单D 说明了如何初始化KeyGenerator和产生密钥。
为了生成密钥,我们首先得获得KeyGenerator的一个实例。这可以由调用KeyGenerator类的静态方法getInstance完成。我们用普通的、不带模式或者方案的DES算法。可选地,你可以如下所示传递参数:
DES/ECB/PKCS5Padding
这样就提供了带ECB(电子密码本)模式和PKCS#5补充风格的DES算法。你还可以传递第2个字符串参数指定要使用的供应者实现,不过这并不是必需的:
KeyGenerator kg = KeyGenerator.getInstance("DES");
获得自己的KeyGenerator,之后就可以调用generateKey方法获得我们的密钥:
Key key = kg.generateKey();
产生密码
我们采用生成密钥相同的方式生成一个密码。我们必须调用Cipher类的静态方法getInstance。该方法的参数同KeyGenerator完全一样:
Cipher cipher = Cipher.getInstance(“DES”);
程序清单E 显示了有关的操作程序。
数据加密和解密
加密是在字节级别上进行的,所以数据的各个方面一个不落全都会被加密。一旦获得了密钥和密码,你就可以对数据进行安全操作了。值得注意的是密钥和密码必须采用同类算法。你不能用DESede初始化密钥却用DES初始化密码。Cipher对象采用同样的方法对数据加密和解密,所以你必须首先对其初始化以便它知道对数据进行怎样的操作:
cipher.init(Cipher.ENCRYPT_MODE, key);
以上方法调用对Cipher对象初始化以准备加密数据。加密数据的最简单办法就是调用 Cipher对象的doFinal方法,同时传递字节数组:
byte[] data = “Hello World!”.getBytes();
byte[] result = cipher.doFinal(data);
result现在包含传递数据的加密形式。对同一数据解密也很容易。但在解密之前,我们必须重新初始化Cipher对象以便其准备解密:
cipher.init(Cipher.DECRYPT_MODE, key);
之后即可解密:
byte[] original = cipher.doFinal(result);
现在original应该和data.完全相同。程序清单F所示为全部源代码。
小结
JCE是一种强大的API,它可以实施多种类型的加密和其他涉及安全的任务。我们已经知道了如何以静态和动态方式安装JCE,以及采用对称加密算法对简单消息加密和解密。在本系列的第2部分,我还会利用以上的这些知识运用到真实环境下来,教你如何编写简单的封装类以结合套接字加密应用程序的所有网络流量。
C:/jdk1.3/jre/lib/security/java.security 以下是我的JDK里面的配置代码
security.provider.1=sun.security.provider.Sun security.provider.2=sun.security.rsa.SunRsaSign security.provider.3=com.sun.net.ssl.internal.ssl.Provider security.provider.4=com.sun.crypto.provider.SunJCE security.provider.5=sun.security.jgss.SunProvider security.provider.6=com.sun.security.sasl.Provider security.provider.7=org.jcp.xml.dsig.internal.dom.XMLDSigRI security.provider.8=sun.security.smartcardio.SunPCSC security.provider.9=sun.security.mscapi.SunMSCAPI