开发者社区> 余二五> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

密码学研究-消息摘要(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. Hex 编码 将二进制数据按16进制转换为字符串,1字节=2个字符,编码后体积为2倍。 2. Base64 由MIME规范定义的编码算法,其将3个字节(24位)编码为4个字符。 字符集包括64个,可表示6二进制位的数据,因此一个字符对应一组6bit的数据。
752 0
【Java小工匠聊密码学】--消息摘要--SHA3算法
1、SHA3概述 1.1 SHA3简介 由于近年来对传统常用Hash 函数如MD4、MD5、SHA0、SHA1、RIPENMD 等的成功攻击,美国国家标准技术研究所(NIST)在2005年、2006年分别举行了2届密码Hash 研讨会;同时于2007年正式宣布在全球范围内征集新的下一代密码Hash算法,举行SHA-3竞赛·新的Hash算法将被称为SHA-3,并且作为新的安全Hash标准,增强现有的FIPS 180-2标准。
3790 0
+关注
文章
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载