md5是哈希而非加密,不可逆且不安全,仅适用于文件校验或接口参数一致性;.net core 2.0+中应使用md5.create()而非new md5cryptoserviceprovider(),并用encoding.utf8.getbytes()编码字符串后计算哈希,结果通过bitconverter.tostring().replace("-").tolowerinvariant()或.net 5+的convert.tohexstring()转为32位小写十六进制字符串;密码哈希必须加盐并迭代,推荐rfc2898derivebytes或argon2,而非直接用md5或sha256。

MD5 不是加密,是哈希;它不可逆,也不安全——别用它存密码,只适合校验文件或接口参数一致性。
为什么 new MD5CryptoServiceProvider() 会报错?
在 .NET Core 2.0+、.NET 5+ 和 Blazor WebAssembly 中,MD5CryptoServiceProvider 已被标记为 obsolete,直接 new 它会触发编译警告 CS0618,甚至在 AOT 编译或受限运行时抛出 PlatformNotSupportedException。
- 必须改用工厂方法
MD5.Create(),它返回HashAlgorithm抽象类型,行为统一且跨平台兼容 -
MD5.Create()在 .NET Framework 4.6.1+ 和所有现代 .NET 版本中都可用,无需条件编译 - 写法始终是
using var md5 = MD5.Create();,别手动new,也别用Dispose()手动释放——using足够
Encoding.UTF8.GetBytes() 是默认,但不是万能
MD5.ComputeHash() 只接受 byte[],字符串必须先编码。看似简单,实则容易翻车:
- 中文、emoji、日文等非 ASCII 字符,用
Encoding.ASCII.GetBytes()会静默截断或替换成?,哈希值完全错误 - 对接 Java/PHP 老系统时,对方可能用
new String(bytes, "GBK"),你也得用Encoding.GetEncoding("GBK") - 绝对别用
Encoding.Default——它随 Windows 区域设置变,本地跑通,Linux 容器里就崩 - 99% 新项目用
Encoding.UTF8即可,但要显式写出,不依赖隐式转换
结果转字符串:别用 ToString(),也别拼大写
ComputeHash() 返回的是 byte[16],直接调 .ToString() 得到的是 "System.Byte[]",不是哈希值。
- 标准 MD5 字符串是 32 位小写十六进制(如
5eb63bbbe01eeed093cb22bb8f5acdc3),大小写敏感 - 最简可靠写法:
BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant() - .NET 5+ 推荐用
Convert.ToHexString(hashBytes),更快更安全,但注意它返回小写,无需再ToLower() - 避免
b.ToString("X2")(大写)或string.Concat(bytes.Select(b => b.ToString("x2")))(LINQ 开销高)
MD5 和 SHA256 的实际选择边界在哪?
两者都是哈希,但用途不能混:
-
MD5:仅用于非安全场景,比如比对配置文件是否被篡改、生成缓存键、老接口签名(对方强制要求) -
SHA256:可用于密码哈希,但必须加盐(salt),且推荐用Rfc2898DeriveBytes或Argon2等专用密钥派生函数 - 别把
SHA256.Create().ComputeHash(...)直接当密码存储方案——没盐、没迭代、易被彩虹表或 GPU 暴力破解 - 如果只是校验数据完整性(比如上传文件后比对哈希),
SHA256比MD5更抗碰撞,优先选它
真正容易被忽略的点是:哈希值本身没有“加密强度”概念,它的安全性完全取决于使用方式。一个没加盐的 SHA256 哈希密码,和 MD5 一样脆弱;而一个带随机盐、10 万次迭代的 SHA256 派生,才勉强够格。别只盯着算法名,盯住上下文。











