计算文件Checksum的几种方法

checksum简介

回忆一下,自己是否在网站上下载文件时看到过Checksum这个东西,一串字符串?

比如,我们到Apache网站上去下载用于操作Excel的依赖包 Apache POI,就可以看到checksum:SHA-256, SHA-512。以poi-bin-4.1.0-20190412.tar.gz文件为例,点击SHA-256和SHA-512的链接查看相关的值如下:

##SHA-256的值
d8db4f8228d87935ca46b0af72db68ad83f45b31d885e67b089d195b5ee800bb

##SHA-512的值
87499ab94882605ee2f407fc66e24c613ae98896b8d5f527b6cd8c604574922fc72d148da42962b2ee30ad18cd712e3de42bfe14770261b07217717c52a738a9

本文将简单介绍一下checksum(含义,作用)以及如何使用java程序计算出不同算法的checksum值,包括MD5SHA-1SHA-256以及SHA-512

Checksum:总和检验码,校验和。在数据处理和数据通信领域中,用于校验目的的一组数据项的和。这些数据项可以是数字或在计算检验总和过程中看作数字的其它字符串。通常是以十六进制为数制表示的形式。
作用:用于检查文件完整性,检测文件是否被恶意篡改,比如文件传输(如插件、固件升级包等)场景使用。

计算checksum

接下来,我们一起看下怎么使用java程序产生相关的checksum值,本文以文件poi-bin-4.1.0-20190412.tar.gz为例,具体可以通过如下路径下载:

http://mirror.bit.edu.cn/apache/poi/release/bin/poi-bin-4.1.0-20190412.tar.gz

因为要使用不同算法的checksum值,包括MD5、SHA-1,SHA-256以及SHA-512,先定义一个枚举类,用于区分不同的算法。

package com.wangmengjun.tutorial.checksum;
 
public enum CheckSumAlgoType {
  MD5("MD5"), SHA_256("SHA-256"), SHA_512("SHA-512"), SHA_1("SHA1"); 
  private String name;
  private CheckSumAlgoType(String name) {    
      this.name = name;  
  }
  public String getName() {    return name;  }
  public void setName(String name) {    this.name = name;  }
}

接下来,我们就来看看几种计算文件checksum的方法:

  1. 使用java.security.MessageDigest
  2. 使用org.apache.commons.codec.digest.DigestUtils
  3. 使用com.google.common.io.Files.hash

使用java.security.MessageDigest

public static String genChecksum1(File file, String checkSumAlgo) throws NoSuchAlgorithmException, IOException {    
    MessageDigest messageDigest = MessageDigest.getInstance(checkSumAlgo);    
    messageDigest.update(Files.readAllBytes(file.toPath()));    
    byte[] digestBytes = messageDigest.digest();    
    StringBuffer sb = new StringBuffer();    
    for (byte b : digestBytes) {      
        sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));    
    }    
    return sb.toString();  
}

其中,下面的这段代码

StringBuffer sb = new StringBuffer();    
for (byte b : digestBytes) {      
    sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));    
}    
return sb.toString();

可以使用javax.xml.bind.DatatypeConverter的方法来做,简化后的代码如下:

public static String genChecksum1(File file, String checkSumAlgo) throws NoSuchAlgorithmException, IOException {    
        MessageDigest messageDigest = MessageDigest.getInstance(checkSumAlgo);    
        messageDigest.update(Files.readAllBytes(file.toPath()));    
        byte[] digestBytes = messageDigest.digest();    
        return DatatypeConverter.printHexBinary(digestBytes).toLowerCase();  
}

因为DatatypeConverter.printHexBinary(digestBytes)返回的字符大写,所以添加了toLowerCase()方法保持其一致性。

使用org.apache.commons.codec.digest.DigestUtils

使用commons-codec来完成,Maven工程需要添加依赖包,如:

<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>    
    <groupId>commons-codec</groupId>    
    <artifactId>commons-codec</artifactId>    
    <version>1.13</version>
</dependency>

简单代码如下,通过调用类DigestUtils的静态方法完成指定checksum的计算即可:

public static String genChecksum2(File file, CheckSumAlgoType checkSumAlgoType)      throws FileNotFoundException, IOException {    
/**     * 使用org.apache.commons.codec.digest.DigestUtils     */    
        String checksum = null;    
        switch (checkSumAlgoType) {    
            case MD5:      
                checksum = DigestUtils.md5Hex(new FileInputStream(file));      
                break;
            case SHA_1:      
                checksum = DigestUtils.sha1Hex(new FileInputStream(file));      
                break;
            case SHA_256:      
                checksum = DigestUtils.sha256Hex(new FileInputStream(file));      
                break;    
            case SHA_512:      
                checksum = DigestUtils.sha512Hex(new FileInputStream(file));      
                break;    
            default:      
                checksum = DigestUtils.md5Hex(new FileInputStream(file));    
        }
        return checksum;  
}

