1. 基础信息:

  • MD5算法,全称MD5信息摘要算法(MD5 Message-Digest Algorithm),是一种广泛使用的密码散列函数,可以产生128位 / 16字节的散列值(hash value),用于确保信息传输完成一致。
  • 将不定长的数据变为固定长度的数据,这是散列算法的基础原理。
  • MD5算法可破解,且无法防止碰撞(collision)。高度安全性的数据或是安全性认证,不适用MD5。

2. 算法基础实现:

  • 算法输入输出

    • 输入:任意长度数据;
    • 输出:固定长度128 bits的数据。
  • 内部逻辑
    • 填充

      • 将输入信息长度填充到N,此时N mod 512 = 448;
      • 当原输入信息长度本就满足N mod 512 = 448时,需填充512位;
      • 填充方法为先一个1,后续全0。
    • 记录信息长度
      • 剩余64位用于记录填充前输入信息的长度。
    • 初始化4个32位整数A、B、C、D
      • A = 0x67452301, B = 0xefcdab89, C = 0x98badcfe, D = 0x10325476;
    • 循环运算
      • 将ABCD和512位的数据经过运算,输出128位结果,根据数据位高低赋值于A、B、C、D中,继续循环直至结束。
      • PS:MD5具体的计算流程源码可见sun.security.provider.MD5
    • 输出由32位的A、B、C、D拼接而成的128位的结果

3. 用途:

  • 防止被篡改:

    • 比如发送一个电子文档,发送前先得出一个MD5值,在对方接收到文件后,核对MD5值,能避免文档被篡改;
    • 文件、程序下载同样,若下载到的程序被修改过,相应的MD5值就会发生变化。
  • 用于加密明文:
    • 例如数据库中存储用户信息如密码时,可以直接存储经过MD5加密的密码,用户校验可以直接在后台进行。这样做既保证了存储安全,又降低了数据丢失的损害。
  • 数字签名:
    • 这种做法类似于防止电子文档篡改,第三方机构能通过MD5对A签署的一份文件进行摘要,后续在证明一份电子文件是否是原文件时能进行直接比对。

4. 安全性:

  • MD5本身是不可逆的,所以严格上来说不算一种加解密方式。通常认为MD5的安全性很高,暴力破解的时间很长,但实际上单纯的使用MD5是很容易被破解。因为市面上存在大量的彩虹表,也就是相当于提前准备好了一套字符串-Hash值对应表,对于一些常规的字符段,很容易就能查到对应的MD5值。
  • 这也是市面上很多MD5破解网站的思路。

5. Java中使用MD5:

  • Java自身提供了一套完整的密码学架构JCA,通过JCA能直接使用到MD5或是SHA等信息摘要算法。

    // MD5字符串是用于指定需要的摘要算法名称
    String str = "HelloWorld";
    byte[] bytes = MessageDigest.getInstance("MD5").digest(str.getBytes("UTF-8"));
    

6. 更完善的MD5:加盐

  • 为什么加盐?

    • 因为明文相同,经过MD5后的密文也就相同,这就能通过彩虹表暴力碰撞直接查出明文了。
    • 如果在明文中加入随机数,在过一遍MD5,每次的密文也就不同了,加大了破解的难度。
  • 加盐只是给定了逻辑和方向,实际情况下可以根据情况设计加盐的方式

  • 在输入字符串后加上长度为16的随机数字串为例,必然是需要将这个数字串保存到一个地方。

    • 比如,将加盐后的长度为32的16进制表示的MD5输出值,扩充为长度48的16进制字符串。
    • 步长为3,每个分组中前2个为MD5输出值,最后一个为数字串依次的值
    • 这样在校验数据时,就能保证能提取出盐本身的信息,并完成数据校验了。
  • 加盐的方式还有很多,这只是一种解决方案。

