C# 中的 HMAC SHA256 与 Swift 中的 HMAC SHA256 不匹配
HMAC SHA256 in C# vs HMAC SHA256 in Swift don't match
在 dotnetcore C# 中使用 'standard' HMACSHA256 技术,我可以生成一个散列字符串,如下所示:
private static void Test()
{
var hmac = new HMACSHA256(Encoding.UTF8.GetBytes("testingkey"));
var theHash = hmac.ComputeHash(Encoding.UTF8.GetBytes("testingstringtohash"));
string signature = Convert.ToBase64String(theHash);
Console.WriteLine(signature);
}
//Produces yg/9NCAm5IIwGKJK80PyUeBWkzEUwZswvC3OVnTnT80=
在 swift 中做同样的事情(来自 答案的解决方案似乎是人们正在使用的 'standard')
func HashTest() {
let hash = "testingstringtohash".hmac(algorithm: .SHA256, key: "testingkey")
//hash ca0ffd342026e4823018a24af343f251e056933114c19b30bc2dce5674e74fcd
let hexData = hash.data(using: String.Encoding.utf8)
let signature = hexData?.base64EncodedString()
print(signature!)
}
//Produces Y2EwZmZkMzQyMDI2ZTQ4MjMwMThhMjRhZjM0M2YyNTFlMDU2OTMzMTE0YzE5YjMwYmMyZGNlNTY3NGU3NGZjZA==
我在这里是不是很愚蠢...或者这两个值应该相同,因为它是相同的加密算法,并且相同的密钥对应相同的值。据我所知,C# 示例生成 'correct' 结果,因为使用该示例生成的值的 Web 服务工作正常,但 swift 版本生成的值失败。
这里的问题似乎是给定 swift 解决方案与 C# 解决方案之间的 base64 字符串不同。
哈希算法的输出在字节级别是相同的,但在返回之前通过各种字符串转换进行了操作。
函数
private func stringFromResult(result: UnsafeMutablePointer<CUnsignedChar>, length: Int) -> String {
let hash = NSMutableString()
for i in 0..<length {
hash.appendFormat("%02x", result[i])
}
return String(hash).lowercased()
}
解决方案的一部分是将原始哈希数据转换为字符串,然后在调用 class 中将其转换回数据对象,然后转换为 base64 字符串以返回。由于我们得到的是返回字符串的 base64 字符串,而不是原始字节,我认为这就是问题所在。
通过将 hmac 代码从解决方案更改为此,我们可以将 has 的原始输出转换为 base64 字符串并避免其他步骤。这与 C# 值匹配。
func hmac(algorithm: CryptoAlgorithm, key: String) -> String {
let str = self.cString(using: String.Encoding.utf8)
let strLen = Int(self.lengthOfBytes(using: String.Encoding.utf8))
let digestLen = algorithm.digestLength
let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
let keyStr = key.cString(using: String.Encoding.utf8)
let keyLen = Int(key.lengthOfBytes(using: String.Encoding.utf8))
CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result)
let a = UnsafeMutableBufferPointer(start: result, count: digestLen)
let b = Data(a)
result.deallocate()
let digest = b.base64EncodedString()
return digest
}
在 dotnetcore C# 中使用 'standard' HMACSHA256 技术,我可以生成一个散列字符串,如下所示:
private static void Test()
{
var hmac = new HMACSHA256(Encoding.UTF8.GetBytes("testingkey"));
var theHash = hmac.ComputeHash(Encoding.UTF8.GetBytes("testingstringtohash"));
string signature = Convert.ToBase64String(theHash);
Console.WriteLine(signature);
}
//Produces yg/9NCAm5IIwGKJK80PyUeBWkzEUwZswvC3OVnTnT80=
在 swift 中做同样的事情(来自
func HashTest() {
let hash = "testingstringtohash".hmac(algorithm: .SHA256, key: "testingkey")
//hash ca0ffd342026e4823018a24af343f251e056933114c19b30bc2dce5674e74fcd
let hexData = hash.data(using: String.Encoding.utf8)
let signature = hexData?.base64EncodedString()
print(signature!)
}
//Produces Y2EwZmZkMzQyMDI2ZTQ4MjMwMThhMjRhZjM0M2YyNTFlMDU2OTMzMTE0YzE5YjMwYmMyZGNlNTY3NGU3NGZjZA==
我在这里是不是很愚蠢...或者这两个值应该相同,因为它是相同的加密算法,并且相同的密钥对应相同的值。据我所知,C# 示例生成 'correct' 结果,因为使用该示例生成的值的 Web 服务工作正常,但 swift 版本生成的值失败。
这里的问题似乎是给定 swift 解决方案与 C# 解决方案之间的 base64 字符串不同。
哈希算法的输出在字节级别是相同的,但在返回之前通过各种字符串转换进行了操作。
函数
private func stringFromResult(result: UnsafeMutablePointer<CUnsignedChar>, length: Int) -> String {
let hash = NSMutableString()
for i in 0..<length {
hash.appendFormat("%02x", result[i])
}
return String(hash).lowercased()
}
解决方案的一部分是将原始哈希数据转换为字符串,然后在调用 class 中将其转换回数据对象,然后转换为 base64 字符串以返回。由于我们得到的是返回字符串的 base64 字符串,而不是原始字节,我认为这就是问题所在。
通过将 hmac 代码从解决方案更改为此,我们可以将 has 的原始输出转换为 base64 字符串并避免其他步骤。这与 C# 值匹配。
func hmac(algorithm: CryptoAlgorithm, key: String) -> String {
let str = self.cString(using: String.Encoding.utf8)
let strLen = Int(self.lengthOfBytes(using: String.Encoding.utf8))
let digestLen = algorithm.digestLength
let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
let keyStr = key.cString(using: String.Encoding.utf8)
let keyLen = Int(key.lengthOfBytes(using: String.Encoding.utf8))
CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result)
let a = UnsafeMutableBufferPointer(start: result, count: digestLen)
let b = Data(a)
result.deallocate()
let digest = b.base64EncodedString()
return digest
}