Generate a public key with a predefined modulus and exponent
Asked Answered
F

1

3
"n": "rKZ-1zdz_CoLekSynOtyWv6cPSSkV28Kb9kZZHyYL-yhkKnH_bHl8OpWiGxQiKP0ulLRIaq1IhSMetkZ8FfXH-iptIDu4lPb8gt0HQYkjcy3HoaKRXBw2F8fJQO4jQ-ufR4l-E0HRqwLywzdtAImNWmju3A4kx8s0iSGHGSHyE4EUdh5WKt-NMtfUPfB5v9_2bC-w6wH7zAEsI5nscMXnvz1u8w7g2_agyhKSK0D9OkJ02w3I4xLMlrtKEv2naoBGerWckKcQ1kBYUh6WASPdvTqX4pcAJi7Tg6jwQXIP1aEq0JU8C0zE3d33kaMoCN3SenIxpRczRzUHpbZ-gk5PQ",
"e": "AQAB",

How can I generate a public key from these values? Preferable via python or Linux programs. I'm sorry if the question is nonsense because of invalid values.

The source is here.

Flatt answered 27/1, 2021 at 13:19 Comment(0)
O
5

In Python, you can use Python-JOSE

What you got there in your link is a JSON Web Key Set (JWKS), a JSON formated array of JSON Web Keys (JWK).

n and e are the modulus and exponent of a RSA public key.

The function jwk.construct can directly create a key from a JWK. The key can then be used e.g. to verify a JWT (key.verify).

You can also use jwt.decode like shown in the code below and pass the JWK directly, or in PEM format.

from jose import jwk
from jose.utils import base64url_decode

token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlctNjduZWt0WVRjOEpWWVBlV0g1c1dlN1JZVm5uMFN5NzQxZjhUT0pfQWMifQ.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.hiKxeC66LIyVKOXjiOk7iScFPy_5-ATw7hEfqGij8sBZmwXAeTPT5BRFYHitFKSXomGqmy_63LLvg4zbhcTTmNf8XIeDAuLsC32soO5woSByisswWHVf8BgxMkI_FPW_oEtEQ8Xv3FL_1rF9j9Oy3jIjgjqhFhXUtsSQWAeuGYH-OQljFwiuO5Bqexcw-H71OEWvQLQof_6KJ0viJyte8QEwEVridyO834-ppHzeaoW2sTvZ22ZNfxPCew0Ul2V_TxHTtO7ZuJCZ81EmeIV6dYJ2GrYh3UN1x1PHy4-tEn-PL4otlaO3PYOcXfCHxHa6xtPsquzPZJnB1Vq8zULLfQ"

rsa_key = {
    "kty": "RSA",
    "kid": "W-67nektYTc8JVYPeWH5sWe7RYVnn0Sy741f8TOJ_Ac",
    "use": "sig",
    "alg": "RS256",
    "n": "kFpGoVmBmmKepvBQiwq3hU9lIAuGsAPda4AVk712d3Z_QoS-5veGp4yltnyEFYyX867GOKDpbH7OF2uIjDg4-FPZwbuhiMscbkZzh25SQmfRtCT5ocUloQiopBcNAE-sd1p-ayUJWjhPrFoBrBLZHYxVEjY4JrWevQDj7kSeX7eJpud_VuZ77TNoIzj7d_iUuJUUlqF1ZF540igHKoVJJ6ujQLHh4ob8_izUuxX2iDq4h0VN3-uer59GsWw6OHgkOt85TsjMwYbeN9iw_7cNfLEYpSiH-sVHBCyKYQw7f8bKaChLxDRhUUTIEUUjGT9Ub_A3gOXq9TIi8BmbzrzVKQ",
    "e": "AQAB"
}

key = jwk.construct(rsa_key)

message, encoded_sig = token.rsplit('.', 1)
decoded_sig = base64url_decode(encoded_sig + '=' * (4 - len(encoded_sig) % 4)) # looks weird, but without added padding I got errors
res = key.verify(bytes(message, "UTF-8"), decoded_sig)
# jwt.decode(token=token, key=key.to_pem().decode(), algorithms= 'RS256') # with PEM key
payload = jwt.decode(token=token, rsa_key, algorithms= 'RS256') # with JWK
print(res)
print(payload)

The result will be:

True {'sub': '1234567890', 'name': 'John Doe', 'admin': True, 'iat': 1516239022}

which means the token could be verified with that key.

Oboe answered 27/1, 2021 at 14:3 Comment(7)
Thanks! Can you explain please why a right key (key.to_pem()) returns TypeError: a bytes-like object is required, not 'str' from jose import jwt token: https://mcmap.net/q/1175495/-python-decode-jwt-token-using-jose-module/14190526 (too long to past into a comment) jwt.decode(token=text, key=key.to_pem(), algorithms=algorithms)Flatt
see my edited answer: with key=key.to_pem().decode() the error is gone.Oboe
Yeah, but another error occurs: jose.exceptions.JWTClaimsError: Invalid audience. I have the audience in credentials but don't know how to pass itFlatt
you can set a parameter like this : audience = allowed_aud,. See also #62822813Oboe
just now I checked it and it's working, it's also requiring an access_token for some reason, but I have it in credentials. Some peoples (like I'm) don't vote for their own question because they are not experts and it may lead to confusion because other peoples will think that question has upvoted by experts. Now my question is completely solved, thank u. BTW did you know how preferable to store public keys locally or check online? If locally: is these keys are equivalent or it will be every time signed with another key and therefore I will need to iterate to get out a current key?Flatt
you can cache the key locally and if it fails (or the kid doesn't match), fetch again from the certificate endpoint. I think they change the key frequently, but not so often. Regarding voting, it merely tells the answerer and other people that you (or just someone) found it usefull. On some questions with many answers you see the difference, but afterall you never know who voted and whyOboe
A little note about padding from another question: "and not coincidentally OAuth is specified to use JWS/JWT which is specified to use the base64url variant from rfc4648 which has exactly those alphabet differences, and no padding -- but 0x010001 doesn't need padding. " source: crypto.stackexchange.com/q/87820/86538Flatt

© 2022 - 2024 — McMap. All rights reserved.