作者:伍班权
随着计算机网络技术和软件技术的蓬勃发展,以及internet的广泛应用对传统的工作方式产生的巨大冲击,电子政务(E-government)系统就在这样的环境下应运而生了。电子政务的所有活动都是政府行为,要求具有高度的可靠性和安全性。数字签名技术这种能保证数据的完整性、机密性、抗否定性的信息安全技术毫无疑问将会在电子政务系统中得到广泛的应用。由于java在网络编程中的适用性,以及java的安全系统结构的日益完善和目前java开发网络安全软件的便利性,因此在电子政务系统中用java来实现数字签名会具有更好的现实意义。
数字签名的流程
数字签名是相对于手书签名而言的,是指采用一定的数据交换协议,使用密码算法对待发的数据(如文件、合同、通知等)进行加密处理后,生成一段信息,附着在原文上一起发送,这段信息类似现实中的签名或印章,接收方对其进行验证,判断发送者的身份和原文真伪。
数字签名主要是采用非对称加密算法,先采用单向Hash函数,将待发送的数据生成消息摘要MD_1,发送方使用自己的私钥对消息摘要加密生成数字签名,将数字签名附着在原文上一起发送。接收方收到消息以后,先用发送方的公钥将签名解密,得到消息摘要。然后利用接收的原数据进行单向Hash函数的计算,得到消息摘要MD_2进行验证,如果MD_1=MD_2,说明签名成功。
数字签名的流程如图(一)所示:
从流程图可以看出,数字签名包括签名算法和验证算法,目前主要使用的签名算法有RSA和DSA。
从数字签名的原理和流程图我们可以看出,数字签名主要有以下几方面的功能:
(1)保证了信息的完整性。根据Hash函数的性质,一旦原始信息被改动,所生成的数字摘要就会发生很大的变化。因此,通过这种方式,能防止原始信息被篡改。
(2)抗否认性。使用公开密钥的加密算法,由于只有发送方一人拥有私钥,因此,发送方不能否认发送过信息。
(3)防止接收方伪造一份报文,声称来自于发送方。
java在实现数字签名方面的优势
java在实现数字签名方面有很大的优势,主要表现在以下几个方面:
1、Java平台为安全和加密服务提供了两组API:JCA和JCE;
2、JCA (Java Cryptography Architecture)提供基本的加密框架,如证书、数字签名、消息摘要和密钥对产生器;
3、JCE在JCA的基础上作了扩展,包括加密算法、密钥交换、密钥产生和消息鉴别服务等接口。
在电子政务系统中使用混合密码体制来实现数字签名技术
在电子政务系统中如果在数字签名时原文在网络上以明文传输,就不能保证原始信息的机密性,而要保证原始信息的机密性,就需要对待发送的原始信息实行加密运算,若对原文使用非对称密码算法,由于使用非对称密码算法在解密时运算量很大,将会影响运算速度。所以,选择使用对称密码算法对原文进行加密,而用非对称的密码算法来实现数字签名技术,使用这种混合密码体制,既能实现数字签名,保证了在传输过程中原文机密性,又能提高运算效率。
使用混合密钥的数字签名流程如图(二)所示:
用java语言来实现混合密钥的数字签名
前面已经提到了java2为实施安全策略提供了很多机制,因此在电子政务中要实现数字签名选用java作为软件的开发平台是一个可行的方案,下面就给出一个实例的主要算法说明用java2是怎样实现数字签名的。因为是用在电子政务系统中,接收和发送文件的双方通常都比较固定,这里就不考虑公钥传送的安全问题,先假定接收方使用的公钥即为发送方使用的私钥所对应的公钥,算法中生成消息摘要的算法为MD5,签名算法使用RSA,对原文进行对称加密算法使用DES:
Java2中需要用到的主要的类基本上都封装在java.security.*和javax.crypto.*两个包中。
(1)引入需要用的java包
/*包含输入输出的类*/
Import java.io.*;
/*包含密钥对生成器类、密钥管理类、签名类*/
Import java.security.*;
/*包含各种密码算法类如:DES和RSA等*/
Import javax.crypto.*;
(2)发送方的代码( 假设要传送的数据是保存在文件info.dat中的):
/*生成RSA算法的公钥pubKey和私钥priKey,这里假定公钥生成以后是通过第三方安全的发送给接收方的*/
KeyPairGenerator DoublekeyGen = KeyPairGenerator.getInstance(“RSA”);
DoublekeyGen.init(1024);
KeyPair DoubleKey = DoublekeyGen.generateKeyPair();
PrivateKey priKey = DoubleKey.getPrivate();
PublicKeypubKey = DoubleKey.getpublic();
/* 将公钥pubKey保存在文件pubKey.dat文件中,供接收方使用*/ ObjectOutputStream out = new.ObjectOutputStream(newFileOutputStream(“pubKey.dat”);
out.writeObject(pubKey);
out.close();
/*生成DES算法的密钥Key*/
KeyPairGenerator SinglekeyGen = KeyGenerator.getInstance(“DES”);
SinglekeyGen.init(64);
Key SingleKey = SinglekeyGen.generateKey();
/*从文件info.dat读出需要传输的原始数据并保存在数组info_Plain[ ]中*/
ObjectInputStream in=new ObjectInputStream(new FileInputStream(“info.dat”));
byte[ info_Plain=(byte[ ])in.readObject();
in.close();
/*将待传输的原始信息生成消息摘要MD_1*/
MessageDigest messageDigest = MessageDigest.getInstance(“MD5”);
messageDigest.update(info_Plain);
byte[ ] MD_1 = messageDigest.digest();
/* 将待传输的信息用DES加密,并将加密后的数据保存在数组Des_info[ ]中*/
Ciphercipher = cipher.getInstance(“DES”);cipher.init(Cipher.ENCRYPT_MODE,SingleKey);
byte[ ] Des_info[ ] = cipher.doFinal(info_plain);
/* 将消息摘要MD_1[ ]和对称密钥SingleKey合并到字节数组MD_Key[ ]中,并用RSA算法中的私钥对该数组加密并保存在数组Rsa_sign[ ]中形成了数字签名*/
合并数组的算法略(主要就是通过循环将对称密钥添加到消息摘要数组的后面,形成一个新的数组MD_Key[ ],对称密钥要通过强制类型转化为byte类型)
Cipher cipher = cipher.getInstance(“RSA”);
cipher.init(Cipher.ENCRYPT_MODE, priKey);
byte[ ]Rsa_sign[ ] = cipher.doFinal(MD_Key);
/*将需要传输的原文的密文和数字签名写到文件En_info.dat中,En_info.dat即为在网上传输的信息*/
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(“En_info.dat));
Out.writeobject(Des_info);
Out.writeobject(Rsa_sign);。
Out.close();
(3)接收方的代码
接受方收到文件En_info.dat,该文件信息由两部分组成○1原文的密文:保存数组Des_info[ ];○2发送方的数字签名:保存在Rsa_sign[ ]数组中;并从pubKey.dat文件中将公钥读出且保存在变量PubKey中。
/*从文件En_info.dat中读出原文的密文和数
字签名两个数组*/
此部分算法略
/*将数字签名保存在Rsa_sign[ ]数组中用发送方的公钥解密得到消息摘要和对称密钥组成的数组MD_Key[ ]*/
公钥解密的算法略(解密和加密算法基本相同)
Int len = MD_Key.length();
Byte[ ]MD_1 = new Byte[ ];
Byte[ ]Key =new Byte[ ]
For (int i=0; i<128;i++)/*因为用MD5产生的数字摘要为128位*/
MD_1[i]=Md_Key[i];/*将摘要部分提取出来赋给数组MD_1*/
/*数组中的128位以后的元素即为对称密钥*/
While(i {Key[i]=Md_Key[i];}/*将对称密钥提取出来赋给数组Key[ ]*/
Key SingleKey = (PrivateKey)key; /*将对称密钥强制类型转换为key型*/
/*得到对称密钥后,通过DES的解密算法将密文变成明文,再将明文用MD5算法生成消息摘要并保存在数组MD_2[ ]中*/
解密和生成消息摘要的算法略
/*将MD_1[ ] 和MD_2[ ]做比较,若相等,则签名正确*/
For(int i=0;i<128;i++)
{ if MD_1[i] != MD_2[i]
{
System.out.println(“Signature error!”);
System.exit.( );
}
}
System.out.println(“Signature success!”);
由于只是给出了主要的算法,没有考虑在程序的执行过程中可能出现的异常情况以及一些基本的输入输出语句。