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.
❤️
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..] | |
| } |