Skip to content

Instantly share code, notes, and snippets.

@lmammino
Last active Feb 22, 2022
Embed
What would you like to do?
Decode an EU DGC (greenpass) in Rust

This code was presented as part of the talk "A look inside the European Covid Green Certificate" at Codemotion 2021.

You can find all the slides at loige.link/green.

❤️

[package]
name = "dgc-decode"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
base45 = "3.0.0"
ciborium = "0.2.0"
inflate = "0.4.5"
serde_json = "1.0.71"
use ciborium::{de::from_reader, value::Value};
use serde_json::to_string_pretty;
fn main() {
let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4.P7*ZOP-IMJTI94F/8X*G3M9JUPY0BZW4Z*AK.GNNVR*G0C7PHBO335KN/NBEDBVBJ623323EAJ7UJ5PNDIB6PNS7B1DN%BBWC7WC7GB3683ML7SZ4ZI00T9UKPSH9WC5PF6846A$Q 76QW6A/98T5WBI$E9$UPV3Q.GUQ$9WC5R7ACB97C968ELZ5$DP6PP5IL*PP:+P*.1D9R8Q02-DE%QHOJ+PB/VSQOL9DLKWCZ3EBKDYGIZ J$XI4OIMEDTJCJKDLEDL9CZTAKBI/8D:8DKTDL+SQ05.$S6ZC0JBY63-C3F+LBQ99Q9E$BDZIA9JJ-JS7BYZJ92KG0TB9FNDA5KD9FED.B4JB3E9B9NNPCV9E6LFSD9C8J-QDSWNG4C-TLNKE$JDVPLW1KD0KCZGBKQCJE%RH5WAMSSR$F-75NXONQ84QV9/7/-LT1AIYBZGD$9RCLV-PTZ-K63ET-D1757H3GF9MV2N7WNQSY1SBZT-:81JJLHFQ-VG$HK00XWPD2";
let no_prefix = remove_prefix(cert_data);
let decoded = decode_base45(no_prefix);
let decompressed = decompress(decoded);
let cwt_payload = get_cwt_payload(decompressed);
let parsed_payload = parse_cwt_payload(cwt_payload);
println!("{}", to_string_pretty(&parsed_payload).unwrap());
}
fn parse_cwt_payload(data: Vec<u8>) -> Value {
from_reader(data.as_slice()).unwrap()
}
fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> {
let parsed: Value = from_reader(data.as_slice()).unwrap();
let (tag, arr) = parsed.as_tag().unwrap();
assert_eq!(tag, 18);
let arr = arr.as_array().unwrap();
let payload = arr[2].as_bytes().unwrap();
payload.clone()
}
fn decompress(data: Vec<u8>) -> Vec<u8> {
inflate::inflate_bytes_zlib(data.as_slice()).unwrap() // IRL use a Result!
}
fn decode_base45(data: &str) -> Vec<u8> {
base45::decode(data).unwrap() // IRL use a Result!
}
fn remove_prefix(data: &str) -> &str {
if data.len() < 4 || !&data.starts_with("HC1:") {
panic!("Invalid prefix"); // IRL use a Result!
}
&data[4..]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment