博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
密码学研究-数字签名
阅读量:6327 次
发布时间:2019-06-22

本文共 5169 字,大约阅读时间需要 17 分钟。

引入:

提到签名,大家都不陌生,大家知道,重大的文件一般都要领导签名,来确保这个文件的真实有效。而一些比较重要的合同,比如买房的购房合同,都要盖“骑缝章”,这个骑缝章,就是盖在2页纸中间的印章,它也代表了签名,它用来保证你合同的完整性。所以说,签名在日常生活中非常重要,它主要用来保证了信息的完整性。同样,计算机世界也对这个签名过程进行了模拟,数字签名的概念由此而生。

数字签名的过程:

一般数字签名的过程分为2个,一个是签名过程,一个是验证过程。

数字签名的基本过程如下

(1)发送方用指定的散列函数作用于原始报文,计算出原始报文的原始摘要。

(2)发送方选用非对称的密钥中的私钥对原始摘要进行加密,得到加密后的原始摘要

(3)发送方构造一个报文(SignedObject对象),将原始报文添加在其中

(4)发送方将第(2)步产生的加密后的原始摘要也添加到第(3)步构建的报文中。

这个报文通过不可信任的网络传输到接收端。

(5)接受端从报文中取出原始报文,用约定的散列函数计算出摘要值,记为D1。

(6)接受端从报文中取出加密后的原始摘要,用公钥解密,还原出摘要值,记为D2。

(7)接收端比较D1和D2的值,如果相同,那么认为这个原始报文是可靠的。

实践:

我们java.security包提供了一组API 来表示数字签名的过程,这个核心类就是Signature类,它提供了一组方法来签名和验证,我们这里就给出这个类的一般用法:

