import std/logging import bearssl import ../../encoding import ../../jwa import ../../jwk proc bearHMAC(message: string, alg: JwtAlgorithm, key: string): string = var vtable: ptr HashClass var hashSize: int case alg: of HS256: vtable = addr sha256Vtable; hashSize = sha256Size of HS384: vtable = addr sha384Vtable; hashSize = sha384Size of HS512: vtable = addr sha512Vtable; hashSize = sha512Size else: raise newException(ValueError, "Unsupported HMAC algorithm '" & $alg & "'") if key.len < hashSize: warn( "Computing an HMAC with a small key (" & $key.len & " bytes). It " & "is recommended to use keys of at least " & $hashSize & " bytes for " & $alg) var keyCtx: HmacKeyContext var hmacCtx: HmacContext hmacKeyInit(keyCtx, vtable, key.cstring, uint key.len) hmacInit(hmacCtx, keyCtx, uint 0) hmacUpdate(hmacCtx, message.cstring, uint message.len) let resLen = hmacSize(hmacCtx) result = newString(resLen) discard hmacOut(hmacCtx, addr result[0]) proc hmac*(message: string, alg: JwtAlgorithm, key: string): string = return bearHMAC(message, alg, key) proc hmac*(message: string, alg: JwtAlgorithm, key: JWK): string = if key.keyKind != Octet: raise newException(ValueError, $alg & " requires an octet key (\"typ\"=\"oct\"), not a \"typ\"=\"" & $(key.keyKind) & "\" key.") return bearHMAC(message, alg, b64UrlDecode(key.octKey.k))