定义

MD全称Message-Digest,即信息摘要,所以MD家族的算法也叫信息摘要算法

MD家族有MD2、MD3、MD4、MD5,一代比一代强。

所以MD5是MD算法家族中,目前最常用的一种加密算法。

任何信息,都可以通过MD5算法运算生成一个16字节(128位)的散列值,但却无法通过这16个字节的散列值获得加密前的信息。

最终这16个散列值,通常用一个长度为32的十六进制字符串来表示。

这就是MD5最重要的一个特性:加密不可逆。

MD5特点

加密不可逆,即无法通过密文得到原文。

不变性,即相同的原文,通过MD5算法得到的密文总是相同的。

散列性,即对原文作轻微的改动,都可导致最终的密文完全改变。

常见应用场景

1、校验文件的完整性

如果张三给李四传了一个文件,如何确认这个文件传给李四是完整的呢

张三传文件前,先对文件做一个MD5加密,同时把MD5加密的密文传给李四

李四收到文件,也对该文件做MD5加密,如果得到的密文和张三给的密文一样,就说明文件是完整的。

2、存储用户密码

用户密码,理论上也不能直接明文存储在数据库中,因为一旦数据库被破解,用户的密码就全部丢失了

所以可以将用户密码做一个MD5加密,然后将密文存在数据库中

用户登录的时候,可以将用户的密码进行MD5加密,然后比对密文和数据库中的密文是否一致,来判断用户前台填的密码是否正确。

这只是一个思路,一般不会这么简单,一般生产环境会对用户密码加盐加密等等的处理,用户信息更加重要的,则需要更加复杂的计算逻辑。

原理

MD5的加密过程,整体来看,就是先定义四个值,然后用这四个值,对原文信息进行计算,并得到新的四个值,然后再对原文进行计算,再得到新的四个值,如此循环一定次数,最终对最后的这四个值进行简单的字符串拼接,就得到了最终的密文。

主要就是下面这3步:

1、填补信息

用原文长度位数对512求余,如果结果不为448,就填充到448位。填充是第一位填1,后面填0。512-448=64,用这剩余的64位,记录原文长度。

最终得到一个填补完的信息(总长=原文长度 512位)

2、拿到初始值

四个初始值,是MD5这个算法提前定义好的,分别是4个32位的值,总共刚好128位。

我们用ABCD命名:

  • A=0x01234567
  • B=0x89ABCDEF
  • C=0xFEDCBA98
  • D=0x76543210

3、真正的计算

计算分为多次循环,每次循环,都是用ABCD和原文在第一步填补完的信息,进行计算,最终得到新的ABCD。最后将最后一次ABCD拼成字符串,就是最终的密文。

  • 循环先分为主循环,每个主循环中又套有子循环。
  • 主循环次数 = 原文长度/512。
  • 子循环次数 = 64次。

我们看看单次子循环都做了什么:

下面是单次子循环真正的计算逻辑(这段实现摘自网友):

在这里插入图片描述

图中,A,B,C,D就是哈希值的四个分组。每一次循环都会让旧的ABCD产生新的ABCD。一共进行多少次循环呢?由处理后的原文长度决定。

  • 假设处理后的原文长度是M
  • 主循环次数 = M / 512
  • 每个主循环中包含 512 / 32 * 4 = 64 次 子循环。

上面这张图所表达的就是单次子循环的流程。

下面对图中其他元素一一解释:

1.绿色F

图中的绿色F,代表非线性函数。官方MD5所用到的函数有四种:

F(X, Y, Z) =(X&Y) | ((~X) & Z)
G(X, Y, Z) =(X&Z) | (Y & (~Z))
H(X, Y, Z) =X^Y^Z
I(X, Y, Z)=Y^(X|(~Z))

在主循环下面64次子循环中,F、G、H、I 交替使用,第一个16次使用F,第二个16次使用G,第三个16次使用H,第四个16次使用I。

2.红色“田”字

很简单,红色的田字代表相加的意思。

3.Mi

Mi是第一步处理后的原文。在第一步中,处理后原文的长度是512的整数倍。把原文的每512位再分成16等份,命名为M0 ~ M15,每一等份长度32。在64次子循环中,每16次循环,都会交替用到M1 ~ M16之一。

