MD5是一种广泛使用的散列函数,它将输入数据不可逆地映射成固定长度的哈希值,通常是128位的二进制数。在计算机科学中,哈希函数(也叫散列函数)是将任意数量的数据映射到固定数量的数据的函数,而MD5就是其中一种。本文主要从以下几个方面进行详细阐述。
一、MD5加密算法原理
MD5加密算法是由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)在1991年提出,它基于消息摘要算法,能够快速将任意长度的字节序列映射为一个128位的哈希值。MD5加密算法的基本原理如下:
1、填充数据:首先在数据末位填充一位1,然后在末尾填充足够的0,使得填充前的长度之与512同余448,这里的512是MD5加密算法的一个固定参数。
public class MD5 { private static final String SPLIT_STR = "'5A827999' + F(a,b,c,d) + X[k] + T[i]"; private static final Integer[] R = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}; // T是用正弦函数生成的一个表,其中k表示第k个元素的值 private static final Integer[] T = new Integer[64]; static { for (int i = 0; i < 64; i++) { double d = Math.abs(Math.sin(i + 1)); T[i] = (int) (d * (1L << 32)); } } // ... }
2、划分数据:将填充后的数据划分为多个512位的块,然后对每个块进行加密操作。
3、初始化变量:对每个块进行加密操作之前,需要先对MD5加密算法用到的四个变量进行初始化,这四个变量的初始值为固定值。
4、加密:将每个块进行加密操作,每个块的加密都是基于上一个块的加密结果。最终的加密结果即为MD5值。
二、MD5加密算法应用场景
MD5加密算法在计算机领域中有着广泛的应用场景,下面介绍三个典型的应用场景。
1、密码存储
MD5加密算法可以用于密码的存储,通过将用户输入的明文密码进行MD5加密,将加密后的结果存储到数据库中。当用户下一次登录时,再将输入的密码进行MD5加密,并与数据库中的密文密码进行比对,从而达到验证用户身份的目的。
public class PasswordUtils { /** * 对字符串进行MD5加密 * * @param src 待加密的字符串 * @return 加密后的字符串 */ public static String encrypt(String src) { MessageDigest md5; try { md5 = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } byte[] byteArray = src.getBytes(StandardCharsets.UTF_8); byte[] md5Bytes = md5.digest(byteArray); StringBuilder hexValue = new StringBuilder(); for (byte md5Byte : md5Bytes) { int val = ((int) md5Byte) & 0xff; if (val < 16) { hexValue.append("0"); } hexValue.append(Integer.toHexString(val)); } return hexValue.toString(); } // ... }
2、数字签名
MD5加密算法可以用于数字签名,数字签名是指用某个私钥对信息进行签名,再将签名与信息一起发送给收件人,收件人使用对应的公钥来验证签名的合法性。
public class DigitalSignatureUtils { /** * 对数据进行数字签名 * * @param data 待签名的数据 * @param privateKey 签名私钥 * @return 数字签名 * @throws Exception */ public static byte[] sign(byte[] data, PrivateKey privateKey) throws Exception { Signature signature = Signature.getInstance("MD5withRSA"); signature.initSign(privateKey); signature.update(data); return signature.sign(); } /** * 验证数字签名 * * @param data 原始数据 * @param signature 签名 * @param publicKey 验证公钥 * @return 验证结果 * @throws Exception */ public static boolean verify(byte[] data, byte[] signature, PublicKey publicKey) throws Exception { Signature sig = Signature.getInstance("MD5withRSA"); sig.initVerify(publicKey); sig.update(data); return sig.verify(signature); } }
3、文件校验
MD5加密算法可以用于文件校验,因为文件的MD5值是唯一的,这意味着当用户想要下载一个文件时,可以先对文件的MD5值进行校验,如果MD5值一致,则表明该文件是原来的文件,否则文件就被篡改了。
public class FileCheckUtils { /** * 计算文件MD5值 * * @param file 待计算MD5值的文件 * @return MD5值 * @throws Exception */ public static String getFileMD5(File file) throws Exception { FileInputStream fileInputStream = new FileInputStream(file); byte[] buffer = new byte[1024]; MessageDigest md5 = MessageDigest.getInstance("MD5"); int numRead; do { numRead = fileInputStream.read(buffer); if (numRead > 0) { md5.update(buffer, 0, numRead); } } while (numRead != -1); fileInputStream.close(); byte[] md5Bytes = md5.digest(); StringBuilder hexValue = new StringBuilder(); for (byte md5Byte : md5Bytes) { int val = ((int) md5Byte) & 0xff; if (val < 16) { hexValue.append("0"); } hexValue.append(Integer.toHexString(val)); } return hexValue.toString(); } }
三、MD5加密算法存在的问题
虽然MD5加密算法在很多应用场景中都得到了广泛的应用,但由于一些历史原因和技术问题,MD5加密算法在某些场景下可能存在一些问题,下面介绍两个MD5加密算法存在的问题。
1、碰撞攻击
在密码存储、数字签名等场景中,MD5加密算法被用于验证数据的完整性、安全性,但实际上,MD5加密算法可以被破解,因为它并不是完全无法反推。碰撞攻击是指在输入的任意两个不同的数据中找到相同的MD5值的过程。目前针对MD5的碰撞攻击已经非常成熟,因此在密码存储、数字签名等场景中建议使用更为安全的加密算法。
2、MD5彩虹表攻击
彩虹表攻击是指对密文进行预先计算,存储在数据库中的彩虹表中,然后进行账号破解的攻击方式。虹表都是提前计算好算法,存放在一个表格里,由于在运算速度上,计算要比破解慢得多,因此,指定长度的几乎所有明文可能,都可以构造一张包含其MD5值的彩虹表。因此,为了增强密码的安全性,导入“盐值”(即随机数)后再进行MD5加密。
public class SaltMd5 { /** * 加盐MD5加密 * * @param src 待加密的字符串 * @param salt 盐值 * @return 盐值加密后的字符串 */ public static String encrypt(String src, String salt) { return DigestUtils.md5Hex(salt + DigestUtils.md5Hex(src)); } }
总之,MD5加密算法在现实生活中有着广泛的应用场景,在使用时候,我们需要根据具体的业务场景来选择加密方式,建议在密码存储、数字签名等安全性要求比较高的场景下,不要使用MD5加密算法。