Skip to content

Instantly share code, notes, and snippets.

@lmammino
Last active February 22, 2022 19:37
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lmammino/45ef563744cee5ecdc49fc6b19554146 to your computer and use it in GitHub Desktop.
Save lmammino/45ef563744cee5ecdc49fc6b19554146 to your computer and use it in GitHub Desktop.
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