4.Ki

一个常量,在64次子循环中,每一次用到的常量都是不同的。

5.黄色的<<

FF(a,b,c,d,Mj,s,ti)表示a=b ((a F(b,c,d) Mj ti)<<<s)

<<<s表示循环左移s位

第一轮
 a=FF(a,b,c,d,M0,7,0xd76aa478)
 b=FF(d,a,b,c,M1,12,0xe8c7b756)
 c=FF(c,d,a,b,M2,17,0x242070db)
 d=FF(b,c,d,a,M3,22,0xc1bdceee)
 a=FF(a,b,c,d,M4,7,0xf57c0faf)
 b=FF(d,a,b,c,M5,12,0x4787c62a)
 c=FF(c,d,a,b,M6,17,0xa8304613)
 d=FF(b,c,d,a,M7,22,0xfd469501)
 a=FF(a,b,c,d,M8,7,0x698098d8)
 b=FF(d,a,b,c,M9,12,0x8b44f7af)
 c=FF(c,d,a,b,M10,17,0xffff5bb1)
 d=FF(b,c,d,a,M11,22,0x895cd7be)
 a=FF(a,b,c,d,M12,7,0x6b901122)
 b=FF(d,a,b,c,M13,12,0xfd987193)
 c=FF(c,d,a,b,M14,17,0xa679438e)
 d=FF(b,c,d,a,M15,22,0x49b40821)
 
第二轮
 a=GG(a,b,c,d,M1,5,0xf61e2562)
 b=GG(d,a,b,c,M6,9,0xc040b340)
 c=GG(c,d,a,b,M11,14,0x265e5a51)
 d=GG(b,c,d,a,M0,20,0xe9b6c7aa)
 a=GG(a,b,c,d,M5,5,0xd62f105d)
 b=GG(d,a,b,c,M10,9,0x02441453)
 c=GG(c,d,a,b,M15,14,0xd8a1e681)
 d=GG(b,c,d,a,M4,20,0xe7d3fbc8)
 a=GG(a,b,c,d,M9,5,0x21e1cde6)
 b=GG(d,a,b,c,M14,9,0xc33707d6)
 c=GG(c,d,a,b,M3,14,0xf4d50d87)
 d=GG(b,c,d,a,M8,20,0x455a14ed)
 a=GG(a,b,c,d,M13,5,0xa9e3e905)
 b=GG(d,a,b,c,M2,9,0xfcefa3f8)
 c=GG(c,d,a,b,M7,14,0x676f02d9)
 d=GG(b,c,d,a,M12,20,0x8d2a4c8a)
 
第三轮
 a=HH(a,b,c,d,M5,4,0xfffa3942)
 b=HH(d,a,b,c,M8,11,0x8771f681)
 c=HH(c,d,a,b,M11,16,0x6d9d6122)
 d=HH(b,c,d,a,M14,23,0xfde5380c)
 a=HH(a,b,c,d,M1,4,0xa4beea44)
 b=HH(d,a,b,c,M4,11,0x4bdecfa9)
 c=HH(c,d,a,b,M7,16,0xf6bb4b60)
 d=HH(b,c,d,a,M10,23,0xbebfbc70)
 a=HH(a,b,c,d,M13,4,0x289b7ec6)
 b=HH(d,a,b,c,M0,11,0xeaa127fa)
 c=HH(c,d,a,b,M3,16,0xd4ef3085)
 d=HH(b,c,d,a,M6,23,0x04881d05)
 a=HH(a,b,c,d,M9,4,0xd9d4d039)
 b=HH(d,a,b,c,M12,11,0xe6db99e5)
 c=HH(c,d,a,b,M15,16,0x1fa27cf8)
 d=HH(b,c,d,a,M2,23,0xc4ac5665)
 
