密码学研究-消息摘要(MessageDigest)

简介:

引入:

我们在http://supercharles888.blog.51cto.com/609344/1313864 中讲到了加密的几种方式,其中最简单的是单向加密,它的作用是用来校验数据的完整性。

如果大家玩过网游的话,都知道任何客户端或者补丁的下载,一般在下载处,都会提供一个MD5校验码,其实这个就是保证你下载完这个客户端或者补丁是完整没有被篡改过的。

102836222.png

当然了, 很多游戏客户端并不需要自己去算这个MD5校验码然后和官方给出的MD5的值进行比对,很多游戏工具都提供了MD5校验工具,比如我最喜欢的“魔兽世界”,它在工具包中就提供了MD5校验工具,你只要吧下载的客户端放到工具中校验下,它就自动会识别你这个客户端的完整性。这个很重要,因为大家都知道,现在的游戏客户端多数有可能被挂木马,这些木马会盗取你的账号信息,从而影响你的虚拟财产。这里我们的被下载的软件是广义的”消息",而被散列后的值是“消息摘要


透过现象看本质,我们知道,这个数据完整性的校验是由哈希函数保证的,又称“散列”,它有若干的特点可以保证完成我们的任务。

a. 它是正向不可逆的,你只能从原始值转为hash值,而无法从hash值倒推到原始值。

b.相同的原始内容被相同哈希函数哈希后其哈希值一定是相同的。

