Java与数字签名
关键字:Java 数字签名 PKI Keystore 数字证书 keytool jarsigner
摘要:本文介绍了数字签名的相关基础知识,并介绍了如何用java实现数字签名。
数字签名作为一种电子身份的认证的手段,被普遍用于网上银行,安全网络通信等领域.数字签名是电子签名的一种特定形式.本文不对数字签名的原理作介绍,只对相关概念作一些简单的介绍,详细讲解了在java中如何对jar文件进行数字签名.
数字签名的相关概念
实际上数字签名又称作基于PKI的电子签名, PKI的核心机构是电子认证服务提供者,即通称的认证机构CA,PKI签名的核心元素是由CA签发的数字证书,数字证书就如同日常生活中的身份证一样,用来标识网上实体的身份,CA就是对网上实体进行认证的第三方机构.数字证书就是CA机构对网上实体进行认证而产生的电子证书,它是数据签名的基础技术保障.CA机构对电子证书的有效性,有效期等提供查询服务.数字证书所包含公钥用来对使用对应的私钥加密的数据信息进行验证.
数字签名实现的具体原理是:
1、 将报文按双方约定的HASH算法计算得到一个固定位数的报文摘要。在数学上保证,只要改动报文中任何一位,重新计算出的报文摘要值就会与原先的值不相符。这样就保证了报文的不可更改性。(详见参考资料的"公钥密码技术原理"章节)
2、 将该报文摘要值用发送者的私人密钥加密,然后连同原报文和数字证书(包含公钥)一起发送给接收者而产生的报文即称数字签名。
3、接收方收到数字签名后,用同样的HASH算法对报文计算摘要值,然后与用发送者的公开密钥进行解密解开的报文摘要值相比较,如相等则说明报文确实来自所称的发送者。
4、同时通过证书颁发机构CA确认证书的有效性即可确认发送的真实身份。
数字证书的技术实现:
数字证书是公钥的载体,是PKI的核心元素.数字证书符合X.509标准,现行的PIK机制一般为又证书,即一个实体一般有两个证书,两个密码对,一个用于电子签名,一个用于加密通信.按照X.509标准,一个标准和数字证书的格式为:
CA《A》=CA{V,SN,AI,CA,UCA,A,UA,Ap,Ta}
它将包含证书颁发机构和标识及用户的标识,证书ID,有效期等信息(详见参考资料),另外还包含CA对此证书内容的进行了数字签名,以验证此证书的有效性.在验证一个数字证书的过程中,对数字证书的数字签名的验证将递归进行,只到找到双方共同可信任的CA根证书为止.
如何获取数字证书
数字证书可向专门的CA机构申请,有免费的数字证书和付费的数字证书.比如:中国数字认证网(http://www.ca365.com)、广东省电子商务认证中心(http://www.cnca.net/)就可申请到有效期为一年的免费数字证书.注意申请的证书是以该CA的证书作为申请的个人证书的根证书,所以如果想要申请的证书有效,需要下载并安装相应CA的根证书.另外,其它一些工具也可生成个人使用的数字证书,如微软的makecert(下载地址http://www.microsoft.com/downloads/details.aspx?familyid=2b742795-d0f0-4a66-b27f-22a95fcd3425&displaylang=en)),JDK中包含的keytool工具(以下会详细介绍如何使用)都可生成没有经过认证的数字证书.
Java如何实现数字签名
JDK有部分工具和API提供了对数字签名的支持:keytool,jarsigner,policytool等.
KeyTool工具可生成,导入,导出数字证书,支持的证书的格式为当前流行的
生成证书:keytool -genkey -alias mykey -keystore mystore
导入证书:keytool -import -alias abc -file ABCCA.cer -keystore mystore
导出证书: keytool -export -alias mykey -file MJ.cer -keystore mystore
对jar文件进行签名使用的工具是jarsigner:
格式如下:jarsigner -keystore keystoreFile jarfile alias
例如:jarsigner -keystore sylilzyKeystore.dat test.jar sylilzy
验证一个jar文件如下:
jarsigner -verify jarfile
以下步骤演示了一个完整的由获取数字证书到签名jar文件,然后访问该jar文件时显示签名信息的全过程:
上面提到,数字证书可由以下方式生成,第一,去http://www.ca365.com申请一个免费的数字证书,下载后为test.der
也可用keytool -genkey -alias mykey -keystore mystore生成,运行此命令后,提示相关信息,并填写完毕,如下:
E:\temp>keytool -genkey -alias mykey -keystore mystore
输入keystore密码: 111111
您的名字与姓氏是什么?
[Unknown]: shi
您的组织单位名称是什么?
[Unknown]: eshore
您的组织名称是什么?
[Unknown]: de
您所在的城市或区域名称是什么?
[Unknown]: gz
您所在的州或省份名称是什么?
[Unknown]: gd
该单位的两字母国家代码是什么
[Unknown]: cn
CN=shi, OU=eshore, O=de, L=gz, ST=gd, C=cn 正确吗?
[否]: y
输入<mykey>的主密码
(如果和 keystore 密码相同,按回车):
到此,我们则生成了一个名为mystore的keystore文件,该文件中保存有别名为mykey的数字证书.输入以下命令即可查看此数字证书:
E:\temp>keytool -list -alias mykey -keystore mystore
输入keystore密码: 111111
mykey, 2006-7-5, keyEntry,
认证指纹 (MD5): A1:A9:A7:C6:D8:E5:E5:20:EA:80:59:AF:C2:65:B4:17
或者带上-v参数显示详细信息
E:\temp>keytool -list -alias mykey -keystore mystore -v
输入keystore密码: 111111
别名名称: mykey
创建日期: 2006-7-5
输入类型:KeyEntry
认证链长度: 1
认证 [1]:
Owner: CN=shi, OU=eshore, O=de, L=gz, ST=gd, C=cn
发照者: CN=shi, OU=eshore, O=de, L=gz, ST=gd, C=cn
序号: 44ab3fb8
有效期间: Wed Jul 05 12:27:36 CST 2006 至: Tue Oct 03 12:27:36 CST 2006
认证指纹:
MD5: A1:A9:A7:C6:D8:E5:E5:20:EA:80:59:AF:C2:65:B4:17
SHA1: AC:8D:AA:9D:A7:62:48:70:ED:F4:28:4C:DC:DE:56:CE:41:FE:52:C9
以上为创建的一个证书,我们可以将它从keystore文件中导出:
E:\temp>keytool -export -keystore mystore -alias mykey -file my.cer
输入keystore密码: 111111
保存在文件中的认证 <my.cer>
我们也可将前面从网上申请的电子证书导入keystore文件:
E:\temp>keytool -import -alias sily -file test.der -keystore mystore
输入keystore密码: 111111
Owner: CN=施祖阳, OU=develop, O=eshore, L=广州, ST=广东, C=CN
发照者: CN=CA365 Free Root Certificate, O=CA365, L=Beijing, ST=Beijing, C=CN
序号: 653e1a63bb003fb3
有效期间: Tue Jul 04 12:02:25 CST 2006 至: Wed Jul 04 12:02:25 CST 2007
认证指纹:
MD5: 4A:AA:63:2A:8A:E2:8D:76:4B:2B:73:E9:F3:03:CD:6F
SHA1: 02:B3:9E:D0:7E:BB:9E:C4:B3:B0:79:19:FA:89:B6:93:DB:0F:4A:88
信任这个认证? [否]: y
认证已添加至keystore中
现在查看mystore中已经存了两个证书:
E:\temp>keytool -list -keystore mystore
输入keystore密码: 111111
Keystore 类型: jks
Keystore 提供者: SUN
您的 keystore 包含 2 输入
sily, 2006-7-5, trustedCertEntry,
认证指纹 (MD5): 4A:AA:63:2A:8A:E2:8D:76:4B:2B:73:E9:F3:03:CD:6F
mykey, 2006-7-5, keyEntry,
认证指纹 (MD5): A1:A9:A7:C6:D8:E5:E5:20:EA:80:59:AF:C2:65:B4:17
现在,我们开始利用前面生成的数字证书给jar文件签名.由于applet在浏览器中运行时的权限是受限的,不能对本地文件进行读写,但是如果applet所在的jar文件如果是经过数字签名,并且用户信任该签名,那此applet则可对本地文件进行读写,下面给出一个写本地文件的applet:
package com.applet;
import java.applet.Applet;
public class TestSecurity extends Applet {
/**
*
*/
private static final long serialVersionUID = 1L;
public TestSecurity() {
System. out .println( "this is good! " );
}
public void init() {
JButton button = new JButton( "Create a file" );
button.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent evt) {
File file = new File( "c:\\a.txt" );
try {
file.createNewFile();
JOptionPane. showMessageDialog ( null , " 成功创建文件c:\\a.txt" , "消息" ,
JOptionPane. INFORMATION_MESSAGE );
} catch (Exception ex) {
JOptionPane. showMessageDialog ( null , ex.getMessage(), "错误" , JOptionPane. ERROR_MESSAGE );
}
}
});
add(button);
}
}
将此文件编译后生成在com\applet生成两个class文件,用jar打包:
E:\sylilzy\documents\project\tjava\classes>jar -cvf test.jar com
标明清单(manifest)
增加:com/(读入= 0) (写出= 0)(存储了 0%)
...
会发现在当前目录下会生成一个"test.jar"文件,将此文件copy到与mystore同一个目录,准备对该文件进行电子签名.
E:\temp>jarsigner -keystore mystore test.jar mykey
输入密钥库的口令短语: 111111
警告: 签名者证书将在六个月内过期。
则test.jar已经被签名,编码一个简单的html文件对其进行访问,html如下:
Created with Colorer-take5 Library. Type 'html'
<html><head><metahttp-equiv="Content-Type"content="text/html; charset=GB2312"><title>
HTML Test Page
</title></head><body>
test.Applet1 will appear below in a Java enabled browser.<br><appletcodebase="."code="com.applet.TestSecurity"name="TestApplet"width="400"height="300"hspace="0"vspace="0"align="middle"archive="test.jar"></applet></body></html>
将以上html文件与test.jar文件放在同一目录,用IE打开,则可看到IE弹出安全警告: The application's digital signature is invalid.Do you want to run the application?
用户可查看test.jar的签名信息,如果选择取消息,然后点击create a file 按钮,则提示:access denied(java.io.FilePermission c:\a.txt write)
如果在IE弹出安全警告选择"始终信任此发行者的内容",然后点击运行,再点击create a file 按钮,则提示:成功创建文件c:\a.txt
上面给test.jar签名的数字证书是未经验证的,现在我们使用从网上申请的经过验证的数字证书给test.jar签名,看会出现什么结果:
E:\temp>jarsigner -keystore mystore test.jar sily
输入密钥库的口令短语: 111111
jarsigner: 找不到 sily 的证书链。sily 必须引用包含专用密钥和相应的公共密钥证书链的有效密钥库密钥条目。
这是因为sily的证书链不存在导致的,我们需要导入sily的证书链才可形成完整的sily的证书链,可以通过keytool -certreq生成证书链的PKCS#10格式的请求,然后再导入请求的PKCS#7格式的回复即可,由于名为sily的key是从cer文件导入的,它在keystore中是以trusted certificate entries类型存储的,没有私钥,所以不能生成证书链的请求.我们可以将前面名为mykey的key导出证书请求,或者导出mykey的证书,然后将此证书安装至"受信任的根证书颁发机构",然后访问用此证书签名过的文件,则IE将不再弹出安全警告窗口.