Reputation: 23
I am attempting at following the [RFC for JSON Web Signatures]1 but getting some problems when following the example.
I get everything up until the end, where I am unable to generate the same signature. Here is the example Python 3.8 code:
import hmac
import hashlib
import base64
signing_input = b"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
key = b"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
signature = hmac.digest(key, signing_input, digest=hashlib.sha256)
print(base64.urlsafe_b64encode(signature))
# Output: b'ZekyXWlxvuCN9H8cuDrZfaRa3pMJhHpv6QKFdUqXbLc='
# Expected: b'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'
Additionally I have tried a few online tools that handle HMAC-SHA256 but I am getting the same output as my Python script provides. Any ideas on where I'm going wrong? [1]: https://www.rfc-editor.org/rfc/rfc7515#appendix-A.1
Upvotes: 2
Views: 1548
Reputation: 30494
You're using the wrong key. The RFC shows the key in the JSON Web Key format using the JSON Web Algorithm "oct"
. This means that the key is a base64url encoded sequence of bytes. You need to decode it before using it if you want your results to match.
Note that python's urlsafe_b64decode
and urlsafe_b64encode
do not exactly implement the base64url encoding used by JWT and friends. The python functions expect/produce padding characters, which the base64url encoding used by JWT specifies should be removed.
Putting this all together:
import hmac
import hashlib
import base64
signing_input = b"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
key = b"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
# Decode the key. Pad it with '=' characters to a length divisible by 4
# as expected by urlsafe_b64decode
if len(key) % 4 == 2:
key += b'=='
elif len(key) % 4 == 3:
key += b'='
key = base64.urlsafe_b64decode(key)
signature = hmac.digest(key, signing_input, digest=hashlib.sha256)
signature = base64.urlsafe_b64encode(signature)
# Strip off any '=' characters urlsafe_b64encode added to pad the key to
# a length divisible by 4
signature = signature.rstrip(b'=')
print(signature)
# Prints: b'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'
Upvotes: 4