SHA256是哈希非加密,ComputeHash()返回byte[]需转十六进制字符串;必须用UTF8编码字节数组,大文件须分块计算;应使用using var sha = SHA256.Create()并避免复用实例。

SHA256 在 C# 中不是加密,是哈希;直接调 SHA256.Create().ComputeHash() 得到的是 byte[],不是字符串——不转格式就等于没结果。
为什么 SHA256.Create().ComputeHash() 看起来“没输出”或显示 System.Byte[]?
因为 ComputeHash() 返回的是原始字节数组,.ToString() 默认输出类型名,不是哈希值本身。常见错误是写成:
string hash = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes("abc")).ToString(); // ❌ 输出 "System.Byte[]" 必须显式转换为十六进制字符串:
-
Convert.ToHexString(hash).ToLower()(推荐,.NET 5+,快且无分隔符) -
BitConverter.ToString(hash).Replace("-", "").ToLower()(兼容旧版,但注意短横线和大小写) - 别用
string.Concat(hash.Select(b => b.ToString("x2"))):LINQ 分配多、性能差,高并发下易成瓶颈
字符串哈希必须用 Encoding.UTF8.GetBytes(),不能省
SHA256 对字节运算,不是对字符串。编码错,哈希就错——这是跨平台验签失败最常见原因。
-
Encoding.Default绑定系统区域设置(如中文 Windows 是 GB2312),不可靠 -
Encoding.Unicode(即 UTF-16)会让“你好”变成 4 字节,而服务端(JWT、API 签名)几乎全按 UTF-8 解释,必然不匹配 - 硬写
"salt" + input拼接再哈希?中文一来就乱,且盐值未字节化,长度扩展风险高
正确做法始终是:Encoding.UTF8.GetBytes(input),加盐时也走字节数组拼接:salt.Concat(Encoding.UTF8.GetBytes(input)).ToArray()。
大文件哈希不能直接传 FileStream 给 ComputeHash()
看似一行代码:SHA256.Create().ComputeHash(fs),实则会把整个文件读进内存——4GB 文件可能触发 OutOfMemoryException,GC 暂停严重,实测比手动分块慢近一倍。
- 必须用
TransformBlock()+TransformFinalBlock()增量计算 - 缓冲区设
64 * 1024(64KB)较优:太小增加调用开销,太大对 NVMe/SSD 吞吐无提升 -
FileStream构造时要传FileOptions.SequentialScan和显式bufferSize(如 8192),否则默认 4KB 缓冲拖慢顺序读 - 别用
File.OpenRead():它不支持传FileOptions,也没法控缓冲区
别用 new SHA256Managed(),也别复用 SHA256 实例
SHA256Managed 在 .NET Core 2.0+ 已过时,iOS/AOT 环境下直接抛 PlatformNotSupportedException;而 SHA256 实例线程不安全、不可复用。
- 一律用
using var sha = SHA256.Create();—— 它自动选最优实现(Windows 上是 CNG,Linux 上是 OpenSSL) - 每次哈希都新建实例,别存字段或静态变量里反复调用
ComputeHash() - 不写
using?资源不释放,高频调用下句柄泄漏,Windows 上可能报ERROR_TOO_MANY_OPEN_FILES
真正容易被忽略的,是哈希前的编码选择和哈希后的格式化——这两步出错,结果看起来“算出来了”,其实和别人根本对不上。


















