Skip to content

Commit 4c97264

Browse files
committed
implement keyconv
1 parent 8863cfb commit 4c97264

File tree

1 file changed

+151
-0
lines changed

1 file changed

+151
-0
lines changed

src/cryptojwt/tools/keyconv.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#!/usr/bin/env python3
2+
3+
"""Convert symmetric JWK from/to binary format"""
4+
5+
import argparse
6+
import json
7+
from binascii import hexlify
8+
from getpass import getpass
9+
10+
from cryptography.hazmat.primitives import serialization
11+
from cryptojwt.jwk import JWK
12+
from cryptojwt.jwk.ec import (ECKey, import_private_key_from_file,
13+
import_public_key_from_file)
14+
from cryptojwt.jwk.rsa import (RSAKey, import_private_rsa_key_from_file,
15+
import_public_rsa_key_from_file)
16+
from cryptojwt.jwx import key_from_jwk_dict
17+
18+
19+
def jwk_from_file(filename: str, private: bool = True) -> JWK:
20+
"""Read JWK from file"""
21+
with open(filename, mode='rt') as input_file:
22+
jwk_dict = json.loads(input_file.read())
23+
return key_from_jwk_dict(jwk_dict, private=private)
24+
25+
26+
def pem2rsa(filename: str, kid: str = None, private: bool = False, passphrase: str = None) -> JWK:
27+
"""Convert RSA key from PEM to JWK"""
28+
if private:
29+
key = import_private_rsa_key_from_file(filename, passphrase)
30+
else:
31+
key = import_public_rsa_key_from_file(filename)
32+
jwk = RSAKey(kid=kid)
33+
jwk.load_key(key)
34+
return jwk
35+
36+
37+
def pem2ec(filename: str, kid: str = None, private: bool = False, passphrase: str = None) -> JWK:
38+
"""Convert EC key from PEM to JWK"""
39+
if private:
40+
key = import_private_key_from_file(filename, passphrase)
41+
else:
42+
key = import_public_key_from_file(filename)
43+
jwk = ECKey(kid=kid)
44+
jwk.load_key(key)
45+
return jwk
46+
47+
48+
def jwk2bin(jwk: JWK) -> bytes:
49+
"""Convert symmetric key from JWK to binary"""
50+
return jwk.key
51+
52+
53+
def pem2jwk(filename: str, kid: str, private: bool = False) -> bytes:
54+
55+
with open(filename, 'rt') as file:
56+
content = file.readlines()
57+
header = content[0]
58+
59+
if private:
60+
passphrase = getpass('Private key passphrase: ')
61+
if len(passphrase) == 0:
62+
passphrase = None
63+
else:
64+
passphrase = None
65+
66+
if 'BEGIN EC PRIVATE KEY' in header:
67+
jwk = pem2ec(filename, kid, private=True, passphrase=passphrase)
68+
elif 'BEGIN EC PUBLIC KEY' in header:
69+
jwk = pem2ec(filename, kid, private=False)
70+
elif 'BEGIN RSA PRIVATE KEY' in header:
71+
jwk = pem2rsa(filename, kid, private=True, passphrase=passphrase)
72+
elif 'BEGIN RSA PUBLIC KEY' in header:
73+
jwk = pem2rsa(filename, kid, private=False)
74+
else:
75+
raise ValueError("Unknown PEM format")
76+
77+
return jwk
78+
79+
80+
def jwk2pem(jwk: JWK, private: bool = False) -> bytes:
81+
"""Convert asymmetric key from JWK to PEM"""
82+
83+
if private:
84+
passphrase = getpass('Private key passphrase: ')
85+
if passphrase:
86+
enc = serialization.BestAvailableEncryption(passphrase.encode())
87+
else:
88+
enc = serialization.NoEncryption
89+
serialized = jwk.priv_key.private_bytes(
90+
encoding=serialization.Encoding.PEM,
91+
format=serialization.PrivateFormat.PKCS8,
92+
encryption_algorithm=enc)
93+
else:
94+
serialized = jwk.pub_key.public_bytes(
95+
encoding=serialization.Encoding.PEM,
96+
format=serialization.PublicFormat.SubjectPublicKeyInfo)
97+
98+
return serialized
99+
100+
101+
def main():
102+
""" Main function"""
103+
parser = argparse.ArgumentParser(description='JWK Key Conversion Utility')
104+
105+
parser.add_argument('--kid',
106+
dest='kid',
107+
metavar='key_id',
108+
help='Key ID')
109+
parser.add_argument('--private',
110+
dest='private',
111+
action='store_true',
112+
help="Output private key")
113+
parser.add_argument('--output',
114+
dest='output',
115+
metavar='filename',
116+
help='Output file name')
117+
parser.add_argument('filename', metavar='filename', nargs=1, help='filename')
118+
args = parser.parse_args()
119+
120+
f = args.filename[0]
121+
122+
if f.endswith('.json'):
123+
jwk = jwk_from_file(f, args.private)
124+
if jwk.kty == 'oct':
125+
serialized = jwk2bin(jwk)
126+
else:
127+
serialized = jwk2pem(jwk, args.private)
128+
129+
if args.output:
130+
with open(args.output, mode='wt') as file:
131+
file.write(serialized)
132+
else:
133+
if jwk.kty == 'oct':
134+
print(hexlify(serialized).decode())
135+
else:
136+
print(serialized.decode())
137+
elif f.endswith('.pem'):
138+
jwk = pem2jwk(f, args.kid, args.private)
139+
serialized = jwk.serialize(private=args.private)
140+
141+
if args.output:
142+
with open(args.output, mode='wt') as file:
143+
file.write(json.dumps(serialized))
144+
else:
145+
print(serialized)
146+
else:
147+
exit(-1)
148+
149+
150+
if __name__ == "__main__":
151+
main()

0 commit comments

Comments
 (0)