b.不同的原始内容被相同哈希函数哈希后其哈希值一定是不同的。(这个是相对的, 因为世界上的消息,文件是无限多的,但是定长的哈希值能表示的内容范围是有上限的,比如64位就最多能表示2的64次方,但是这种“碰撞”的概率极小极小,对于MD5来说,已经有人破解了这个算法,给出了找出碰撞的原始内容的快捷方法,有兴趣的同学可以参考相应的文献http://wenku.baidu.com/view/bfbcf17f5acfa1c7aa00ccf6.html


JDK中,也提供了MessageDigest(消息摘要)类来专门处理如何将一个消息hash成对应的消息摘要(hash值),因为JDK有许多不同的Provider,见我们上文http://supercharles888.blog.51cto.com/609344/1314058 ,所以对于消息摘要来说也有多种不同的算法,当然了,对于这个API的使用上,是完全一致的,而且虽然这个类名字叫消息摘要,其实它不仅可以处理文本类消息,还可以处理二进制文件作为原始内容(就像我们网络游戏的客户端或者补丁),我们这里就用编程的方式来演示下这个类的常见的使用。


实践:

为了应付各种情况,我们提供了一个工具类,它的方法1可以将某消息通过给定算法转为对应的消息摘要,方法2可以将给定的二进制文件通过给定算法转为对应的消息摘要。我们看下实现:

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
100
101
package  com.charles.securitystudy;
import  java.io.FileInputStream;
import  java.io.FileNotFoundException;
import  java.security.DigestInputStream;
import  java.security.MessageDigest;
import  java.security.NoSuchAlgorithmException;
import  java.security.Provider;
/**
  *
  * Description:提供一组工具类来方便我们计算消息摘要
  *
  * @author charles.wang
  * @created Oct 24, 2013 10:21:19 AM
  *
  */
public  class  MessageDigestUtil {
     /**
      * 为指定的字符串产生消息摘要
      *
      * @param mesage
      * @return
      */
     public  static  String genMessageDigestForString(String message, String algorithm) {
         // 原始的信息,将其转为原始字节数组
         byte [] input = message.getBytes();
         try  {
             // 用指定的算法来初始化消息摘要。
             MessageDigest md = MessageDigest.getInstance(algorithm);
             // 返回消息摘要的长度
             int  digestLength = md.getDigestLength();
             System.out.println( "消息摘要长度为:"  + digestLength);
             // 返回消息摘要的提供者
             Provider provider = md.getProvider();
             System.out.println( "消息摘要的提供者为:"  + provider.getName());
             // 更新消息摘要,从而让消息摘要变为对应原始信息的消息摘要
             md.update(input);
             // 完成更新消息摘要动作,从消息摘要中返回散列后的字节数组
             byte [] values = md.digest();
             return  (byte2hex(values));
         catch  (NoSuchAlgorithmException ex) {
             ex.printStackTrace();
             System.out.println( "不存在此消息摘要算法" );
             return  null ;
         }
     }
     /**
      * 为二进制文件流产生消息摘要
      *
      * @param args
      * @throws Exception
      */
     public  static  String genMessageDigestForBinaryFile(String fileName, String algorithm) {
         try  {
             // 用指定的算法来初始化消息摘要
             MessageDigest md = MessageDigest.getInstance(algorithm);
             FileInputStream fis =  new  FileInputStream(fileName);
             DigestInputStream dis =  new  DigestInputStream(fis, md);
             // 计算摘要
             md = dis.getMessageDigest();
             // 完成更新消息摘要动作,从消息摘要中返回散列后的字节数组
             byte [] values = md.digest();
             return  (byte2hex(values));
         catch  (NoSuchAlgorithmException ex) {
             ex.printStackTrace();
             System.out.println( "不存在此消息摘要算法" );
             return  null ;
         catch  (FileNotFoundException ffe) {
             ffe.printStackTrace();
             System.out.println( "文件不存在" );
             return  null ;
         }
     }
     /**
      * 将二进制转为字符串的形式
      *
      * @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();
     }
}



然后我们用一个测试类来做实验:

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
package  com.charles.securitystudy;
/**
  *
  * Description: 演示类
  *
  * @author charles.wang
  * @created Oct 23, 2013 5:44:18 PM
  *
  */
public  class  MessageDigestDemo {
                                                                                     
                                                                                     
                                                                                     
     public  static  void  main(String [] args)  throws  Exception{
                                                                                         
         //演示为指定字符串产生消息摘要
         System.out.println( "演示为指定字符串产生消息摘要" );
         String givenString= "abcdedf" ;
         String digestAlgorithm= "SHA" ;
         System.out.println( "原始字符串为:" +givenString+ "," + "使用的消息摘要算法为:" +digestAlgorithm);
         System.out.println( "产生的消息摘要为:" +MessageDigestUtil.genMessageDigestForString(givenString,digestAlgorithm));
         System.out.println();
                                                                                         
         //演示为指定二进制文件产生消息摘要
         System.out.println( "演示为指定二进制文件产生消息摘要" );
         String fileName= "travel.jpg" ;
         System.out.println( "原始文件为:" +fileName+ "," + "使用的消息摘要算法为:" +digestAlgorithm);
         System.out.println( "产生的消息摘要为:" +MessageDigestUtil.genMessageDigestForBinaryFile(fileName,digestAlgorithm));
                                                                                         
     }
                                                                                     
                                                                                     
                                                                                     
}



最后我们来看下运行结果:

103940143.png


这说明,我们提供的方法是正确的,大家可以拿来随便用哦。





本文转自 charles_wang888 51CTO博客,原文链接:http://blog.51cto.com/supercharles888/1314332,如需转载请自行联系原作者
目录
相关文章
|
1月前
|
算法 安全 关系型数据库
密码学系列之七:数字签名
密码学系列之七:数字签名
|
2月前
|
安全 算法 数据安全/隐私保护
现代密码学 补充1:两种窃听不可区分实验的区别
现代密码学 补充1:两种窃听不可区分实验的区别
22 0
|
5月前
|
存储 算法 安全
【11.10】现代密码学1——密码学发展史:密码学概述、安全服务、香农理论、现代密码学
【11.10】现代密码学1——密码学发展史:密码学概述、安全服务、香农理论、现代密码学
88 0
|
8月前
|
前端开发 网络协议 JavaScript
ChatGPT逐字推送的秘密
ChatGPT逐字推送的秘密
205 0
|
10月前
|
存储 人工智能 分布式计算
大模型时代,一定要来讨论下数据与隐私
大模型时代,一定要来讨论下数据与隐私
105 0
|
并行计算 算法 搜索推荐
【密码学】消息认证码
(Message Authentication Code) 是一种确认完整性并进行认证的技术,简称 MAC。使用消息认证码可以确认自己收到的消息是否就是发送者的本意,也就是说可以判断消息是否被篡改,是否有人伪装成发送者发送了这条消息。消息认证码的输入包括任意长度的和一个发送者与接收者之间的。输出固定长度的数据,输出的数据就是 MAC 值。
1646 1
|
定位技术
【密码学】一文读懂零知识证明
本文来聊一聊零知识证明的一点知识, 本文的例子纯属虚构,故事素材来源于网络和论文,以及我的瞎编, 如有雷同, 纯属巧合。
【密码学】一文读懂零知识证明
|
安全 区块链 数据安全/隐私保护
伯克利区块链课程:替代密码验证,比特币应用数字签名的进化之路
数字签名的诞生和区块链的最终问世,真正使得一个理想的去中心化交易网络成为了现实。但比特币还远远谈不上真正的价储藏和交换媒介,区块链世界的潜力尚待挖掘。
1350 0