Aus aktuellem Anlass tragen derzeit viele Menschen ein digitales Impfzertifikat in Form eines QR-Codes mit sich herum. Anscheinend steht da nur irgendwelcher binärer Müll drin. Das macht neugierig, also mal genauer hingeschaut.

Noch eine kurze Anmerkung zum Start: Aus Datenschutzgründen und weil es teils nichts zur Sache tut kürze ich einige der Ausgaben bzw. ersetzte Zeichen durch x. Dies tut der eigentlichen Erklärung allerdings keinen Abbruch.

Mit einem QR Code Reader der Wahl also mal eben so ein digitales Zertifikat eingelesen. Dabei kommt etwas heraus in dieser Form:

HC1:6BFOXN*TS0BI$ZDFRH%YJLABRKAIPH769V0M3XHP+56R5%KP-0BA4DEH9...

Ok, das ist zumindest im ersten Anlauf noch nichts was direkt lesbar wäre. Doch Moment, am Anfang steht „HC1:“. HC steht hierbei für „Health Care“. Das soll an der Stelle für den Moment reichen. Ich streiche also die ersten 4 Zeichen aus dem String heraus. Über bleibt somit:

6BFOXN*TS0BI$ZDFRH%YJLABRKAIPH769V0M3XHP+56R5%KP-0BA4DEH9...

Hm. Wirklich gut ist was anderes. Doch noch mal rasch darüber nachgedacht und genauer hingeschaut: Für binär sind da etwas zu wenig verschiedene Zeichen drin. Nochmals rasch genauer hingeschaut: Passt, sind 45 verschiedene. Nämlich diese hier:

0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:

Und? Klingelt es bereits? Ja, das kennt man: Wenn man binäre Daten umwandelt in weniger ASCII-Zeichen, dann spricht man von base. Die bekannteste dürfte sicherlich die in Emails gebräuchliche base-64 Variante sein. Das geht allerdings auch wie oben gezeigt als base-45. Aber warum jetzt ausgerechnet base-45?

Auch diese Antwort ist ziemlich einfach: Ein digitales Impfzertifikat. Also digital signierte Daten. Diese sind nun einmal binär und sollen in einen QR-Code gepackt werden. Dafür ist dieser aber nur bedingt geeignet. Und genau hier tritt base-45 auf die Bühne als effektivere Methode binäre Daten in QRs zu packen als z.B. via base-64. Details gefällig? Gibt es hier: https://datatracker.ietf.org/doc/draft-faltstrom-base45/08/. Zitat gefällig? Bitte schön:

A 45-character subset of US-ASCII is used; the 45 characters usable in a QR code in Alphanumeric mode. Base45 encodes 2 bytes in 3 characters, compared to Base64, which encodes 3 bytes in 4 characters.

Mal eben ein paar Tests gemacht: Binäre Daten nach base-45 umgewandelt sind in etwa 17% kleiner als base-64. Das spart also Platz und macht den resultierenden QR-Code kleiner. Ok, diese Untersuchung ist jetzt alles andere als wissenschaftlich. Diese Nachricht sollte dennoch angekommen sein: Für QR-Codes ist base-45 besser da „kleiner“.

Zurück zum eigentlichen Thema: Den String also rasch base-45 dekodiert ergibt folgenden String:

x���⼐Qm!�G�kX�R���HF�%�I.�,R�...

Das sind jetzt wirklich binäre Daten. Doch halt, auch wenn die Darstellung hier im Web nicht ganz richtig ist, da steckt doch die Magic Number 78 drin. Eine kurze Prüfung unter Linux mit file bestätigt dies:

$ file 3
3: zlib compressed data

Infos zu den Datei Signaturen? Gibt es unter anderem hier: https://en.wikipedia.org/wiki/List_of_file_signatures.

Also der nächste Schritt: Einmal zlib entpacken. Nun sieht das Ergebnis so aus:

҄C�&�H^EVf�xWY
�bDEc���a�u'9��av��bcix0URN:UVCI:01DE/A74002480/1LMGF1K3XTW0YJGQ7WKENY#7bcobDEbdnbdtj2021-12-29bistRobert Koch-InstitutbmamORG-100031184bmp...

Ok, immer noch Teile binär. Dafür aber schon die ersten Textfragmente lesbar. Es wird also. Dieses Format hier heißt CBOR.

   The Concise Binary Object Representation (CBOR) is a data format
   whose design goals include the possibility of extremely small code
   size, fairly small message size, and extensibility without the need
   for version negotiation.

Aha. Nochmal ein kleineres Nachrichtenformat. Details mal wieder im RFC: https://datatracker.ietf.org/doc/html/rfc8949. Fertig gelesen? Dann geht es hier weiter: https://datatracker.ietf.org/doc/html/rfc8152. Das beschreibt COSE, ein Format mit dem man CBOR digital signieren kann. Das noch rasch dekodiert und schon hat man den finale JSON-String in hübsch und lesbar:

{
  "1": "DE",
  "4": "xxxxxxxxx",
  "6": "xxxxxxxxx",
  "-260": {
    "1": {
      "v": [
        {
          "ci": "URN:UVCI:01DE/xxxxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxx",
          "co": "DE",
          "dn": 2,
          "dt": "2021-xx-xx",
          "is": "Robert Koch-Institut",
          "ma": "ORG-1000xxxxx",
          "mp": "EU/x/xx/xxxx",
          "sd": 2,
          "tg": "8405xxxxx",
          "vp": "1119xxxxx"
        }
      ],
      "dob": "xxxx-xx-xx",
      "nam": {
        "fn": "Schoch",
        "gn": "Steffen",
        "fnt": "SCHOCH",
        "gnt": "STEFFEN"
      },
      "ver": "1.3.0"
    }
  }
}

Ok, mit ein bisschen Erfahrung und dem ein oder anderen Format welches man schon gesehen hat kommt man doch ordentlich weit. Das wäre allerdings auch anders gegangen: Einmal die Suchmaschine der Wahl bedient und man hätte das hier gefunden: https://ec.europa.eu/health/sites/default/files/ehealth/docs/digital-green-certificates_v3_en.pdf. Mystisch und geheimnisvoll ist hier nicht, ist sogar ordentlich dokumentiert. Von wegen nur binärer Kauderwelsch 😉