文章目录
- 一 消息摘要
- 1.1 消息摘要的特点
- 1.2 消息摘要常见算法
- 1.3 数字摘要的运用举例:
- 1.4 字符串数字摘要演示
- 1.5 其他数字摘要算法演示
- 1.6 获取文件消息摘要
一 消息摘要
- 消息摘要(Message Digest)又称为数字摘要(Digital Digest)
- 它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash签名函数对消息进行作用而产生
- 使用数字摘要生成的值是不可以篡改的,为了保证文件或者值的安全
1.1 消息摘要的特点
- **无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。**例如应用MD5算法摘要的消息有128个比特位,用SHA-1算法摘要的消息最终有160比特位的输出
- 只要输入的消息不同,对其进行摘要以后产生的摘要消息也必不相同;但相同的输入必会产生相同的输出。换句话说,消息摘要的输入和输入信息有一一对应的特性。
- 消息摘要是单向,不可逆的
1.2 消息摘要常见算法
- SHA512在线签名和解密网站
- 消息摘要生成工具
- 总结:
- MD5算法 : 摘要结果16个字节, 转16进制后32个字节
- SHA1算法 : 摘要结果20个字节, 转16进制后40个字节
- SHA256算法 : 摘要结果32个字节, 转16进制后64个字节
- SHA512算法 : 摘要结果64个字节, 转16进制后128个字节
- MD5(Message-Digest Algorithm)
- MD5信息摘要算法,一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。
- MD5由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开,用以取代MD4算法。
- 该算法存在弱点,可以被加以破解,对于需要高度安全性的数据,一般建议改用其他算法,如SHA-2。MD5算法无法防止碰撞(collision),因此不适用于安全性认证,如SSL公开密钥认证或是数字签名等用途。
- SHA1(英语:Secure Hash Algorithm 1,中文名:安全散列算法1)
- SHA-1是一种密码散列函数,美国国家安全局设计,并由美国国家标准技术研究所(NIST)发布为联邦数据处理标准(FIPS)。
- SHA-1可以生成一个被称为消息摘要的160位(20字节)散列值,散列值通常的呈现形式为40个十六进制数。
- SHA256(Secure Hash Algorithm 2,安全哈希算法2)
- SHA-256作为SHA-2的一部分,目前已经是最流行的哈希算法之一。
- 安全签名算法通过将输入文本拆分成独立的片段,并通过这些独立的片段生成最终的结果——签名算法哈希值。这些签名算法哈希值几乎是唯一的字符串,因而它们往往被用作数据块的摘要"digest",指纹"figerprint"或签名"signature"。
- SHA-256算法往往被用来生成256位的签名。
- SHA512
- sha512是一种哈希算法,对给定的数据执行哈希函数。
- 由上图可知,它是一组称为SHA2的哈希算法的一部分。
- sha512是哈希大家庭里中的一个,哈希都有不可逆的特性。可以把理解为无法解密的签名。更准确来说,在原则上,sha512是无法反向解密的,但是对于简单的,常见的密码,有人会将结果保存下来,当你输入签名后的哈希值时,如果可以查询到原密码,则解码成功。但是相对于复杂的密码来说,由于SHA系列算法的数据摘要长度较长,因此其运算速度与MD5相比,也相对较慢。 不管是 SHA384还是SHA512,都是不可逆的,原则上是无法解密的。
- sha512具有不随机性,拿同一个密码生成的结果永远不会变。将C(密码)进行签名,得出D(结果)只要C不变,算法不变,次数不变,结果D是不变的。
1.3 数字摘要的运用举例:
-
在tomcat的官网下载界面,在下载连接的后面就有数字摘要的身影。
-
当点击相应的数字摘要连接,会展示该文件生成的结果。该算法在修改文件名称时,并不会影响签名运算的结果。所以,我们可以在本地对文件进行相应的签名运算后,与官方网站的内容进行对比,来验证下载文件是否被篡改或损坏。
-
这里采用64位win版进行验证,java代码如下:
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.security.MessageDigest;
public class DigestDemo2 {
public static void main(String[] args) throws Exception {
//将下载的tomcat文件放到src目录下
String sha512 = getDigestFile("src/apache-tomcat-11.0.0-M5-windows-x64.zip", "SHA-512");
System.out.println(sha512);
}
/**
* 获取文件的数字摘要
* @param filePath 表示文件的路径
* @param algorithm 表示算法
* @return
*/
private static String getDigestFile(String filePath, String algorithm) throws Exception{
// 通过io流的方式读取文件
//注意:FileInputStream默认情况目录为项目的根目录
FileInputStream fis = new FileInputStream(filePath);
// 定义长度
int len ;
// 定义一个字节数组
byte[] buffer = new byte[1024];
// 边读边写
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while (((len = fis.read(buffer) )!= -1)){
baos.write(buffer,0,len);
}
// 创建消息摘要对象
MessageDigest digest = MessageDigest.getInstance(algorithm);
// 执行消息摘要算法
byte[] digest1 = digest.digest(baos.toByteArray());
return toHex(digest1);
}
private static String toHex(byte[] digest) {
StringBuilder sb = new StringBuilder();
// 对密文进行迭代
for (byte b : digest) {
// 把密文转换成16进制
String s = Integer.toHexString(b & 0xff);
// 判断如果密文的长度是1,需要在高位进行补0
if (s.length() == 1){
s = "0"+s;
}
sb.append(s);
}
// 使用base64进行转码
return sb.toString();
}
}
1.4 字符串数字摘要演示
- 注意的点:
- 请使用
org.apache.commons.codec.binary.Base64;
类进行计算,需要导入的maven依赖为
<dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.15</version> </dependency>
- 在线网站的结果不是使用64进行编码,而使用16进制进行展示
- 验证计算结果
- 在线网站的计算结果
- 本地计算结果
- 请使用
1.5 其他数字摘要算法演示
import java.security.MessageDigest;
public class DigestDemo04 {
public static void main(String[] args) throws Exception{
// 原文
String input = "天道酬勤";
// 获取数字摘要对象
String md5 = getDigest(input, "MD5");
System.out.println(md5);
String sha1 = getDigest(input, "SHA-1");
System.out.println(sha1);
String sha256 = getDigest(input, "SHA-256");
System.out.println(sha256);
String sha512 = getDigest(input, "SHA-512");
System.out.println(sha512);
}
private static String getDigest(String input, String algorithm) throws Exception {
MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
// 消息数字摘要
byte[] digest = messageDigest.digest(input.getBytes());
System.out.println("密文的字节长度:" + digest.length);
return toHex(digest);
}
private static String toHex(byte[] digest) throws Exception {
// 创建对象用来拼接
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
// 转成 16进制
String s = Integer.toHexString(b & 0xff);
if (s.length() == 1){
// 如果生成的字符只有一个,前面补0
s = "0"+s;
}
sb.append(s);
}
System.out.println("16进制数据的长度:" + sb.toString().getBytes().length);
return sb.toString();
}
}
密文的字节长度:16
16进制数据的长度:32
d34ba38f8eb58109f5ba1ec4e0154517
密文的字节长度:20
16进制数据的长度:40
15313a15333413679c6b98e92b9b2770c3ca8b0b
密文的字节长度:32
16进制数据的长度:64
01afda71911617c438fe1e4e645affa70eebe693458731ce6eb8e9cec479288f
密文的字节长度:64
16进制数据的长度:128
396d16c3d8c03661d656f69c45da0d46f9aa02edd00a954da8960fe139f395d86f336d0a61d47932865e36cd56ed2d6e58e91f720d1523caa13bdedc124f35de
1.6 获取文件消息摘要
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.security.MessageDigest;
public class DigestDemo05 {
public static void main(String[] args) throws Exception{
String input = "aa";
String algorithm = "MD5";
// sha1 可以实现秒传功能
String sha5121 = getDigestFile("src/apache-tomcat-11.0.0-M5-windows-x64.zip", "SHA-512");
System.out.println(sha5121);
String sha5122 = getDigestFile("src/apache-tomcat-11.0.0.zip", "SHA-512");
System.out.println(sha5122);
String md5 = getDigest("aa", "MD5");
System.out.println(md5);
String md51 = getDigest("aa ", "MD5");
System.out.println(md51);
}
private static String getDigestFile(String filePath, String algorithm) throws Exception{
FileInputStream fis = new FileInputStream(filePath);
int len;
byte[] buffer = new byte[1024];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ( (len = fis.read(buffer))!=-1){
baos.write(buffer,0,len);
}
// 获取消息摘要对象
MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
// 获取消息摘要
byte[] digest = messageDigest.digest(baos.toByteArray());
System.out.println("密文的字节长度:"+digest.length);
return toHex(digest);
}
private static String getDigest(String input, String algorithm) throws Exception{
MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
byte[] digest = messageDigest.digest(input.getBytes());
System.out.println("密文的字节长度:"+digest.length);
return toHex(digest);
}
private static String toHex(byte[] digest) {
// 消息摘要进行表示的时候,是用16进制进行表示
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
// 转成16进制
String s = Integer.toHexString(b & 0xff);
// 保持数据的完整性,前面不够的用0补齐
if (s.length()==1){
s="0"+s;
}
sb.append(s);
}
System.out.println("16进制数据的长度:"+ sb.toString().getBytes().length);
return sb.toString();
}
}
- 结论1:改变文件名称,摘要结果不会改变!
- 结论2:改变原文,摘要结果改变