简体   繁体   English

HMAC SHA256 JWT签名不正确

[英]HMAC SHA256 JWT Signature is incorrect

The answer: 答案:

Instead of the hmac func below here are the functions I am now using... 我现在正在使用的功能不是下面的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
}

ORIGINAL POST 原始帖子

I have a JWT which I am trying to verify the signature. 我有一个JWT,我正在尝试验证签名。 Here is the JWT... 这是JWT ...

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhcGkudGVzdC5jb20vdjEvYXV0aCIsImV4cCI6MTQ2OTk3ODQ5OCwic3ViIjoiMTIzNDU2Nzg5MCIsImVtYWlsIjoidGVzdEB0ZXN0LmNvbSIsInJvbGVzIjpbImFkbWluIiwiY3VzdG9tZXIiXSwicGVybWlzc2lvbnMiOlsidGVzdC5wcm9maWxlIiwidGVzdC5wcm9maWxlLmNvbnRhY3QiLCJ0ZXN0LnByb2ZpbGUuZGV2aWNlIiwidGVzdC5wcm9maWxlLmFwcCJdfQ.GfLxXOL978Pm5GYMI0WTBEVcMrfVj2jJb-Il_XzO7g4 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhcGkudGVzdC5jb20vdjEvYXV0aCIsImV4cCI6MTQ2OTk3ODQ5OCwic3ViIjoiMTIzNDU2Nzg5MCIsImVtYWlsIjoidGVzdEB0ZXN0LmNvbSIsInJvbGVzIjpbImFkbWluIiwiY3VzdG9tZXIiXSwicGVybWlzc2lvbnMiOlsidGVzdC5wcm9maWxlIiwidGVzdC5wcm9maWxlLmNvbnRhY3QiLCJ0ZXN0LnByb2ZpbGUuZGV2aWNlIiwidGVzdC5wcm9maWxlLmFwcCJdfQ.GfLxXOL978Pm5GYMI0WTBEVcMrfVj2jJb-Il_XzO7g4

I'm working in Swift 3 and I updated the methods in this SO answer https://stackoverflow.com/a/24411522/741626 . 我在Swift 3中工作,我更新了此SO回答https://stackoverflow.com/a/24411522/741626中的方法。 This is what those methods now look like. 这就是这些方法现在的样子。

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

}

I am able to base64Decode the header & payload successfully but when I try to verify the signature it's always wrong (doesn't look anything like AND is way too long). 我能够成功base64Decode标头和有效载荷,但是当我尝试验证签名时,它总是错误的(看起来不像AND太长了)。

What I've tried. 我尝试过的

1 I've tried several JWTs - always wrong in the same way 1我尝试了几个JWT-总是以相同的方式出错

2 I've hard coded the sha256 constants to ensure I wasn't using the wrong encoding / length 2我已经硬编码了sha256常量,以确保我没有使用错误的编码/长度

3 I've tried many types of String.Encoding but while they always generate a different result as expected, none of them generate the desired signature. 3我已经尝试了许多类型的String.Encoding,但是尽管它们总是按预期生成不同的结果,但是它们都不生成所需的签名。

4 I've used an Objective-C method to generate the hmac to try and rule out if my conversion to Swift 3 broke anything. 4我使用了Objective-C方法来生成hmac,以尝试排除我向Swift 3的转换是否中断了任何事情。 Same results, here is the Objective C code. 结果相同,这是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;
}

The code originated here: https://stackoverflow.com/a/31003443/741626 . 该代码源自此处: https : //stackoverflow.com/a/31003443/741626 I'd rather not plug in Objective-C code to my Swift project but if I have to I will! 我宁愿不将Objective-C代码插入我的Swift项目,但如果需要的话,我会的!

Here is my calling func 这是我的电话功能

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: "")
}

EDIT 编辑

When I run the code the resulting hmac is 当我运行代码时,生成的hmac是

19f2f15ce2fdefc3e6e4660c23459304455c32b7d58f68c96fe225fd7cceee0e 19f2f15ce2fdefc3e6e4660c23459304455c32b7d58f68c96fe225fd7cceee0e

I've triple checked that the secret is correct, which is "" (empty string) 我已经三重检查了机密是否正确,即“” (空字符串)

What am I doing wrong? 我究竟做错了什么?

I would really like to test in my client app that the tokens I receive are trustworthy rather than glossing over this. 我真的很想在客户端应用程序中测试我收到的令牌是否值得信任,而不是掩饰这一点。 If anyone has any ideas what I'm doing wrong that would be great. 如果有人有任何想法,我做错了,那将很棒。

Actually the value that you've generated is correct. 实际上,您生成的值是正确的。 It's just that you're looking at the hexadecimal representation of the HMAC value (and thus hash function), while the JWT hash is of course base64url encoded. 只是您正在查看HMAC值的十六进制表示形式(以及哈希函数),而JWT哈希当然是base64url编码的。

To verify the hash it is important to compare the byte values instead of the encoded values. 为了验证哈希,比较字节值而不是编码值很重要。 The encoded values are just required for human consumption (hexadecimals) or transport over protocols that require text (base64url). 编码值仅用于人类消费(十六进制)或通过需要文本的协议进行传输(base64url)。


When performing the byte array comparison, please make sure that it is time constant or you may introduce vulnerabilities. 执行字节数组比较时,请确保它是时间常数,否则可能会引入漏洞。

One way is to XOR the bytes and then OR the result into a result byte. 一种方法是对字节进行XOR,然后将结果与OR生成结果字节。 Then test that result byte against 00h (any other value indicates an invalid comparison). 然后针对00h测试该结果字节(任何其他值表示无效的比较)。 Reject incorrectly sized arrays first. 首先拒绝大小不正确的数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM