SHA256.Create() 是最稳妥的创建方式,应避免使用已过时且平台兼容性差的 new SHA256Managed();字符串哈希前必须显式用 Encoding.UTF8.GetBytes() 转码,输出推荐 BitConverter.ToString().Replace("-", "").ToLower() 得十六进制小写字符串。

SHA256.Create() 是最稳妥的创建方式
直接调用 SHA256.Create() 而不是 new SHA256Managed(),因为后者在 .NET Core 2.0+ 和 .NET 5+ 中已被标记为过时,且部分平台(如 iOS、AOT 编译环境)可能不支持。前者会根据运行时自动选择最优实现,兼容性更好。
常见错误是硬编码 new SHA256Managed(),导致在 .NET 6+ 的单文件发布或某些容器环境中抛出 PlatformNotSupportedException。
- 始终用
using var sha = SHA256.Create(); - 不要手动指定具体子类,除非你明确需要控制算法提供者(如 FIPS 模式下强制使用特定实现)
- 该方法返回的实例线程不安全,不可复用,每次计算都应新建或使用 using 释放
字符串转字节数组必须显式指定编码
SHA256 对字节流运算,不是对字符串本身。忽略编码会导致相同中文字符串在 UTF-8 和 UTF-16 下产生完全不同的哈希值,这是线上验签失败的高频原因。
默认 Encoding.Default 是系统区域设置相关编码(如中文 Windows 是 GB2312),极不可靠;Encoding.Unicode(即 UTF-16)会产生两倍长度的字节流,和绝大多数服务端(如 JWT、API 签名)约定的 UTF-8 不一致。
- 99% 场景应统一用
Encoding.UTF8.GetBytes(input) - 若对接遗留系统明确要求 GBK,才改用
Encoding.GetEncoding("GBK") - 避免用
input.ToCharArray()或直接调 string.Length —— 这些操作不产生字节,无法喂给哈希函数
输出结果推荐用十六进制小写字符串
ComputeHash() 返回的是 byte[],需自行格式化。用 BitConverter.ToString(hash).Replace("-", "").ToLower() 最常用,但要注意:
-
BitConverter.ToString()默认带短横线,必须.Replace("-", "")去掉 - 不加
.ToLower()会输出大写(如A1B2…),而多数协议(OAuth2、AWS Signature)要求小写,大小写混用会导致签名比对失败 - 不用
string.Concat(hash.Select(b => b.ToString("x2")))—— LINQ 在高并发场景有额外分配开销,非必要不选
示例:
using var sha = SHA256.Create();
byte[] bytes = Encoding.UTF8.GetBytes("hello");
byte[] hash = sha.ComputeHash(bytes);
string result = BitConverter.ToString(hash).Replace("-", "").ToLower(); // "2cf24dba89f8b07e1a89e1b89f0d8b8c9b8c9b8c9b8c9b8c9b8c9b8c9b8c9b8c"
需要 Base64 输出时别漏掉 padding
有些 API(如某些 HTTP 头签名字段)要求 Base64 编码的哈希值。直接 Convert.ToBase64String(hash) 是正确的,但要注意:
- 它默认保留填充字符
=(如LP1LqoifmH4KieG4uYDovIvIvIvIvIvIvIvIvIvIvI=),大多数协议接受这个格式 - 若目标系统明确禁止
=(如某些 URL 安全场景),需用Convert.ToBase64String(hash, Base64FormattingOptions.None)并手动替换+和/为-和_,再截去末尾= - 切勿用
Convert.ToBase64String(hash).Replace("=", "")—— 这会破坏解码逻辑,因为缺失 padding 会导致长度非法
SHA256 计算本身很简单,真正容易出问题的永远是前后两端:输入编码是否一致、输出格式是否匹配协议约定。尤其是跨语言对接时,Python 的 hashlib.sha256(s.encode()).hexdigest() 默认 UTF-8,Java 的 MessageDigest.getInstance("SHA-256").digest(s.getBytes(StandardCharsets.UTF_8)) 也是 UTF-8 —— C# 必须对齐这个隐含契约。











