【Java】聊聊常用的摘要算法,比如MD5

摘要算法的特性

  • 摘要算法的目的的将信息进行简单地摘要,将任意长的信息摘要成固定长的信息。比如MD5,将任意长的信息摘要成128位的摘要。
  • 不可逆的,将报文摘要成一段信息后,无法通过摘要信息还原会报文。
  • 冲突性。一份报文跟其他报文的摘要信息有可能是一致的,即冲突的。一般来说,摘要算法会设计得冲突性尽量小。

常用的摘要算法有:MD5、SHA(Secure Hash Algorithm)等。下面介绍MD5。

MD5

MD,全文是Message Digest,即信息摘要的意思,是常用的信息摘要算法。

它是一种不可逆的算法,也就是说,假如将一个信息MD5摘要成一串代码,将不能通过这串代码还原回原来的信息。

使用的场景

出于这种特性,MD5常用来校验密码是否正确、校验下载文件是否完整无损。

-> 校验密码是否正确:将用户注册的密码MD5摘要后储存起来,待用户登录时将用户录入的密码MD5摘要,对比两次摘要后的信息是否相等,相等即密码正确。(这里如果加盐会更好,见后面章节)

-> 校验下载文件是否完整无损:我们常下载开源文件资源包时,可以看到网站上提供的该资源包的MD5(比如下载POI,如图一),下载文件完毕后,可通过自己的程序或直接去一些网站上计算其MD5码,如果与官网上提供的一致,则表示文件完整无损。(图二第3行日志可见,以下程序计算的MD5码与图一的官网截图一致)

直接进行MD5是否足够,为什么要加盐

如图一可见,123456的MD5码为e10adc3949ba59abbe56e057f20f883e。一般来说,MD5摘要的结果是128位的摘要信息,然后每4位用一个16进制字符表示,所有,MD5摘要的结果一般显示为32位的16进制。

如果你的系统用MD5摘要,并且无加盐,还经常使用123456为测试密码,对这一串MD5码一定很熟悉。这一些MD5码就静静地躺在DB中待校验。

如果数据库被暴露(比如拖库),坏人得到了这些MD5码,就可以通过常用密码与其MD5码的映射关系,轻而易举地翻译出大多数密码。

所以,一般来说,我们需要对原始密码进行加盐,所谓加盐,就是按照一定规则扰乱原有字符串,然后再进行MD5摘要。这个规则,自己定义,并且一定保密。

调用Spring工具类获取MD5码

目前Spring应用广泛,我们就直接使用Spring的api获取MD5码了。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>3.2.15.RELEASE</version>
</dependency>
View Code
package com.nicchagil.md5study;

import org.springframework.util.DigestUtils;

public class MD5UtilBySpring {
    
    /**
     * 使用MD5作信息摘要,并以十六进制表示
     */
    public static String md5(byte[] bytes) {
        return DigestUtils.md5DigestAsHex(bytes);
    }

    /**
     * 使用MD5作信息摘要,并以十六进制表示
     */
    public static String md5(String s) {
        if (s == null || s.length() == 0) {
            return null;
        }
        return MD5UtilBySpring.md5(s.getBytes());
    }
    
}
View Code
package com.nicchagil.md5study;

public class Salter {
    
    public static final String PREFIX = "HOW";
    public static final String FILLING = "ARE";
    public static final Integer FILLING_INDEX = 5;
    public static final String POSTFIX = "YOU!";
    
    public static String salt(String source) {
        if (source == null || source.length() == 0) {
            return null;
        }
        
        StringBuffer sb = new StringBuffer(source);
        if (sb.length() > FILLING_INDEX) {
            sb.insert(FILLING_INDEX, FILLING);
        }
        
        return sb.insert(0, PREFIX).append(POSTFIX).toString();
    }

}
View Code
package com.nicchagil.md5study;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;

import org.junit.Test;

public class HowToUse {
    
    @Test
    public void test() throws Exception {
        String source = "123456";
        String md5Hex = MD5UtilBySpring.md5(source);
        System.out.println(source + "'s hex md5 -> " + md5Hex);
    }
    
    @Test
    public void test2() throws Exception {
        File file = new File("d:/poi-bin-3.13-20150929.tar.gz");
        
        FileInputStream fis = null;
        ByteArrayOutputStream baos = null;
        try {
            fis = new FileInputStream(file);
            baos = new ByteArrayOutputStream();
            
            byte[] bytes = new byte[1024];
            int size = 0;
            while ((size = fis.read(bytes)) != -1) {
                if (size == 1024) {
                    baos.write(bytes);
                } else {
                    baos.write(bytes, 0, size);
                }
            }
            
            byte[] resultBytes = baos.toByteArray();
            System.out.println("size -> " + resultBytes.length);
            String md5Hex = MD5UtilBySpring.md5(resultBytes);
            System.out.println("Hex md5 -> " + md5Hex);
        } finally {
            if (fis != null) {
                fis.close();
            }
            if (baos != null) {
                baos.close();
            }
        }
    }
    
    @Test
    public void test3() throws Exception {
        String source = "123456";
        String saltSource = Salter.salt(source);
        String md5 = MD5UtilBySpring.md5(saltSource);
        System.out.println(source + " salt -> " + saltSource + " MD5 -> " + md5);
        
        source = "12345";
        saltSource = Salter.salt(source);
        md5 = MD5UtilBySpring.md5(saltSource);
        System.out.println(source + " salt -> " + saltSource + " MD5 -> " + md5);
        
        source = "1234";
        saltSource = Salter.salt(source);
        md5 = MD5UtilBySpring.md5(saltSource);
        System.out.println(source + " salt -> " + saltSource + " MD5 -> " + md5);
    }
    
}
View Code

图一

图二

原文地址:https://www.cnblogs.com/nick-huang/p/5067764.html