当前位置: 首页 > news >正文

MD5 + SHA-1 详解

哈希加密工具类文档(MD5 + SHA-1 详解)

一、文档概述

本文档将详细介绍 MD5SHA-1 两种经典哈希加密算法,包括算法原理、实现思路、核心区别,并提供通用可直接使用的加密工具类(基于 Java 原生 API,无第三方依赖),同时结合实际场景说明适用场景,帮助开发者快速理解和使用。

二、两种加密算法核心介绍

2.1 MD5 加密(Message-Digest Algorithm 5)

2.1.1 算法简介
  • 全称:消息摘要算法第5版,是一种不可逆的哈希函数(无法从加密结果反推原始数据);
  • 核心特征:无论输入数据长度如何,输出固定为 128位(16字节) 的摘要,通常以 32位十六进制字符串 表示;
  • 设计用途:主要用于数据完整性校验(如文件校验)、密码加密存储(早期常用);
  • 安全性:已被破解(存在碰撞风险,即不同数据可能生成相同 MD5 结果),不建议用于高安全性场景(如金融、核心密码存储)。
2.1.2 实现思路
  1. 输入处理:将原始字符串按指定编码(如 UTF-8)转为字节数组;
  2. 实例化算法:通过 Java 原生 MessageDigest.getInstance("MD5") 获取 MD5 加密实例;
  3. 生成摘要:调用 digest() 方法对字节数组进行哈希计算,得到 16 字节原始摘要;
  4. 格式转换:将 16 字节摘要转为 32 位十六进制字符串(1 字节 = 2 位十六进制),便于存储和传输。

2.2 SHA-1 加密(Secure Hash Algorithm 1)

2.2.1 算法简介
  • 全称:安全哈希算法第1版,同样是不可逆的哈希函数;
  • 核心特征:输入数据无论长度,输出固定为 160位(20字节) 的摘要,通常以 40位十六进制字符串 表示;
  • 设计用途:数据完整性校验、密码加密存储(安全性高于 MD5);
  • 安全性:比 MD5 更安全(摘要长度更长,碰撞概率极低),但仍属于弱哈希(2017年已被破解),目前推荐用于非核心安全场景。
2.2.2 实现思路
  1. 输入处理:与 MD5 一致,将原始字符串转为 UTF-8 字节数组;
  2. 实例化算法:通过 MessageDigest.getInstance("SHA-1") 获取 SHA-1 加密实例;
  3. 生成摘要:调用 digest() 方法计算字节数组的哈希值,得到 20 字节原始摘要;
  4. 格式转换:将 20 字节摘要转为 40 位十六进制字符串,完成加密。

三、MD5 与 SHA-1 核心区别

对比维度MD5SHA-1
摘要长度128位(16字节)→ 32位十六进制串160位(20字节)→ 40位十六进制串
加密速度较快(计算逻辑相对简单)较慢(计算步骤更多)
安全性较低(存在碰撞风险,已被破解)较高(碰撞概率极低,破解成本更高)
适用场景低安全需求:文件校验、普通数据加密中安全需求:密码存储、接口签名校验
输出字符串长度固定32位(小写/大写可自定义)固定40位(小写/大写可自定义)

四、通用加密工具类(完整实现)