第四轮
 a=II(a,b,c,d,M0,6,0xf4292244)
 b=II(d,a,b,c,M7,10,0x432aff97)
 c=II(c,d,a,b,M14,15,0xab9423a7)
 d=II(b,c,d,a,M5,21,0xfc93a039)
 a=II(a,b,c,d,M12,6,0x655b59c3)
 b=II(d,a,b,c,M3,10,0x8f0ccc92)
 c=II(c,d,a,b,M10,15,0xffeff47d)
 d=II(b,c,d,a,M1,21,0x85845dd1)
 a=II(a,b,c,d,M8,6,0x6fa87e4f)
 b=II(d,a,b,c,M15,10,0xfe2ce6e0)
 c=II(c,d,a,b,M6,15,0xa3014314)
 d=II(b,c,d,a,M13,21,0x4e0811a1)
 a=II(a,b,c,d,M4,6,0xf7537e82)
 b=II(d,a,b,c,M11,10,0xbd3af235)
 c=II(c,d,a,b,M2,15,0x2ad7d2bb)
 d=II(b,c,d,a,M9,21,0xeb86d391)

MD5为什么不可逆

MD5不可逆的原因,从原理上来看,

  • 第一是他使用了散列函数,即上面的FGHI函数。
  • 第二是他在里面用了大量的移位操作,即<<<,这些是不可逆的

比如有10110011,我们左移三位,变成了10011000,高三位的101被顶了,低三位用0代替了,那此时就绝对不可能用10011000再逆向得到10110011了。

java实现和使用

public class MD5Util {
    public static void main(String[] args) throws IOException {
        System.out.println(encodeString("123"));
    }
    public static String encodeString(String plainText) throws UnsupportedEncodingException {
        return encodeBytes(plainText.getBytes("UTF-8"));
    }
    public static String encodeBytes(byte[] bytes) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(bytes);
            byte b[] = md.digest();
            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset  ) {
                i = b[offset];
                if (i < 0) {
                    i  = 256;
                }
                if (i < 16) {
                    buf.append("0");
                }
                buf.append(Integer.toHexString(i));
            }
            return buf.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持Devmax。 

关于MD5算法原理与常用实现方式的更多相关文章

  1. 用Swift实现MD5算法&amp;引入第三方类库MBProgressHUD

    之前项目里面是用objc写的MD5加密算法,最近在用swift重写以前的项目,遇到了这个问题。顺带解决掉的还有如何引入第三方的类库,例如MBProgressHUD等一些特别好的控件解决的方法其实是用objc和swift混合编程的方法,利用Bridging-header文件。你可以简单的理解为在一个用swift语言开发的工程中,引入objective-c文件是需要做的一个串联文件,好比架设了一个桥,让swift中也可以调用objective-c的类库和frame等等。

  2. swift排序算法和数据结构

    vararrayNumber:[Int]=[2,4,216)">6,216)">7,216)">3,216)">8,216)">1]//冒泡排序funcmaopao->[Int]{forvari=0;i

  3. swift - 函数指针的应用 - 避免重复算法

    =nil;})}privatefuncsearch(selector:(Employee->Bool))->[Employee]{varresults=[Employee]();foreinemployees{if(selector(e)){results.append(e);}}returnresults;}}

  4. 如何用 Swift 实现 A* 寻路算法

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. swift算法实践1

    在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,所以,这种表示法也称为中缀表示。波兰逻辑学家J.Lukasiewicz于1929年提出了另一种表示表达式的方法。逆波兰表达式,它的语法规定,表达式必须以逆波兰表达式的方式给出。如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。倘若不是的话,则将栈顶的运算符从栈中弹出,直到栈顶运算符的优先级低于当前运算符,将该字符入栈。

  6. swift算法实践2

    字符串hash算法Time33在效率和随机性两方面上俱佳。对于一个Hash函数,评价其优劣的标准应为随机性,即对任意一组标本,进入Hash表每一个单元之概率的平均程度,因为这个概率越平均,数据在表中的分布就越平均,表的空间利用率就越高。Times33的算法很简单,就是不断的乘33,见下面算法原型。

  7. swift算法实践3)-KMP算法字符串匹配

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  8. swift算法实践4)-trie自动机

    1、trie自动机是识别字符串的确定性有向无环自动机2、图示3、构造代码F包括了状态q所对应的P中的字符串

  9. Swift 算法实战之路一

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  10. Swift 算法实战之路二

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部