MD5
2.1 MD5
目录
MD5消息摘要算法,属Hash算法一类。
MD5算法是一种广泛使用的哈希函数,用于生成128位(32个十六进制数字)的消息摘要。
它接受任意长度的输入,并输出固定长度的哈希值(一个128位的消息摘要,32位的数字字母混合码),通常用于验证数据完整性、数字签名、密码存储等领域。
MD5算法以其简洁高效的设计和快速计算速度而闻名,
但近年来由于其存在一些安全性弱点,逐渐被更安全的哈希算法所取代。
MD5主要特点
一个MD5理论上的确是可能对应无数多个原文的,因为MD5是有限多个的而原文可以是无数多个。
比如主流使用的MD5将任意长度的“字节串映射为一个128bit的大整数。
也就是一共有2128种可能 ,大概是3.4*1038,这个数字是有限多个的,
而但是世界上可以被用来加密的原文则会有无数的可能性。
MD5的性质
- 1、压缩性:任意长度的数据,算出的MD5值长度都是固定的(相当于超损压缩)。
- 2、容易计算:从原数据计算出MD5值很容易。
- 3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
- 4、弱抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
- 5、强抗碰撞:想找到两个不同的数据,使它们具有相同的MD5值,是非常困难的。
MD5算法的应用
数据完整性验证
MD5算法常用于数据完整性验证,即确保数据在传输或存储过程中没有被篡改。发送方会计算数据的MD5哈希值并将其附加在数据中一起传输,接收方收到数据后重新计算MD5哈希值,并与接收到的MD5哈希值进行比较,如果一致则说明数据完整性良好。
数字签名
MD5算法也可以用于数字签名,数字签名是一种用于验证数据来源和完整性的技术。发送方使用私钥对数据的MD5哈希值进行加密,生成数字签名并将其附加在数据中发送。接收方使用发送方的公钥解密数字签名,再计算数据的MD5哈希值并与解密后的数字签名进行比较,以验证数据的完整性和真实性。
密码存储
在密码存储方面,MD5算法可以用于加密密码并存储在数据库中。当用户登录时,系统会对用户输入的密码进行MD5哈希运算,然后与数据库中存储的MD5哈希值进行比较,以验证密码的正确性。然而,由于MD5算法存在碰撞攻击等安全漏洞,现在更推荐使用更安全的哈希算法如SHA-256来存储密码。
文件校验
MD5算法还常用于文件校验,例如下载文件后可以计算文件的MD5哈希值,与提供的MD5值进行比较,以确保文件在传输过程中没有被篡改或损坏。如果两个MD5值一致,则文件完整,否则可能存在问题。
问题解答
MD5算法有哪些应用场景?
MD5算法常用于验证数据完整性,文件校验,密码存储等场景。
MD5算法存在哪些安全性问题?
MD5算法存在碰撞攻击漏洞,不再安全可靠,容易被破解。
MD5算法与SHA算法有何区别?
MD5算法和SHA算法都是哈希算法,但SHA算法比MD5更安全,如SHA-256、SHA-512等。
MD5算法是否可逆?
MD5算法是单向哈希算法,不可逆,无法从摘要值还原出原始数据。
MD5算法在密码学中的作用是什么?
MD5算法在密码学中用于生成摘要值,验证数据完整性,密码存储等方面。
代码样例
Java
private static void md5()
throws NoSuchAlgorithmException, UnsupportedEncodingException {
String[] input = {"Hello", "World"};
// 创建一个MessageDigest实例
MessageDigest md = MessageDigest.getInstance("MD5");
// 反复调用update输入数据
for (String s : input) {
md.update(s.getBytes("UTF-8"));
}
// 当输入结束后,调用digest()方法获得byte[]数组表示的摘要
byte[] result = md.digest();
// 最后,把它转换为十六进制的字符串。
// 16 bytes: 68e109f0f40ca72a15e05cc22786f8e6
String rs = HexFormat.of().formatHex(result);
System.out.println(rs);
Preconditions.checkArgument(
StringUtils.equals(rs, "68e109f0f40ca72a15e05cc22786f8e6"), "不符合期望");
}
JavaScript(CryptoJS)
const hasher = CryptoJS.algo.MD5.create();
hasher.reset();
hasher.update('abc');
hasher.update('def');
const hash = hasher.finalize();
return hash + '';
Python
import hashlib
def md5_test1():
md5 = hashlib.new('md5', 'I love python!'.encode('utf-8'))
print(md5.hexdigest())
def md5_test2():
md5 = hashlib.md5()
md5.update('I love '.encode('utf-8'))
md5.update('python!'.encode('utf-8'))
print(md5.hexdigest())
if __name__ == '__main__':
md5_test1() # 21169ee3acd4a24e1fcb4322cfd9a2b8
md5_test2() # 21169ee3acd4a24e1fcb4322cfd9a2b8
MD5 防止彩虹表攻击
使用哈希口令时,还要注意防止彩虹表攻击。
如果只拿到MD5,从MD5反推明文口令,只能使用暴力穷举的方法。
然而暴力穷举会消耗大量的算力和时间。但是,如果有一个预先计算好的常用口令和它们的MD5的对照表(对照表),就可以根据MD5直接反查。
上述代码样例, 经过加盐操作的改良,使黑客的彩虹表失效,即使用户使用常用口令,也无法从MD5反推原始口令。
/**
* 加盐的目的在于使黑客的彩虹表失效,即使用户使用常用口令,也无法从MD5反推原始口令。
*/
private static void md5WithSalt(String salt)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
String[] input = {salt, "Hello", "World"};
// 创建一个MessageDigest实例
MessageDigest md = MessageDigest.getInstance("MD5");
// 反复调用update输入数据
for (String s : input) {
md.update(s.getBytes("UTF-8"));
}
// 当输入结束后,调用digest()方法获得byte[]数组表示的摘要
byte[] result = md.digest();
// 最后,把它转换为十六进制的字符串。
// 16 bytes: 68e109f0f40ca72a15e05cc22786f8e6
String rs = HexFormat.of().formatHex(result);
System.out.println(rs);
Preconditions.checkArgument(
StringUtils.equals(rs, "20fd53312bf2f702d26087a204e6e0b5"), "不符合期望");
}