diff --git a/decode_commonpass.py b/decode_commonpass.py new file mode 100644 index 0000000..0d6f6ed --- /dev/null +++ b/decode_commonpass.py @@ -0,0 +1,20 @@ +import json +import argparse +import base64 +import utils + +def main(): + parser = argparse.ArgumentParser(description='Decodes a CommonPass') + parser.add_argument('input', help='Input CommonPass URL') + args = parser.parse_args() + + numeric_payload = args.input.split('#')[1] + + input_jwt = utils.decode_from_numeric(numeric_payload) + + payload_dict = utils.decode_vc(input_jwt, verify=False) + + print(json.dumps(payload_dict, indent=4)) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/encode_commonpass_in_qr_code.py b/encode_commonpass_in_qr_code.py new file mode 100644 index 0000000..4717fce --- /dev/null +++ b/encode_commonpass_in_qr_code.py @@ -0,0 +1,40 @@ +import argparse +import json +import time +import secrets +import utils + + +def main(): + + parser = argparse.ArgumentParser(description='Encodes a vc') + parser.add_argument('private_keyset_file', help='Private keyset file') + parser.add_argument('issuer', help='Issuer') + parser.add_argument('url', help='URL') + parser.add_argument('input_file', help='Sample VC fixture file') + parser.add_argument('output_file', help='Output file') + + args = parser.parse_args() + (kid, private_signing_key) = utils.load_private_key_from_file( + args.private_keyset_file, + 'sig', + 'ES256' + ) + + with open(args.input_file, 'r') as input_file: + payload = json.load(input_file) + + ##since we're using a static file to form the payload + ## it needs to be modified a bit + now = int(time.time()) + payload['iss'] = args.issuer + payload['iat'] = now + vc_jws = utils.encode_vc(payload, private_signing_key, kid) + + numeric_encoded_payload = utils.encode_to_numeric(vc_jws) + qr_img = utils.create_cp_qr_code(args.url, numeric_encoded_payload) + with open(args.output_file, 'wb') as outfile: + qr_img.save(outfile) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/encode_resource_file_in_qr_code.py b/encode_resource_file_in_qr_code.py index 2d75979..038d122 100644 --- a/encode_resource_file_in_qr_code.py +++ b/encode_resource_file_in_qr_code.py @@ -16,7 +16,7 @@ def main(): fhir_backed_vc = json.load(input_file).get('verifiableCredential')[0] numeric_encoded_payload = utils.encode_to_numeric(fhir_backed_vc) - qr_img = utils.create_qr_code(numeric_encoded_payload) + qr_img = utils.create_shc_qr_code(numeric_encoded_payload) with open(args.output_file, 'wb') as outfile: qr_img.save(outfile) diff --git a/encode_resource_in_qr_code.py b/encode_resource_in_qr_code.py index 87faa73..251af8b 100644 --- a/encode_resource_in_qr_code.py +++ b/encode_resource_in_qr_code.py @@ -31,7 +31,7 @@ def main(): vc_jws = utils.encode_vc(payload, private_signing_key, kid) numeric_encoded_payload = utils.encode_to_numeric(vc_jws) - qr_img = utils.create_qr_code(numeric_encoded_payload) + qr_img = utils.create_shc_qr_code(numeric_encoded_payload) with open(args.output_file, 'wb') as outfile: qr_img.save(outfile) diff --git a/utils.py b/utils.py index 971151f..3210590 100644 --- a/utils.py +++ b/utils.py @@ -130,9 +130,15 @@ def _decode_vc(jws_raw, key_resolver): payload = json.loads(inflate(verified_jws)) return payload -def decode_vc(jws_raw): - resolver = resolve_key_from_issuer() - return _decode_vc(jws_raw, resolver) +def decode_vc(jws_raw, verify=True): + if verify: + resolver = resolve_key_from_issuer() + return _decode_vc(jws_raw, resolver) + else: + verified_jws = jws.verify(jws_raw, "", algorithms='None', verify=False) + payload = json.loads(inflate(verified_jws)) + return payload + def decode_vc_from_local_issuer(jws_raw, jwks_file): resolver = resolve_key_from_file(jwks_file) @@ -153,8 +159,51 @@ def encode_char_to_numeric(ch): def encode_to_numeric(payload): return ''.join([encode_char_to_numeric(ch) for ch in payload]) -def create_qr_code(numeric_encoded_payload): - qr = qrcode.QRCode() - qr.add_data(SMART_HEALTH_CARD_PREFIX) - qr.add_data(numeric_encoded_payload) +def decode_from_numeric(numeric): + if len(numeric) % 2 != 0: + raise Exception("uneven string") + + pair_count = int(len(numeric) / 2) + chars = [] + for i in range(pair_count): + + offset = i * 2 + pair = numeric[offset:offset+2] + + try: + int_value = int(pair) + except BaseException as e: + print(i) + print(pair) + raise e + + # print(int_value) + ch = chr(int_value + SMALLEST_B64_CHAR_CODE) + # print(ch) + chars.append(ch) + + return ''.join(chars) + + +def create_shc_qr_code(numeric_encoded_payload): + qr = qrcode.QRCode( + error_correction=qrcode.constants.ERROR_CORRECT_L + ) + qr.add_data(SMART_HEALTH_CARD_PREFIX, optimize=0) + qr.add_data(numeric_encoded_payload, optimize=0) + version = qr.best_fit() + print(f'The QR Version is {version}') + return qr.make_image(fill_color="black", back_color="white") + +def create_cp_qr_code(url, numeric_encoded_payload): + print(numeric_encoded_payload) + qr = qrcode.QRCode( + error_correction=qrcode.constants.ERROR_CORRECT_L + ) + qr.add_data(url.upper()) + qr.add_data('#') + qr.add_data(numeric_encoded_payload, optimize=0) + version = qr.best_fit() + print(f'The QR Version is {version}') + # qr.make(fit=False) return qr.make_image(fill_color="black", back_color="white")