7. 更好的封装:commons-codec

  • JCA本身并没有提供加盐的方法(可能是我没找到),所以对于这一点市面上存在更好的封装,也就是commons-codec,本质上这个封装底层还是使用的JCA相关的实现。

    <!-- maven依赖 这里的版本是1.14,可以根据自己的情况定制
    -->
    <dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.14</version>
    </dependency>
    
  • commons-codec包提供了一个DigestUtils工具类,能实现最基础的MD5加密功能。

    String str = "HelloWorld";
    // 底层其实也是调用的 MessageDigest.getInstance("MD5").digest(byte[] input)方法
    byte[] bytes = DigestUtils.md5(str.getBytes("UTF-8"));// 同时commons-codec直接提供将MD5后输出的byte[]直接转化为16进制字符串的方法
    // String DigestUtils.md5Hex(String str);
    // String DigestUtils.md5Hex(byte[] input);
    
  • commons-codec包同时也提供了MD5加盐的封装Md5Crypt工具类。

    String str = "HelloWorld", salt = "Java";// 该方法在不指定盐时,方法默认会随机构造一个长度为8的字符串盐
    // 随机实现使用的是java.security.SecureRandom
    String result = Md5Crypt.md5Crypt(str.getBytes("UTF-8"));// 这个类还提供了另一类方法统称为Md5Crypt.apr1Crypt();
    // String result = Md5Crypt.apr1Crypt(str.getBytes("UTF-8"));
    
    • 当指定盐值时,需要注意盐要注意指定前缀。允许的前缀有两种

      • “$apr1$” 或者 “$1$”

      其实两者的实际差别几乎没有,只是因为在实现中会将前缀也放入MD5处理过程中如下,所以同样的输入和盐可能输出结果不同罢了。

    String result2 = Md5Crypt.md5Crypt(str.getBytes("UTF-8"), "$1$" + salt);// 但这里有特殊点
    // 对于另一个方法Md5Crypt.apr1Crypt(),并不需要指定前缀
    // 这倒让我觉得前者是代码人员的失误了
    // String result2 = Md5Crypt.apr1Crypt(str.getBytes("UTF-8"), salt);
    
    • 方法的返回值也具有格式特殊性,基本格式是$ + prefix + $ + salt + $ + md5_result。三个部分由$分隔开,因此在取出salt值时可以使用正则表达式实现数据校验。
    String str = "HelloWorld", salt = "Java";String result = Md5Crypt.md5Crypt(str.getBytes("UTF-8"), "$1$" + salt);
    // result = $1$Java$4bCRZ5vxppArDR5eMq30M0
    String result2 = Md5Crypt.apr1Crypt(string, salt);
    // result2 = $apr1$Java$4n4eOBC4fkHaZdC.j7NiQ/
    
    • 关于common-codec的MD5加盐部分,我个人觉得还是使用随机生成的盐,也就是直接使用直接传入字节数组就行,会比指定盐好很多。但我始终不理解这两种方式到底有什么区别,还望有大佬指教一下。

8. 结尾:

  • 关于MD5的那些事就说到这里了,原理部分没涉及太多,因为MD5的原理确实说不上简单。

  • 但是总的来说对MD5的使用应该是理通了,如果有什么错误的地方还望指教(轻喷)。

  • 希望以这个【必知必会】系列激励自己不断学习!!!

  • 参考文档,感谢各位博主的分析和分享:

    • https://blog.csdn.net/u012611878/article/details/54000607
    • https://www.cnblogs.com/peaceliu/p/7825706.html

程序猿必知必会[EP1]MD5算法相关推荐

  1. 程序员必知必会之maillist篇

    程序员必知必会之maillist篇        本文最初由恋花蝶发表于http://blog.csdn.net/lanphaday,可以随意转载,但未经同意不得增删修改,转载应保留本声明,否则追究责 ...

  2. 程序员必知必会之blog篇

    程序员必知必会之blog篇 网易广州       赖勇浩(http://blog.csdn.net/lanphaday) 本文最初发表于恋花蝶的博客(http://blog.csdn.net/lanp ...

  3. Python 程序员必知必会的开发者工具

    Python 程序员必知必会的开发者工具 Python已经演化出了一个广泛的生态系统,该生态系统能够让Python程序员的生活变得更加简单,减少他们重复造轮的工作.同样的理念也适用于工具开发者的工作, ...

  4. 程序员必知必会之 word 篇

    程序员必知必会之 word 篇 网易广州 赖勇浩 程序员必知必会之blog篇 地址:http://blog.csdn.net/lanphaday/archive/2007/08/16/1746852. ...

  5. 程序员必知必会之计算机系统概论

    程序员必知必会之计算机系统概论

  6. 猿创征文|计算机类学生必知必会的开发工具

    计算机类学生必知必会的开发工具目录 前言 一.浏览器工具 1.在线工具 2.插件扩展 二.优化电脑使用工具 1.notpad++ 2.plotplayer 3.Office Tool Plus--强大 ...

  7. 操作系统:手把手带你扫盲 操作系统 的那些必知必会!

    前言 操作系统 应是程序猿需掌握的知识,但往往会被忽略 今天,我将手把手带大家扫盲 操作系统 的那些必知必会!希望你们会喜欢. 目录 1. 跨进程通信方式(IPC) 注:此处给出移动端 Android ...

  8. 【计算机网络】网络基础必知必会

    网络基础必知必会 网络协议的体系结构 OSI 参考模型:应用层.表示层.会话层.传输层.网络层.数据链路层.物理层 五层协议的体系结构:应用层.传输层.网络层.数据链路层.物理层 TCP / IP 体 ...

  9. Java架构师必知必会,带走不谢

    可以说,Java是现阶段中国互联网公司中,覆盖度最广的研发语言,掌握了Java技术体系,不管在成熟的大公司,快速发展的公司,还是创业阶段的公司,都能有立足之地. 成为Java架构师,需要掌握哪些技能呢 ...

最新文章

  1. 和12岁小同志搞创客开发:Mind+编程软件简介、安装及使用
  2. Emptiness 空值语义
  3. 柔宇冲刺科创板IPO:3年营收5亿净亏31亿,乐视掘墓人刘姝威坐镇董事会
  4. #时间预测算法_【时间序列】时序预测竞赛之异常检测算法综述
  5. 使用 Warshall(沃舍尔)算法求解关系的传递闭包
  6. 哈希表和红黑树的对比
  7. cesium 3dtiles 加载本地数据_深入echarts学习:加载跨域、异步、本地json数据的防坑录
  8. java 删除二进制内容_二进制搜索树节点删除不删除替换Java
  9. java 守护进程 linux_Java使用appache deamon实现linux守护进程
  10. 问答| 为什么汽车会采用前轮转向,后轮驱动的方式?为什么反过来的搭配方式很少见?
  11. !heap 和 _HEAP_ENTRY
  12. 为什么自建深度学习机器?因为比AWS便宜10倍啊!
  13. matlab 对称矩阵特征值为负数,【原创】古典Jaccobi方法计算实对称矩阵A的特征值和向...
  14. [请您去投票]ESRI中国社区2008年度优秀会员评选
  15. 2022 最新 Memcached 面试题
  16. 牛客真题编程——day16
  17. 针对灰产外挂的分析与研究
  18. Ubuntu 16.04下的美化配置过程
  19. java thread yield()_Java Thread yield()方法
  20. 用c语言验证欧拉定理,欧拉定理_欧拉定理的意义

热门文章

  1. 淘淘商城第77讲——实现商品详情页面展示
  2. 客厅的走廊应该怎么去设计
  3. 招生难、管理难!教育如何实现零流失、高增长?教育行业如何玩转“私域流量”?...
  4. 速途网范锋:重要合作可能决定网络企业生死
  5. 内蒙古最新八大员安全员模拟真题题库及答案
  6. Flutter 全能型选手GetX —— 状态管理
  7. Python神器!只需一行代码,纯文本秒变Markdown!
  8. U-BOOT启动流程【03】
  9. 打开*.acb格式音频文件
  10. 健身健美减脂、脱水、充碳记录