zoukankan      html  css  js  c++  java
  • 【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

    图一

    图二

  • 相关阅读:
    oracle 11g 中 (oracle 10g) crsctl 的 替换命令
    BZOJ 2792 Poi2012 Well 二分答案
    java基础入门-多线程同步浅析-以银行转账为样例
    CF 316div2 E.Pig and Palindromes
    Linux 性能监控 —— Load Average
    UISearchBar cancel 按钮设置文本
    UISlider 设置增量
    推荐一个在线json数据格式化网站
    解决ARC下performselector-may-cause-a-leak-because-its-selector-is-unknown 警告
    UITextView 添加 pleaceholder
  • 原文地址:https://www.cnblogs.com/nick-huang/p/5067764.html
Copyright © 2011-2022 走看看