4.1 工具类代码(HashUtil.java)

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Objects;/*** 哈希加密工具类(MD5 + SHA-1)* 特点:无第三方依赖、支持空值处理、可自定义编码和大小写、线程安全*/
public class HashUtil {// 默认编码(UTF-8,主流项目通用)private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;// 十六进制字符集(小写)private static final char[] HEX_CHARS_LOWER = "0123456789abcdef".toCharArray();// 十六进制字符集(大写)private static final char[] HEX_CHARS_UPPER = "0123456789ABCDEF".toCharArray();/*** MD5 加密(默认 UTF-8 编码,小写输出)* @param data 原始数据(可为 null)* @return 32位十六进制加密串(data 为 null/空串时返回空串)*/public static String md5(String data) {return md5(data, DEFAULT_CHARSET, false);}/*** MD5 加密(自定义编码和大小写)* @param data 原始数据(可为 null)* @param charset 字符编码(如 StandardCharsets.UTF_8)* @param upperCase 是否大写输出(true:大写,false:小写)* @return 32位十六进制加密串*/public static String md5(String data, Charset charset, boolean upperCase) {if (data == null || data.trim().isEmpty()) {return "";}return hash(data, "MD5", charset, upperCase);}/*** SHA-1 加密(默认 UTF-8 编码,小写输出)* @param data 原始数据(可为 null)* @return 40位十六进制加密串(data 为 null/空串时返回空串)*/public static String sha1(String data) {return sha1(data, DEFAULT_CHARSET, false);}/*** SHA-1 加密(自定义编码和大小写)* @param data 原始数据(可为 null)* @param charset 字符编码(如 StandardCharsets.UTF_8)* @param upperCase 是否大写输出(true:大写,false:小写)* @return 40位十六进制加密串*/public static String sha1(String data, Charset charset, boolean upperCase) {if (data == null || data.trim().isEmpty()) {return "";}return hash(data, "SHA-1", charset, upperCase);}/*** 双重加密(MD5 → SHA-1,默认 UTF-8 编码,小写输出)* 场景:需要比单一加密更高安全性的场景(如密码存储)* @param data 原始数据(可为 null)* @return 40位十六进制加密串*/public static String md5Sha1(String data) {if (data == null || data.trim().isEmpty()) {return "";}// 先 MD5 加密,再对 MD5 结果做 SHA-1 加密String md5Result = md5(data);return sha1(md5Result);}/*** 核心哈希加密方法(统一实现 MD5/SHA-1 逻辑)* @param data 原始数据* @param algorithm 加密算法("MD5" 或 "SHA-1")* @param charset 字符编码* @param upperCase 是否大写输出* @return 十六进制加密串*/private static String hash(String data, String algorithm, Charset charset, boolean upperCase) {try {// 1. 获取加密算法实例MessageDigest messageDigest = MessageDigest.getInstance(algorithm);// 2. 字符串转字节数组并计算摘要byte[] digest = messageDigest.digest(data.getBytes(charset));// 3. 字节摘要转为十六进制字符串return bytesToHex(digest, upperCase);} catch (NoSuchAlgorithmException e) {// 算法不存在时抛出运行时异常(理论上不会发生,Java 原生支持 MD5/SHA-1)throw new RuntimeException("加密算法 " + algorithm + " 不支持", e);}}/*** 字节数组转为十六进制字符串* @param bytes 原始字节数组* @param upperCase 是否大写输出* @return 十六进制字符串*/private static String bytesToHex(byte[] bytes, boolean upperCase) {Objects.requireNonNull(bytes, "字节数组不能为 null");char[] hexChars = upperCase ? HEX_CHARS_UPPER : HEX_CHARS_LOWER;char[] result = new char[bytes.length * 2];for (int i = 0; i < bytes.length; i++) {byte b = bytes[i];// 高4位转十六进制result[i * 2] = hexChars[(b >>> 4) & 0x0F];// 低4位转十六进制result[i * 2 + 1] = hexChars[b & 0x0F];}return new String(result);}
}

4.2 工具类使用示例

public class HashUtilDemo {public static void main(String[] args) {String rawData = "123456"; // 原始数据// 1. MD5 加密(默认配置:UTF-8 + 小写)String md5Result = HashUtil.md5(rawData);System.out.println("MD5 加密结果(小写):" + md5Result); // 输出:e10adc3949ba59abbe56e057f20f883e// 2. MD5 加密(UTF-8 + 大写)String md5UpperResult = HashUtil.md5(rawData, StandardCharsets.UTF_8, true);System.out.println("MD5 加密结果(大写):" + md5UpperResult); // 输出:E10ADC3949BA59ABBE56E057F20F883E// 3. SHA-1 加密(默认配置:UTF-8 + 小写)String sha1Result = HashUtil.sha1(rawData);System.out.println("SHA-1 加密结果(小写):" + sha1Result); // 输出:10470c3b4b1fed12c3baac014be15fac67c6e815// 4. 双重加密(MD5 → SHA-1)String md5Sha1Result = HashUtil.md5Sha1(rawData);System.out.println("MD5+SHA-1 双重加密结果:" + md5Sha1Result); // 输出:2fd4e1c67a2d28fced849ee1bb76e7391b93eb12}
}

五、工具类核心特性

  1. 无依赖:仅使用 Java 原生 MessageDigest 和字符编码 API,无需引入第三方 Jar 包;
  2. 空值安全:处理 null、空字符串、纯空格等异常输入,避免空指针异常;
  3. 灵活配置:支持自定义字符编码(如 GBK)、输出大小写(小写默认,大写可选);
  4. 线程安全MessageDigest 实例为方法内局部变量,无线程安全问题;
  5. 功能完整:包含单一加密(MD5/SHA-1)和双重加密(MD5→SHA-1),覆盖大部分场景。

六、适用场景推荐

6.1 MD5 适用场景