我们先建立一个工具类,这个类是个单例,它主要是提供了一些封装方法来封装签名和验证的过程,因为签名和验证都需要公钥-私钥对,所以它包含了这对钥匙的产生逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package 
com.charles.signaturestudy;
import 
java.io.IOException;
import 
java.security.InvalidKeyException;
import 
java.security.KeyPair;
import 
java.security.KeyPairGenerator;
import 
java.security.KeyStore;
import 
java.security.NoSuchAlgorithmException;
import 
java.security.Signature;
import 
java.security.SignatureException;
import 
java.security.SignedObject;
/**
 
*
 
* Description: 这个工具类提供了一组方法来操作Signature类,它主要可以对签名进行一些操作
 
*
 
* @author charles.wang
 
* @created Oct 28, 2013 11:11:52 AM
 
*
 
*/
public 
class 
SignatureUtil {
    
private 
static 
SignatureUtil instance = 
null
;
    
//公钥私钥对
    
private 
KeyPair keyPair = 
null
;
    
//数字签名类
    
private 
Signature signature = 
null
;
    
/**
     
* 私有构造器,用指定的算法来初始化Signature类
     
* @param algorithm
     
*/
    
private 
SignatureUtil(String algorithm) {
        
try 
{
            
// 实例化KeyPairGenerator对象,并且指定算法为DSA
            
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
            
// 初始化 KeyPairGenerator对象
            
keyPairGenerator.initialize(
1024
);
            
// 生成Keypair对象
            
keyPair = keyPairGenerator.generateKeyPair();
            
// 实例化Signature对象,这个对象提供一组动作方法类操作签名
            
signature = Signature.getInstance(keyPairGenerator.getAlgorithm());
        
catch 
(NoSuchAlgorithmException ex) {
            
keyPair = 
null
;
            
signature = 
null
;
        
}
    
}
    
/**
     
* 单例的工厂方法,用于创建SignatureUtil的实例
     
*
     
* @return
     
*/
    
public 
static 
SignatureUtil getInstance(String algorithm) {
        
if 
(instance == 
null
)
            
instance = 
new 
SignatureUtil(algorithm);
        
return 
instance;
    
}
    
/**
     
* 用私钥对指定的原始数据进行签名
     
* @param data 被签名的数据
     
* @return
     
*/
    
public 
byte
[] signWithPrivateKey(
byte
[] data) {
        
try 
{
            
// 私钥完成签名,所以这里用私钥初始化用于签名的Signature
            
signature.initSign(keyPair.getPrivate());
            
// 更新要签名的原始数据
            
signature.update(data);
            
// 返回签名的内容
            
return 
signature.sign();
        
catch 
(InvalidKeyException ie) {
            
ie.printStackTrace();
            
return 
null
;
        
catch 
(SignatureException se) {
            
se.printStackTrace();
            
return 
null
;
        
}
    
}
    
/**
     
* 用公钥对指定的原始数据和签名进行验证
     
* @param data
     
* @param sign
     
* @return
     
*/
    
public 
boolean 
verifySignedObjectWithPublicKey(
byte
[] data, 
byte
[] sign) {
        
try 
{
            
// 公钥完成验证,所以这里用公钥初始化用于验证的Signature
            
signature.initVerify(keyPair.getPublic());
            
// 更新要验证的原始数据
            
signature.update(data);
            
// 验证签名,获得验证结果
            
return 
signature.verify(sign);
        
catch 
(InvalidKeyException ie) {
            
ie.printStackTrace();
            
return 
false
;
        
catch 
(SignatureException se) {
            
se.printStackTrace();
            
return 
false
;
        
}
    
}
                                                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                                      
}

然后我们提供了一个演示类,它的过程如下:

先给出原始数据,再用我们的API对其进行数字签名(sign),并且打印出数字签名的内容,然后我们用我们的API来验证(verify)数字签名的有效性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package 
com.charles.signaturestudy;
/**
 
*
 
* Description: 这个类用来演示数字签名的使用方法
 
*
 
* @author charles.wang
 
* @created Oct 28, 2013 10:37:32 AM
 
*
 
*/
public 
class 
SignatureDemo {
    
public 
static 
void 
main(String [] args) 
throws 
Exception{
                                                                                                                                                                                                                                                                         
        
//SignatureUtil是我们开发的一组动作类,它对于Signature类进行了进一步的封装
        
//它提供了我们可以对数字签名完成的一组动作
        
SignatureUtil sigUtil = SignatureUtil.getInstance(
"DSA"
);
                                                                                                                                                                                                                                                                         
        
//原始数据对象
        
String content=
"被测试的原始数据对象"
;
                                                                                                                                                                                                                                                                         
        
//打印出原始数据
        
System.out.println(
"原始数据为:"
+content);
                                                                                                                                                                                                                                                                         
        
//将原始数据对象转为字节数组
        
byte
[] rawData = content.getBytes();
                                                                                                                                                                                                                                                                         
        
System.out.println(
"\n开始对原始数据签名..."
);
        
//进行签名,返回签名的内容
        
byte
[] sign = sigUtil.signWithPrivateKey(rawData);
        
System.out.println(
"签名内容(16进制)为:"
+byte2hex(sign));
                                                                                                                                                                                                                                                                             
        
System.out.println(
"\n开始对签名内容验证..."
);
        
//进行验证,对验证结果进行分析
        
boolean 
status = sigUtil.verifySignedObjectWithPublicKey(rawData, sign);
                                                                                                                                                                                                                                                                         
        
if
(status==
true
){
            
System.out.println(
"验证结果,此签名是有效的"
);
        
}
else
{
            
System.out.println(
"验证结果,此签名是无效的"
);
        
}
                                                                                                                                                                                                                                                                         
    
}
                                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                     
    
/**
     
* 将二进制转为字符串的形式
     
*
     
* @param b
     
* @return
     
*/
    
protected 
static 
String byte2hex(
byte
[] b) 
// 二行制转字符串
    
{
        
// 最终要转化的16进制字符串
        
StringBuilder hexString = 
new 
StringBuilder();
        
// 处理每个转化的当前字符串
        
String tmpStr = 
""
;
        
for 
(
int 
n = 
0
; n < b.length; n++) {
            
// 将二进制转为16进制
            
tmpStr = (Integer.toHexString(b[n] & 
0XFF
));
            
// 如果当前转成的字符串只有一位长度的话,则前面补0,然后加上当前转换值
            
if 
(tmpStr.length() == 
1
) {
                
hexString.append(
"0"
).append(tmpStr);
            
}
            
// 否则,,则直接将当前转换值tmpStr附加在hexString后面
            
else
                
hexString.append(tmpStr);
            
// 如果没有到byte[]的尾部,则中间用冒号分开,最后一个后面不用加冒号
            
if 
(n < b.length - 
1
)
                
hexString.append(
":"
);
        
}
        
return 
hexString.toString().toUpperCase();
    
}
}

最后,我们运行这个实例程序,然后可以清晰的看出以上的过程:

本文转自 charles_wang888 51CTO博客,原文链接:http://blog.51cto.com/supercharles888/1316192,如需转载请自行联系原作者
你可能感兴趣的文章
查看文件的真实路径
查看>>
如何开发一个自己的 RubyGem?
查看>>
职工系统150206308
查看>>
『中级篇』K8S最小调度单位Pod(62)
查看>>
ACE网络编程思考(一)
查看>>
数据结构的几种存储方式
查看>>
React源码学习——ReactClass
查看>>
JavaScript中几个相似方法对比
查看>>
如何恢复RAWD盘的资料
查看>>
物联网+云平台未来方向之一
查看>>
大作业项目
查看>>
北大校长王恩哥送给毕业学生的十句话
查看>>
IDC简报:2012年全球六大最佳主机服务器提供商
查看>>
HC3i论坛5月份热门资源30个
查看>>
mysqldump导出--数据+结构+(函数+存储过程)
查看>>
浏览器的渲染原理简介
查看>>
获取系统当前时间参数date
查看>>
MySQL性能优化的最佳20+条经验
查看>>
exchange server 相关
查看>>
centos7系列安装vnc服务并授权用户访问
查看>>