[英]HMAC SHA256 JWT Signature is incorrect
答案:
我现在正在使用的功能不是下面的hmac func ...
func base64Encoded(algorithm: CryptoAlgorithm, key: String) -> String {
let hmac = self.hmac(algorithm: algorithm, key: key)
let digestLen = algorithm.digestLength
let dataResult = NSData(bytes: hmac, length: digestLen)
hmac.deallocateCapacity(digestLen)
return dataResult.base64EncodedString()
}
func hash(algorithm: CryptoAlgorithm, key: String) -> String {
let hmac = self.hmac(algorithm: algorithm, key: key)
let digestLen = algorithm.digestLength
let hash = NSMutableString()
for i in 0..<digestLen {
hash.appendFormat("%02x", hmac[i])
}
hmac.deallocateCapacity(digestLen)
return hash as String
}
func hmac(algorithm: CryptoAlgorithm, key: String) -> UnsafeMutablePointer<CUnsignedChar> {
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>(allocatingCapacity: 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)
return result
}
原始帖子
我有一个JWT,我正在尝试验证签名。 这是JWT ...
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhcGkudGVzdC5jb20vdjEvYXV0aCIsImV4cCI6MTQ2OTk3ODQ5OCwic3ViIjoiMTIzNDU2Nzg5MCIsImVtYWlsIjoidGVzdEB0ZXN0LmNvbSIsInJvbGVzIjpbImFkbWluIiwiY3VzdG9tZXIiXSwicGVybWlzc2lvbnMiOlsidGVzdC5wcm9maWxlIiwidGVzdC5wcm9maWxlLmNvbnRhY3QiLCJ0ZXN0LnByb2ZpbGUuZGV2aWNlIiwidGVzdC5wcm9maWxlLmFwcCJdfQ.GfLxXOL978Pm5GYMI0WTBEVcMrfVj2jJb-Il_XzO7g4
我在Swift 3中工作,我更新了此SO回答https://stackoverflow.com/a/24411522/741626中的方法。 这就是这些方法现在的样子。
import Foundation
enum CryptoAlgorithm {
case MD5, SHA1, SHA224, SHA256, SHA384, SHA512
var HMACAlgorithm: CCHmacAlgorithm {
var result: Int = 0
switch self {
case .MD5: result = kCCHmacAlgMD5
case .SHA1: result = kCCHmacAlgSHA1
case .SHA224: result = kCCHmacAlgSHA224
case .SHA256: result = kCCHmacAlgSHA256
case .SHA384: result = kCCHmacAlgSHA384
case .SHA512: result = kCCHmacAlgSHA512
}
return CCHmacAlgorithm(result)
}
var digestLength: Int {
var result: Int32 = 0
switch self {
case .MD5: result = CC_MD5_DIGEST_LENGTH
case .SHA1: result = CC_SHA1_DIGEST_LENGTH
case .SHA224: result = CC_SHA224_DIGEST_LENGTH
case .SHA256: result = CC_SHA256_DIGEST_LENGTH
case .SHA384: result = CC_SHA384_DIGEST_LENGTH
case .SHA512: result = CC_SHA512_DIGEST_LENGTH
}
return Int(result)
}
}
extension String {
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>(allocatingCapacity: 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 hash = NSMutableString()
for i in 0..<digestLen {
hash.appendFormat("%02x", result[i])
}
result.deallocateCapacity(digestLen)
return hash as String
}
我能够成功base64Decode标头和有效载荷,但是当我尝试验证签名时,它总是错误的(看起来不像AND太长了)。
我尝试过的
1我尝试了几个JWT-总是以相同的方式出错
2我已经硬编码了sha256常量,以确保我没有使用错误的编码/长度
3我已经尝试了许多类型的String.Encoding,但是尽管它们总是按预期生成不同的结果,但是它们都不生成所需的签名。
4我使用了Objective-C方法来生成hmac,以尝试排除我向Swift 3的转换是否中断了任何事情。 结果相同,这是Objective C代码。
+ (NSData *)hmacSha256:(NSString *)string key:(NSString *)key;
{
NSData *dataIn = [string dataUsingEncoding:NSUTF8StringEncoding];
NSData *keyIn = [key dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *macOut = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];
CCHmac( kCCHmacAlgSHA256,
keyIn.bytes,
keyIn.length,
dataIn.bytes,
dataIn.length,
macOut.mutableBytes);
return macOut;
}
该代码源自此处: https : //stackoverflow.com/a/31003443/741626 。 我宁愿不将Objective-C代码插入我的Swift项目,但如果需要的话,我会的!
这是我的电话功能
func decodeToken(token: String) {
let array = token.characters.split(isSeparator: { $0 == "." })
.map(String.init)
let header:String = String(array[0])
let payload:String = String(array[1])
let signature:String = String(array[2])
let encodedString = header + "." + payload
let hmac = encodedString.hmac(algorithm: .SHA256, key: "")
}
编辑
当我运行代码时,生成的hmac是
19f2f15ce2fdefc3e6e4660c23459304455c32b7d58f68c96fe225fd7cceee0e
我已经三重检查了机密是否正确,即“” (空字符串)
我究竟做错了什么?
我真的很想在客户端应用程序中测试我收到的令牌是否值得信任,而不是掩饰这一点。 如果有人有任何想法,我做错了,那将很棒。
实际上,您生成的值是正确的。 只是您正在查看HMAC值的十六进制表示形式(以及哈希函数),而JWT哈希当然是base64url编码的。
为了验证哈希,比较字节值而不是编码值很重要。 编码值仅用于人类消费(十六进制)或通过需要文本的协议进行传输(base64url)。
执行字节数组比较时,请确保它是时间常数,否则可能会引入漏洞。
一种方法是对字节进行XOR,然后将结果与OR生成结果字节。 然后针对00h测试该结果字节(任何其他值表示无效的比较)。 首先拒绝大小不正确的数组。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.