checksum簡(jiǎn)介
回憶一下幽纷,自己是否在網(wǎng)站上下載文件時(shí)看到過(guò)Checksum這個(gè)東西,一串字符串?
比如挠羔,我們到Apache網(wǎng)站上去下載用于操作Excel的依賴(lài)包 Apache POI,就可以看到checksum:SHA-256埋嵌, SHA-512
破加。以poi-bin-4.1.0-20190412.tar.gz
文件為例,點(diǎn)擊SHA-256和SHA-512的鏈接查看相關(guān)的值如下:
##SHA-256的值
d8db4f8228d87935ca46b0af72db68ad83f45b31d885e67b089d195b5ee800bb
##SHA-512的值
87499ab94882605ee2f407fc66e24c613ae98896b8d5f527b6cd8c604574922fc72d148da42962b2ee30ad18cd712e3de42bfe14770261b07217717c52a738a9
本文將簡(jiǎn)單介紹一下checksum(含義雹嗦,作用)以及如何使用java程序計(jì)算出不同算法的checksum值范舀,包括MD5
、SHA-1
了罪,SHA-256
以及SHA-512
锭环。
Checksum:總和檢驗(yàn)碼,校驗(yàn)和泊藕。在數(shù)據(jù)處理和數(shù)據(jù)通信領(lǐng)域中辅辩,用于校驗(yàn)?zāi)康牡囊唤M數(shù)據(jù)項(xiàng)的和。這些數(shù)據(jù)項(xiàng)可以是數(shù)字或在計(jì)算檢驗(yàn)總和過(guò)程中看作數(shù)字的其它字符串吱七。通常是以十六進(jìn)制為數(shù)制表示的形式汽久。
作用:用于檢查文件完整性,檢測(cè)文件是否被惡意篡改踊餐,比如文件傳輸(如插件景醇、固件升級(jí)包等)場(chǎng)景使用。
計(jì)算checksum
接下來(lái)吝岭,我們一起看下怎么使用java程序產(chǎn)生相關(guān)的checksum值三痰,本文以文件poi-bin-4.1.0-20190412.tar.gz
為例,具體可以通過(guò)如下路徑下載:
http://mirror.bit.edu.cn/apache/poi/release/bin/poi-bin-4.1.0-20190412.tar.gz
因?yàn)橐褂貌煌惴ǖ腸hecksum值窜管,包括MD5散劫、SHA-1,SHA-256以及SHA-512幕帆,先定義一個(gè)枚舉類(lèi)获搏,用于區(qū)分不同的算法。
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; }
}
接下來(lái)失乾,我們就來(lái)看看幾種計(jì)算文件checksum的方法:
- 使用
java.security.MessageDigest
- 使用
org.apache.commons.codec.digest.DigestUtils
- 使用
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
的方法來(lái)做纬乍,簡(jiǎn)化后的代碼如下:
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();
}
因?yàn)?code>DatatypeConverter.printHexBinary(digestBytes)返回的字符大寫(xiě),所以添加了toLowerCase()
方法保持其一致性裸卫。
使用org.apache.commons.codec.digest.DigestUtils
使用commons-codec來(lái)完成仿贬,Maven工程需要添加依賴(lài)包,如:
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.13</version>
</dependency>
簡(jiǎn)單代碼如下墓贿,通過(guò)調(diào)用類(lèi)DigestUtils的靜態(tài)方法完成指定checksum的計(jì)算即可:
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來(lái)完成茧泪,Maven工程需要添加依賴(lài)包,如:
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
簡(jiǎn)單代碼如下聋袋,通過(guò)調(diào)用com.google.common.io.Files
的hash
方法即可:
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;
}
驗(yàn)證
最后队伟,我們一起來(lái)驗(yàn)證一下上述幾種方法對(duì)文件的checksum計(jì)算。
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() + "計(jì)算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();
}
}
運(yùn)行結(jié)果如下:
采用MD5計(jì)算checksum
method=genChecksum1,checksum=2fa39c79790c29c53368ec0c14fdea97
method=genChecksum2,checksum=2fa39c79790c29c53368ec0c14fdea97
method=genChecksum3,checksum=2fa39c79790c29c53368ec0c14fdea97
采用SHA-256計(jì)算checksum
method=genChecksum1,checksum=d8db4f8228d87935ca46b0af72db68ad83f45b31d885e67b089d195b5ee800bb
method=genChecksum2,checksum=d8db4f8228d87935ca46b0af72db68ad83f45b31d885e67b089d195b5ee800bb
method=genChecksum3,checksum=d8db4f8228d87935ca46b0af72db68ad83f45b31d885e67b089d195b5ee800bb
采用SHA-512計(jì)算checksum
method=genChecksum1,checksum=87499ab94882605ee2f407fc66e24c613ae98896b8d5f527b6cd8c604574922fc72d148da42962b2ee30ad18cd712e3de42bfe14770261b07217717c52a738a9
method=genChecksum2,checksum=87499ab94882605ee2f407fc66e24c613ae98896b8d5f527b6cd8c604574922fc72d148da42962b2ee30ad18cd712e3de42bfe14770261b07217717c52a738a9
method=genChecksum3,checksum=87499ab94882605ee2f407fc66e24c613ae98896b8d5f527b6cd8c604574922fc72d148da42962b2ee30ad18cd712e3de42bfe14770261b07217717c52a738a9
采用SHA1計(jì)算checksum
method=genChecksum1,checksum=f56e42474fa81676d82a38ae6a8df67194a50b93
method=genChecksum2,checksum=f56e42474fa81676d82a38ae6a8df67194a50b93
method=genChecksum3,checksum=f56e42474fa81676d82a38ae6a8df67194a50b93
我們可以看到幽勒,計(jì)算結(jié)果和Apache上顯示的checksum是一致的缰泡。
總結(jié)
本文主要給出了三種計(jì)算checksum的方式,包括:
使用java.security.MessageDigest
使用org.apache.commons.codec.digest.DigestUtils
使用com.google.common.io.Files.hash
當(dāng)然代嗤,可能還有其它的實(shí)現(xiàn)方式和工具包,如果讀者發(fā)現(xiàn)其它的也可以同步一下缠借,一起學(xué)習(xí)干毅。
作者:孟君的編程札記
鏈接:https://www.imooc.com/article/290973?block_id=tuijian_wz
來(lái)源:慕課網(wǎng)