【问题标题】:JWT verify signature using HMACSHA256 and show "Invalid Signature" by SwiftJWT 使用 HMACSHA256 验证签名并由 Swift 显示“无效签名”
【发布时间】:2019-10-06 09:59:00
【问题描述】:

我有一个关于智威汤逊的问题。
我尝试创建自己的签名并使用硬编码密钥“hello1234567890987654321test1234”。
我使用我的函数创建签名并发布到https://jwt.io/ 进行解码。
然后这个网站显示“无效签名”。
我的 HMACSHA256 函数有什么问题?
我在网页中找到了“-”,“_”,并在我的输出签名中转换了“+”,“/”。
如何修复我的输出签名?
这个签名正确吗?

我还在 Google 中找到了两种 HMACSHA256 方法。我不知道哪个更好。
请给我一些关于选择这个的建议。
谢谢。

图片:

方法一:

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 hmac1(algorithm: CryptoAlgorithm, key: String) -> String {
        var result: [CUnsignedChar]
        if let ckey = key.cString(using: String.Encoding.utf8), let cdata = self.cString(using: String.Encoding.utf8) {
            result = Array(repeating: 0, count: Int(algorithm.digestLength))
            CCHmac(algorithm.HMACAlgorithm, ckey, ckey.count-1, cdata, cdata.count-1, &result)
        } else {
            fatalError("Nil returned when processing input strings as UTF8")
        }

        return Data(bytes: result, count: result.count).base64EncodedString()
    }
}

方法二:

enum HMACAlgorithm {
    case MD5, SHA1, SHA224, SHA256, SHA384, SHA512

    func toCCHmacAlgorithm() -> 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)
    }

    func digestLength() -> Int {
        var result: CInt = 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 hmac2(algorithm: HMACAlgorithm, key: String) -> String {
        let cKey = key.cString(using: String.Encoding.utf8)
        let cData = self.cString(using: String.Encoding.utf8)
        var result = [CUnsignedChar](repeating: 0, count: Int(algorithm.digestLength()))
        CCHmac(algorithm.toCCHmacAlgorithm(), cKey!, strlen(cKey!), cData!, strlen(cData!), &result)
        let hmacData:NSData = NSData(bytes: result, length: (Int(algorithm.digestLength())))
        let hmacBase64 = hmacData.base64EncodedString(options: .lineLength76Characters)
        return String(hmacBase64)
    }
}

用法:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let headerString: String = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
        let payloadString: String = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"
        let totalString: String = headerString + "." + payloadString

        let signature1 = totalString.hmac1(algorithm: .SHA256, key: "hello1234567890987654321test1234")
        let signature2 = totalString.hmac2(algorithm: .SHA256, key: "hello1234567890987654321test1234")

        print("signature1 : \(signature1)") // signature1 : L9YSDasvO2B5i8FZUczC+MAtSsTuM0Dj+FEpfn6uoRs=
        print("signature2 : \(signature2)") // signature2 : L9YSDasvO2B5i8FZUczC+MAtSsTuM0Dj+FEpfn6uoRs=

    }
}

【问题讨论】:

  • 注意:我在下面回答您的主要问题,但不是关于哪种方法更好的问题。请一次只问一个问题。哪个更好也是一个基于意见的问题,在 SO 上被认为是题外话。

标签: ios swift jwt sha256 hmac


【解决方案1】:

问题在于编码。 JWT uses base64url encoding

JWT 表示为 URL 安全部分的序列,由 句点 ('.') 字符。每个部分都包含一个 base64url 编码的 价值。

但您在签名中使用 base64 编码,如您的代码示例所示。

base64url encoding 和 base64 编码之间的区别在于,正常 base64 输出中的字符“+”和“/”将被替换为“-”和“_”,而结尾的“=”(填充)将省略。

你说:

我在网页中找到了“-”,“_”,并在我的输出签名中转换了“+”,“/”。

使用 '-' 和 '_' 而不是 '+' 和 '/' 你有一个正确的输出。

当你有这样的 base64url 编码签名时

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.L9YSDasvO2B5i8FZUczC-MAtSsTuM0Dj-FEp>

签名将被验证。

【讨论】:

  • 谢谢。我是否需要从 base64 编码 base64url?喜欢下面的问题stackoverflow.com/questions/43499651/…
  • 是的,这就是重点,签名必须是 base64url 编码。我不是 swift 用户,所以我不确定你可以使用哪些方法,但结果应该是 base64url 编码的。
  • 之前没有注意到您第一条评论中的链接。是的,如果没有直接base64url转换,接受答案中的base64ToBase64url函数应该没问题。
猜你喜欢
  • 2018-09-16
  • 2016-08-28
  • 1970-01-01
  • 2017-04-03
  • 2016-12-29
  • 2023-03-25
  • 2019-11-14
  • 2019-10-30
相关资源
最近更新 更多