寻求PHP转C#的HMAC-SHA256验证函数getVerifiedPayload实现帮助
从PHP转换C#的HMAC验证函数实现
我们需要在服务器与客户端间安全传输数据包,已用PHP实现相关逻辑,现需转为C#代码。刚接触C#,已完成createHashedPayload函数的转换,附上PHP原代码及已实现的C#加密函数,请求帮助转换getVerifiedPayload验证函数。
PHP原代码
function createHashedPayload(string $packet, string $secret, string $hash = 'sha256'): string { return base64_encode(hash_hmac('sha256', $packet, $secret, true) . $packet); } function getVerifiedPayload(string $payload, string $secret, string $hash = 'sha256'): ?string { $decoded = base64_decode($payload); $hashlen = strlen(hash($hash, "test", true)); // Quick method to get hash length $hmac = substr($decoded, 0, $hashlen); // Get HMAC from start of string $content = substr($decoded, $hashlen); // Rest of the string is content // Verify HMAC $calcmac = hash_hmac($hash, $content, $secret, true); if (hash_equals($hmac, $calcmac)) { return $content; } return null; }
已实现的C#加密函数
static string createHashedPayload(string text, string key) { key = key ?? ""; using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(key))) { var hash = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(text)); return Convert.ToBase64String(hash); } }
修正后的C#完整实现
1. 先修正createHashedPayload函数
注意:当前C#版的createHashedPayload和PHP逻辑不一致——PHP是将HMAC字节流与原始数据包字节拼接后再做Base64编码,而当前C#版仅返回了HMAC的Base64,这会导致后续验证失败,先做修正:
static string CreateHashedPayload(string text, string key) { key = key ?? string.Empty; byte[] textBytes = Encoding.UTF8.GetBytes(text); using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(key))) { byte[] hashBytes = hmacsha256.ComputeHash(textBytes); // 拼接HMAC字节和原始文本字节 byte[] combinedBytes = new byte[hashBytes.Length + textBytes.Length]; Buffer.BlockCopy(hashBytes, 0, combinedBytes, 0, hashBytes.Length); Buffer.BlockCopy(textBytes, 0, combinedBytes, hashBytes.Length, textBytes.Length); return Convert.ToBase64String(combinedBytes); } }
2. 实现GetVerifiedPayload验证函数
对应PHP的getVerifiedPayload逻辑,完成C#版本:
static string? GetVerifiedPayload(string payload, string key) { key = key ?? string.Empty; try { // 解码Base64字符串 byte[] decodedBytes = Convert.FromBase64String(payload); // SHA256的HMAC固定长度为32字节,直接使用固定值替代PHP的动态获取方式 int hashLength = 32; // 校验数据长度是否合法 if (decodedBytes.Length < hashLength) { return null; } // 拆分出接收到的HMAC和原始内容字节 byte[] receivedHmac = new byte[hashLength]; byte[] contentBytes = new byte[decodedBytes.Length - hashLength]; Buffer.BlockCopy(decodedBytes, 0, receivedHmac, 0, hashLength); Buffer.BlockCopy(decodedBytes, hashLength, contentBytes, 0, contentBytes.Length); // 计算内容的HMAC using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(key))) { byte[] calculatedHmac = hmacsha256.ComputeHash(contentBytes); // 用固定时间比较防范时序攻击,等价于PHP的hash_equals if (CryptographicOperations.FixedTimeEquals(receivedHmac, calculatedHmac)) { return Encoding.UTF8.GetString(contentBytes); } } } catch (FormatException) { // Base64解码失败直接返回null return null; } return null; }
补充说明
- 使用
CryptographicOperations.FixedTimeEquals做字节数组比较,避免时序攻击,保证验证安全性; - SHA256的HMAC长度固定为32字节,无需像PHP那样动态计算,直接用固定值更高效;
- 加入异常捕获处理Base64解码失败的情况,避免程序崩溃。
内容的提问来源于stack exchange,提问作者jagadeeshaleti
相关产品推荐
相关产品推荐

