Forked from yaci/eu-covid-certificate-qr-decoder.py
Created
November 4, 2021 01:36
-
-
Save miklobit/8351ed4cc7a67ec63635a74618770644 to your computer and use it in GitHub Desktop.
Decode information from European covid19 travel certificates
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
####### | |
# | |
# REQUIRES: pip install cose #!!!! | |
# | |
# HOW TO USE: | |
# 1. Use your favourite QR scanner to scan the code from a certificate, | |
# you'll get a string that starts with "HC1:" | |
# 2. Run the script: python3 covid-qr-certificate-decoder.py | |
# 3. Paste the string when prompted | |
# | |
# | |
# READING (how to interpret the output and test data): | |
# api spec: https://github.com/eu-digital-green-certificates/dgca-issuance-web/blob/main/src/generated-files/dgc-combined-schema.d.ts | |
# https://github.com/eu-digital-green-certificates/dgca-issuance-web/blob/main/src/misc/edgcProcessor.tsx | |
# https://github.com/admin-ch/CovidCertificate-Examples | |
# https://github.com/eu-digital-green-certificates/dgc-testdata/tree/main/PL | |
# | |
####### | |
from typing import Union | |
import zlib | |
from cose.messages import CoseMessage | |
import cbor2 | |
import pprint | |
import json | |
# example code for testing | |
# QRCODE = 'HC1:6BFC80Z80T9WTWGVLK659A:TG4G$BTZM0X*4FBBE*3FN0KKC+H3WY0/9CWC4*70 6AD97TK0F90KECTHGXJC$+D.JCBECB1A-:8$966469L6OF6VX6Z/ER2DD46JH8946XJCCWENF6OF63W5NW60A6WJCT3E 6AWJC0FDTA6AIA%G7X+AQB9746XG7TS9 967:6DL6WX8BM8CA6DB83R63X6$A7UF6QG8Q46/A8.A8$96V47.JCP9EJY8L/5M/5 96.96WF6%JCXQEIN8G/D6LE ZDQZCAJB0LEE4F0ECKQEPD09WEQDD+Q6TW6FA7C46TPCBEC8ZKW.CHWEBIAG09:S9Q+9DN90S7BIAOT9W.CUEEY3EAECWGDMXG2QDUW5*MEWUMMPCG/D8EDETAG+9*NAWB8 JC6/DYOACEC+EDR/OLEC$PC5$CUZCY$5Y$5JPCT3E5JDKA7Q47%964W5WA6N68$E5FAWIBG9SQCLEH19FZMD8B TL6AW8JJRBHTB91L0GMSNRCBBPL8R958CR2:7T84H7*6C V86W0*8G1MZJVS72L:M5WAB9UB0HF0' | |
# credits: https://github.com/kirei/python-base45/blob/main/base45/__init__.py | |
def b45decode(s: Union[bytes, str]) -> bytes: | |
"""Decode base45-encoded string to bytes""" | |
BASE45_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:" | |
res = [] | |
try: | |
if isinstance(s, str): | |
buf = [BASE45_CHARSET.index(c) for c in s] | |
else: | |
buf = [BASE45_CHARSET.index(c) for c in s.decode()] | |
buflen = len(buf) | |
for i in range(0, buflen, 3): | |
x = buf[i] + buf[i + 1] * 45 | |
if buflen - i >= 3: | |
x = buf[i] + buf[i + 1] * 45 + buf[i + 2] * 45 * 45 | |
res.extend(list(divmod(x, 256))) | |
else: | |
res.append(x) | |
return bytes(res) | |
except (ValueError, IndexError, AttributeError): | |
raise ValueError("Invalid base45 string") | |
def main() -> None: | |
data = input("Paste the decoded QR code string and press Enter:\n") | |
if data.startswith('HC1:'): data = data[4:] | |
decoded = b45decode(data) | |
decompressed = zlib.decompress(decoded); | |
msg = CoseMessage.decode(decompressed); | |
phdr, uhdr = msg._hdr_repr() | |
payload = cbor2.loads(msg.payload) | |
#payload is the most interesting part, the others are rather boring | |
print("\n") | |
print("==PHDR==\n") | |
pprint.pprint(phdr) | |
print("==UHDR==\n") | |
pprint.pprint(uhdr) | |
#print("==SIGNATURE==\n",msg.signature,"\n") | |
print("==PAYLOAD==") | |
print(json.dumps(payload, ensure_ascii=False, indent=4)) | |
print("\n") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment