SHA256.Create() 是最稳妥的创建方式,它跨平台、向前兼容、自动适配运行时最优实现且支持 FIPS 模式;字符串哈希前必须显式指定 Encoding.UTF8.GetBytes(),避免编码不一致导致结果错误。

SHA256.Create() 是最稳妥的创建方式
直接 new SHA256CryptoServiceProvider() 会埋雷——它在 .NET Core 3.0+ 和 .NET 5+ 中已标记为过时,且在某些容器或 FIPS 启用环境下可能抛出 CryptographicException。用 SHA256.Create() 才是跨平台、向前兼容的正确入口。
它会根据运行时自动选择最优实现(如 SHA256Managed 或硬件加速的 SHA256Cng),不用手动判断。
- 别写
new SHA256CryptoServiceProvider(),尤其别硬编码在工具类里 - 如果项目需支持 FIPS 模式(如政企环境),
SHA256.Create()仍能 fallback 到合规实现;而SHA256Managed在 FIPS 下直接失败 - 返回对象是
SHA256抽象类实例,可安全调用ComputeHash(),无需 downcast
字符串转字节数组必须显式指定编码
哈希的是字节,不是“字符串”。"abc" 用 UTF-8 编码是 [97, 98, 99],用 UTF-16 就变成 [97, 0, 98, 0, 99, 0] —— 结果完全不同。不指定编码,Encoding.Default 会随系统区域设置漂移,本地跑通,上线就错。
- 一律用
Encoding.UTF8.GetBytes(input),别依赖隐式转换或Encoding.Default - 若业务明确要求与旧系统兼容(比如 legacy GBK 接口),才显式用
Encoding.GetEncoding("GBK"),并加注释说明原因 - Base64 或十六进制输出只是展示形式,不影响哈希值本身;但编码选错,连哈希值都算歪了
ComputeHash() 的三种重载别混用
ComputeHash() 有三个常见重载:ComputeHash(byte[])、ComputeHash(Stream)、ComputeHash(byte[], int, int)。传错参数类型或越界,轻则结果错误,重则 ArgumentException 或静默截断。
- 小文本(如密码、token)直接用
hasher.ComputeHash(Encoding.UTF8.GetBytes(input)) - 大文件(如上传的 ZIP)务必走
Stream重载,避免一次性加载进内存;记得用using (var fs = File.OpenRead(path))确保释放 - 第三个重载用于处理 byte 数组的子区间,比如解析协议头后的有效载荷;传错
offset或count会导致哈希内容偏移
输出格式:Hex 还是 Base64?看下游怎么用
SHA256 原生输出是 32 字节 byte[],必须转成字符串才能存储或传输。选 Convert.ToBase64String() 还是 BitConverter.ToString().Replace("-", "").ToLower(),取决于对接方要求和可读性权衡。
- Base64 更短(44 字符 vs Hex 的 64 字符),适合 URL、JWT header 等对长度敏感场景
- Hex 字符串全小写、无特殊字符,便于日志排查、数据库 LIKE 查询、人工比对;注意去掉
BitConverter.ToString()默认插入的短横线 - 别用
Encoding.UTF8.GetString(hashBytes)—— 二进制数据不是合法 UTF-8,会出 或静默替换,哈希值彻底报废
真正容易被忽略的,是编码一致性贯穿全程:输入字符串用什么 Encoding,输出比较时就得用同一套规则反解(如果需要);存数据库的字段长度要按最终字符串长度预留(Base64 固定 44 字符,Hex 固定 64 字符);前后端约定好格式,否则一个用 Hex、一个用 Base64,永远对不上。


