使用com.google.common.io.Files.hash

使用Guava来完成,Maven工程需要添加依赖包,如:

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>    
    <groupId>com.google.guava</groupId>    
    <artifactId>guava</artifactId>    
    <version>23.0</version>
</dependency>

简单代码如下,通过调用com.google.common.io.Fileshash方法即可:

public static String genChecksum3(File file, CheckSumAlgoType checkSumAlgoType) throws IOException {    
        /**     * 使用Guava     */    
        String checksum = null;    
        switch (checkSumAlgoType) {    
            case MD5:      
                checksum = com.google.common.io.Files.hash(file, Hashing.md5()).toString();
                break;    
            case SHA_1:      
                checksum = com.google.common.io.Files.hash(file, Hashing.sha1()).toString();      
                break;
            case SHA_256:      
                checksum = com.google.common.io.Files.hash(file, Hashing.sha256()).toString();      
                break;    
            case SHA_512:      
                checksum = com.google.common.io.Files.hash(file, Hashing.sha512()).toString();      
                break;    
            default:      
                checksum = com.google.common.io.Files.hash(file, Hashing.md5()).toString();    
        }    
        return checksum;  
}

验证

最后,我们一起来验证一下上述几种方法对文件的checksum计算。

public static void main(String[] args) throws NoSuchAlgorithmException, IOException {    
File file = new File("/users/wmj/Downloads/poi-bin-4.1.0-20190412.tar.gz");    
        for (CheckSumAlgoType type : CheckSumAlgoType.values()) {      
            System.out.println("采用" + type.getName() + "计算checksum");      
            System.out.println(          String.format("method=%s,checksum=%s", "genChecksum1", genChecksum1(file, type.getName())));      
            System.out.println(String.format("method=%s,checksum=%s", "genChecksum2", genChecksum2(file, type)));      
            System.out.println(String.format("method=%s,checksum=%s", "genChecksum3", genChecksum3(file, type)));      
            System.out.println();    
        }  
}

运行结果如下:

采用MD5计算checksum
method=genChecksum1,checksum=2fa39c79790c29c53368ec0c14fdea97
method=genChecksum2,checksum=2fa39c79790c29c53368ec0c14fdea97
method=genChecksum3,checksum=2fa39c79790c29c53368ec0c14fdea97


采用SHA-256计算checksum
method=genChecksum1,checksum=d8db4f8228d87935ca46b0af72db68ad83f45b31d885e67b089d195b5ee800bb
method=genChecksum2,checksum=d8db4f8228d87935ca46b0af72db68ad83f45b31d885e67b089d195b5ee800bb
method=genChecksum3,checksum=d8db4f8228d87935ca46b0af72db68ad83f45b31d885e67b089d195b5ee800bb

采用SHA-512计算checksum
method=genChecksum1,checksum=87499ab94882605ee2f407fc66e24c613ae98896b8d5f527b6cd8c604574922fc72d148da42962b2ee30ad18cd712e3de42bfe14770261b07217717c52a738a9
method=genChecksum2,checksum=87499ab94882605ee2f407fc66e24c613ae98896b8d5f527b6cd8c604574922fc72d148da42962b2ee30ad18cd712e3de42bfe14770261b07217717c52a738a9
method=genChecksum3,checksum=87499ab94882605ee2f407fc66e24c613ae98896b8d5f527b6cd8c604574922fc72d148da42962b2ee30ad18cd712e3de42bfe14770261b07217717c52a738a9

采用SHA1计算checksum
method=genChecksum1,checksum=f56e42474fa81676d82a38ae6a8df67194a50b93
method=genChecksum2,checksum=f56e42474fa81676d82a38ae6a8df67194a50b93
method=genChecksum3,checksum=f56e42474fa81676d82a38ae6a8df67194a50b93

我们可以看到,计算结果和Apache上显示的checksum是一致的。

总结

本文主要给出了三种计算checksum的方式,包括:

使用java.security.MessageDigest
使用org.apache.commons.codec.digest.DigestUtils
使用com.google.common.io.Files.hash

当然,可能还有其它的实现方式和工具包,如果读者发现其它的也可以同步一下,一起学习。

作者:孟君的编程札记
链接:https://www.imooc.com/article/290973?block_id=tuijian_wz
来源:慕课网

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350