如何生成SCRAM-SHA-256哈希值以通过.NET5创建PostgreSQL 13用户
核心问题解答
- PostgreSQL 13+ 使用的SCRAM-SHA-256密码哈希方案不需要在计算前拼接用户名,这一点和旧版MD5哈希规则完全不同。
- 你可以直接用.NET 5原生的密码学API生成符合PostgreSQL规范的哈希串,不需要依赖第三方组件。
实现逻辑说明
PostgreSQL的SCRAM-SHA-256哈希串遵循固定格式:SCRAM-SHA-256$<迭代次数>:<Base64编码的盐>$<Base64编码的StoredKey>:<Base64编码的ServerKey>
生成步骤遵循RFC 7677规范:
- 用PBKDF2-HMAC-SHA256算法,以明文密码、随机盐、4096次迭代(PostgreSQL默认值)为参数,派生得到32字节的SaltedPassword
- 以SaltedPassword为密钥,对字符串
Client Key做HMAC-SHA256运算得到Client Key,再对Client Key做SHA256哈希得到StoredKey - 以SaltedPassword为密钥,对字符串
Server Key做HMAC-SHA256运算得到Server Key - 把各部分按上述格式拼接即可
.NET 5 实现代码
using System; using System.Security.Cryptography; using System.Text; public static class PostgresPasswordHasher { /// <summary> /// 生成PostgreSQL兼容的SCRAM-SHA-256密码哈希 /// </summary> /// <param name="plainPassword">明文密码</param> /// <param name="iterations">迭代次数,PostgreSQL默认值为4096</param> /// <param name="salt">自定义盐,不传入则自动生成16字节加密安全随机盐</param> /// <returns>可直接用于CREATE USER语句的哈希字符串</returns> public static string GenerateScramSha256Hash(string plainPassword, int iterations = 4096, byte[] salt = null) { // 盐处理:未传入则生成16字节加密安全随机盐 salt ??= new byte[16]; if (salt.Length == 0) { RandomNumberGenerator.Fill(salt); } // 派生SaltedPassword using var pbkdf2 = new Rfc2898DeriveBytes( password: plainPassword, salt: salt, iterations: iterations, hashAlgorithm: HashAlgorithmName.SHA256); byte[] saltedPassword = pbkdf2.GetBytes(32); // 计算StoredKey byte[] clientKey; using (var hmacClient = new HMACSHA256(saltedPassword)) { clientKey = hmacClient.ComputeHash(Encoding.UTF8.GetBytes("Client Key")); } byte[] storedKey = SHA256.HashData(clientKey); // 计算ServerKey byte[] serverKey; using (var hmacServer = new HMACSHA256(saltedPassword)) { serverKey = hmacServer.ComputeHash(Encoding.UTF8.GetBytes("Server Key")); } // 拼接为PostgreSQL要求的格式 return $"SCRAM-SHA-256${iterations}:{Convert.ToBase64String(salt)}${Convert.ToBase64String(storedKey)}:{Convert.ToBase64String(serverKey)}"; } }
使用示例
如果要生成明文为postgres的哈希,直接调用方法即可:
var hash = PostgresPasswordHasher.GenerateScramSha256Hash("postgres");
得到的哈希串可以直接填入CREATE USER语句的PASSWORD参数使用,和你示例中的效果完全一致。如果需要复现你给出的示例哈希,只需要把示例中的盐H45+UIZiJUcEXrB9SHlv5Q==转为字节数组传入方法的salt参数即可。
内容的提问来源于stack exchange,提问作者kuja
相关产品推荐
相关产品推荐