  • 文件完整性校验(如下载文件后校验 MD5 是否与官方一致,判断文件是否篡改或损坏);
  • 普通数据加密(如非核心业务的用户昵称、设备ID等,仅需防明文存储);
  • 缓存键生成(如将复杂查询条件 MD5 加密作为缓存键,减少键长度)。

6.2 SHA-1 适用场景

  • 密码存储(比 MD5 更安全,适合非金融类项目的用户密码加密存储);
  • 接口签名校验(如 API 接口请求参数拼接后 SHA-1 加密,防止参数被篡改);
  • 日志数据校验(如重要日志的摘要存储,后续可校验日志是否被修改)。

6.3 双重加密(MD5→SHA-1)适用场景

  • 高安全性密码存储(如管理后台用户密码、支付相关密码);
  • 核心数据加密(如敏感配置项、密钥相关数据)。

七、注意事项

  1. 不可逆性:MD5 和 SHA-1 都是哈希摘要算法,不是加密解密算法,无法从加密结果反推原始数据(如需可逆加密,需使用 AES/DES 等对称加密算法);
  2. 盐值增强:密码存储场景中,建议在加密前添加「盐值」(如 rawData + salt),避免彩虹表破解(工具类可扩展盐值参数,示例如下):
    // 扩展带盐值的 MD5 加密
    public static String md5WithSalt(String data, String salt) {return md5(data + salt); // 盐值可随机生成并与加密结果一起存储
    }
    
  3. 高安全场景替代方案:金融、政务等核心安全场景,建议使用 SHA-256/SHA-512 等更强的哈希算法,或国密算法(SM3);
  4. 编码一致性:加密和校验时需使用相同的字符编码(如均为 UTF-8),否则会导致校验失败。

八、常见问题排查

  1. 加密结果不一致
    • 检查原始数据是否一致(含空格、特殊字符);
    • 确认编码是否一致(如一方用 UTF-8,一方用 GBK);
    • 核实输出大小写是否一致(小写 “a” 和大写 “A” 视为不同结果)。
  2. 空指针异常
    • 工具类已处理 null 输入,若仍报错,检查是否传入了 null 编码(charset 不可为 null)。
  3. 算法不支持异常
    • 确保 JDK 环境支持 MD5/SHA-1(主流 JDK 均支持,无需额外配置)。
http://www.dtcms.com/a/572641.html

相关文章:

  • [Dify 实战] 对接飞书、企业微信等聊天系统的最佳实践与策略
  • Spring MVC 响应处理:页面、数据与状态配置详解
  • 图解 MySQL JOIN
  • 数据结构知识掌握
  • 利用MLPack插件在DuckDB中机器学习
  • 做电子书的网站很有名后来被关闭了东营市建设局官网
  • 企业微信可信IP配置的Python完美解决方案
  • 卫朋:IPD如何实现战略解码?三步翻译术
  • 德州市市长朱开国率队到访深兰科技,加速推进机器人产业落地与合作深化
  • Redis中的分布式锁
  • JVM核心知识整理《1》
  • 可以上传数据的网站开发图书页面设计模板
  • 09.MCP协议介绍
  • 彻底讲清楚 Kotlin 的 when 表达式
  • 济宁网站建设 果壳科技腾讯云主机
  • 百度收录不到我的网站聊大 网站设计
  • Jackson SerializerModifier 拦截器(高性能)实现时间戳自动添加
  • 虚拟机server2012 安装oracle11g遇到的坑
  • Webpack中各种devtool配置的含义与SourceMap生成逻辑
  • 深入理解 PostgreSQL Tuple 与 Dead Tuple:检测方法与 VACUUM 自动化实践
  • 系统分析师-案例分析-数据库系统数据仓库反规范化技术NoSQL内存数据库
  • 用Python来学微积分32-定积分的可积性条件详解
  • 游戏远程操控性能横评:ToDesk、Parsec、UU远程深度对比
  • 【C/C++刷题集】二叉树算法题(二)
  • Django登录注册完整代码(图片、邮箱验证、加密)
  • 基于Optuna 贝叶斯优化的自动化XGBoost 超参数调优器
  • Qt开发初识
  • ReactNative 快速入门手册
  • 【C++:map和set的使用】C++ map/multimap完全指南:从红黑树原理入门到高频算法实战
  • GPT-OSS大模型Attention架构设计