MD5是用来加密的吗?BCrypt又是什么呢?

前言

最近经常看到一种关于 MD5 的说法,比如某某系统的登录模块使用了 MD5 加密算法,保证了用户密码的安全。那么 MD5 究竟是不是一种加密算法呢?从概念上来说『加密』对应的是『解密』,我们把数据采用某种方式加密之后,可以在之后的某一时刻进行解密来获得原始数据,照此观点来说 MD5 并不是一种加密算法,它只能把原文加密成密文,而不能将密文解密成原文。但是 MD5 确实把明文变成了不容易被破解的密文,达到了 “加密” 的目的,好像说它可以用来加密勉强也可以。

更准确的说法,MD5 是一种哈希算法,又叫散列算法或者摘要算法,是一类把任意长度数据转换为定长数据的算法统称,它广泛应用于错误检查,经常通过计算 MD5 来检验下载到的文件的完整性,优秀的哈希算法通常需要具有低碰撞概率,MD5 就是其中的一种。

MD5的八卦

可用于处理密码,是不可逆的

刚刚前面已经提到它可以把原始数据变成定长的摘要信息,而不能把摘要信息再还原成原始数据。就比如 110+119=229,通过原始信息 110 和 119 可以转化成摘要信息229,而已知229却无法知道它是由那两个数相加得到的,当然这个例子只是象征性的,它的碰撞率太高了。

既然不可逆,那么怎样才能判断密码信息呢?这可以利用比较hash值来判断,我们在注册时计算密码的 MD5 值入库,当玩家登录时再次使用玩家输入的明文密码再次计算 MD5 值,如果一致就验证成功,这就是为什么哈希算法要有低碰撞率了。

MD5现在不太安全了

因为MD5算法是确定,用一个字符串计算出来的哈希值也是固定的,所以出现了一些针对该算法的破解方法。

  1. 暴力枚举法:因为可以不断尝试,并且随着计算机硬件能力的快速提升,使得这种方法来破解短密码称为了可能
  2. 字典法:也就是撞库,黑客通过收集互联网已泄露的用户和密码信息,生成对应的字典表,通过撞库来完成破解
  3. 彩虹表:在字典法的基础上改进,以时间换空间,使用预计算的哈希链集来降低存储空间,是目前最常用的方法

MD5可以为自己代言(带盐)

对于固定的哈希算法,相同的输入会得到相同的输出,那么针对MD5算法只需要准备一个字典或者一个彩虹表就可以一直沿用,如果在原有的密码上加点料,那么即使两个用户使用相同的密码,因为盐不同,得到的输出值也就不同,那么破解难度大大提高了。

BCrypt加密

上面说过单独使用MD5加密不太安全,但是加盐以后可以大大提高破解的难度,为什么BCrypt加密火了起来,大有代替MD5的趋势~

BCrypt 是 Niels Provos 和 DavidMazières 基于 Blowfish 密码设计的,是 OpenBSD 的默认密码哈希算法。 目前有针对 C、C++、Python 、C# 、Java、JS、PHP 等多种编程语言的实现,使用起来非常方便。

它相对于MD5有哪些优势呢?

自己加盐

首先他不用自己来管理用户的“盐”,如果所有的用户使用相同的盐不太安全,每个人生成不同的盐,需要自己单独来存储使用,而BCrypt内部自己实现了随机加盐处理,可以实现每次加密后的密文是不一样的。

对于同一个密码,Bcrypt每次生成的哈希结果都不一样,那么它是如何进行校验的?

其实BCrypt算法将盐随机生成并混入最终加密后的密码之中,验证时会自动提取,无需单独提供“盐”信息,生成的Hash值通常格式如下:

1
$2b$12$ABJPtagiuqTVhnIPvOLoB.hbIlZ3joRkpck3joDsX6xe3O2KShuty

其中 $ 为分隔符,2b是bcrypt加密版本号,12是工作负载,紧接着22位是盐,剩下的字符串就是密码的密文了。

看到这个密码仿佛就是明牌了跟对手打呀,如果你真的获得了加密后的密码,那你就知道了加密版本、工作负载,盐的信息,这样会不会很危险呢?是挺危险的,但是即使你使用MD5加密,那个盐也是要存储的,也会面临同样的问题,另外BCrypt还有其他的法宝。

工作负载

BCrypt的工作负载有时也称为加密轮数、成本因子等等(一提到工作负载就想到比特币,数字游戏而已),目的就是提高破解难度,带来的缺点就是速度慢。MD5的Hash值生成通常是微妙级别的,但是Bcrypt一个密码出来的时间比较长,Python环境使用默认12轮负载需要0.25秒生成一个密码(C++环境需要进一步测试)。

所以如果使用Bcrypt,需要考虑它的成本,负责做认证的服务器,可能在原基础上扩容几十倍或者几百倍,它是靠把计算成本提高多个数量级来换取安全的。

使用方便

目前在各大主流编程语言中都可以方便的使用BCrypt相关函数,下面以Python为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import time
import bcrypt

passwd = b'123456nx'

start = time.time()
salt = bcrypt.gensalt(12)
pwsd = bcrypt.hashpw(passwd, salt)

cost = time.time() - start
print("[salt]", salt)
print("[pwsd]", pwsd)
print("[cost]", cost)

运行结果如下:

1
2
3
[salt] b'$2b$12$lEsQ9dGnRe2vKfFDRUZYAO'
[pwsd] b'$2b$12$lEsQ9dGnRe2vKfFDRUZYAOmmmdlgWfHfNO94C/UqCKGGRioruF77u'
[cost] 0.24636435508728027

总结

  • MD5从严格意义上来说并不是一个加密算法,更准确的说法应该是单向散列算法,因为无法逆向进行解密
  • 通过 MD5 计算后的密码,可以使用的破解方法有暴力枚举、字典表、彩虹表等,其中《彩虹表》最常用
  • BCrypt算法可以随机生成盐,并将盐信息混入最终加密后的密码之中,验证时会自动提取
  • BCrypt算法引入了工作负载机制,生成Hash值的时间大大延长,相应的破解难度也随之增加
  • BCrypt算法在Python环境下使用默认参数需0.25秒生成一个密码,选用这种方式需考虑时间成本

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

以史为鉴,理解今天,展望未来~
时刻准备着,这次的大团圆无需担心,可能某个清晨的早间新闻,你们已经回来了!

2021-11-1 00:21:44

Albert Shi wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客