If you receive a vaccine shot against the coronavirus within the EU, you might get a digital certificate in the form of a QR code to prove your vaccination status. The QR code can be verified with specialized apps, like the CovPass Check app.

If you are like me, you want to decode the QR code yourself and know what information is stored. The technical details are published on the webpage of the European Commission. Let’s assume you have a cropped photo of your QR code and have installed the following python packages.

$ pip install cbor2 cose qrtools base45

Decoding steps

To show the information, we need to perform the following steps:

  • First, we need to parse the QR code image (qrtools).
  • The text of the QR code contains a human-readable version identifier, usually, HC1 followed by a colon. To proceed, we chop off this part.
  • The actual binary data is base45 encoded and needs to be decoded.
  • The COSE message itself is ZLib compressed and needs to be decompressed before we can,
  • Finally, parse the COSE message and its payload.

Demo script

The following script illustrates the decoding procedure.

FILE_PATH = "photo_of_the_qr_code.jpg"

from argparse import ArgumentParser
from zlib import decompress
from qrtools import QR
from base45 import b45decode
from cose.messages import CoseMessage
from cbor2 import loads
import json

# Parse the QR code photo
qr = QR()
qr.decode(FILE_PATH)
qr_data = qr.data.encode()

# Remove version
version = qr_data[:3]
print("Version:", version)
raw = qr_data[4:]

# Decode Base 45
decoded = b45decode(raw)

# Decompress
decompressed = decompress(decoded)

# Unpack message
msg = CoseMessage.decode(decompressed)

# Decode payload
payload = loads(msg.payload)

# Print
print("Payload:")
print(json.dumps(payload, indent=2))

Please note that for the sake of clarity, there is no error handling the above script.