0

There is a program that decodes a text in python. I would like that same method to be used to encode the output tekst.

The code is a decoding tool. so I thought if you use the code the other way around you can encode it. But since I don't understand the code itself, I can't reverse the code. so if someone can help me flip the code so you can encode the output again it would be great.

../samples/bartwolff.txt:

NL2:B4V.W9D:LWJ5W2S6A$XQ9N* Y252O4%%  ZNK**$840VPY8T7$J0GR$8L2%VMO/20/3C.C.L XO:FN%IWW.TI+G3KW2RA+ $6T1 BQAGU6HJ35D.2YPIT*6Y3C733IOBZIKEWP4L/$9TX6QUVQFFZWJ+RY/JV6N3%NX%Y4XX43J182O/.AELM1%E-D*Q+8*O1CG*9/5ENUJ0HXT*PJXJ*XE-6QFMM7*B$IFEY04:-PN14PX3% Q5-JQF9$YJFVBSUD*P/AXHJRNUIA:SCX*SBIQ*BHZG$PJ+LG-S*:0.GZ8M4HO.XLM$BKZG7H/BVRUW$7WH$B3$L-T58KK$20EDRZW1B*VJ1Q5VC:X/.5*OQJ/EA92-8J*-QL6J+3NX:C5%%XZ4LLIS31KKPA9:1FP++KT:.QFRZ%M5R$I2*DM36M%BW/3.LS9MX6YE8KU4S-.Q%W2ZCI7CQ79E/X342+5T3ODK8X.-F02J-GMF18KCE.5NDV2V8I/5L0GVNPQRF+T3A*$%HI3-$R3+*RO/X8N.RG7LBFJP5SO9QAD:KYRP978DTHFL39368JXWSO2CKLQTYDZ45CF0FE9J3$$6+ZX RSNRQ6+HV%DE$V:O/Q8FYO+.NZFL6R8R8UE.0:A*Q9$8HYB+WZ26UM%.4R4 25AA7XQW.NYAJCO6+-C QZEPKLYS6G0Z/YGHPR*+YKEDO*3LE:KP HT3NCJPRNRG9K0Y84*C-7N2-BQJXY/+D-VF IIQTJ6-AV83%1Y8JMXN1I6/JSHS+HEG+VU+8UX:LL*Y%B*$G$D4H9HZVMHKWT2-87UTR+EZIWJ*IOTQ70.V%CLHVY  2-HFW4BA6-+FWIW6C:WDS /FU2I9G$LXL$B/MY*WQYMN*R00IQZJJ- 6QFX*$%-9ZGS3%G

the output is:

Version and public cert for verification:
[b'\x02', 'VWS-CC-1']

QR data
{
    "isSpecimen": "1",
    "isPaperProof": "1",
    "validFrom": "1627466400",
    "validForHours": "25",
    "firstNameInitial": "B",
    "lastNameInitial": "B",
    "birthDay": "31",
    "birthMonth": "7"
}

source code:

import asn1
import base45
import sys
from typing import List, Dict, Optional
from var_dump import var_dump
import json

# Thanks to the great work of Bart Wollf


def asn1decode(d: asn1.Decoder):
    res = []
    while not d.eof():
        tag = d.peek()
        if tag.typ == asn1.Types.Primitive:
            tag, value = d.read()
            res.append(value)
        elif tag.typ == asn1.Types.Constructed:
            d.enter()
            res.append(asn1decode(d))
            d.leave()
    return res

class NLDomesticCovidCertSerialization:
    DisclosureTimeSeconds: int
    C: int
    A: int
    EResponse: int
    VResponse: int
    AResponse: int
    ADisclosed: List[int]

    def __init__(self, data: List):
        self.DisclosureTimeSeconds = data[0]
        self.C = data[1]
        self.A = data[2]
        self.EResponse = data[3]
        self.VResponse = data[4]
        self.AResponse = data[5]
        self.ADisclosed = data[6]

    def decode_metadata(self) -> List:
        b = NLDomesticCovidCertSerialization.decode_int(self.ADisclosed[0])
        d = asn1.Decoder()
        d.start(b)
        return asn1decode(d)[0]

    def decode_attributes(self) -> Dict[str, str]:
        res = {}
        attrs = ['isSpecimen',
            'isPaperProof',
            'validFrom',
            'validForHours',
            'firstNameInitial',
            'lastNameInitial',
            'birthDay',
            'birthMonth']
        for i, x in enumerate(self.ADisclosed[1:]):
            res[attrs[i]] = NLDomesticCovidCertSerialization.decode_int(x).decode('utf-8')
        return res

    @staticmethod
    def decode_int(value: int) -> Optional[bytes]:
        if not value & 1:
            return None
        else:
            v = value >> 1
            return v.to_bytes((v.bit_length() + 7) // 8, byteorder='big')

def main():
    with open("../samples/bartwolff.txt") as handle:
        s = handle.readline().rstrip()

    b45data = s[4:]
    asn1data = base45.b58decode(b45data)

    decoder = asn1.Decoder()
    decoder.start(asn1data)

    obj = asn1decode(decoder)[0]

    annotator = NLDomesticCovidCertSerialization(obj)
    print("Version and public cert for verification:")
    print(annotator.decode_metadata())

    print("\nQR data")
    print(json.dumps(annotator.decode_attributes(), indent=4))

if __name__ == '__main__':
    main()
  • 4
    Encryption != Encoding – h0r53 Nov 15 '21 at 15:56
  • This decoding algorithm has two parts. 1) Base58 decode the raw data, 2) De-Serialize the data. Thus, the encoder would be the other direction. 1) Serialize your data, 2) Base58 encode the serialized data. – h0r53 Nov 15 '21 at 15:59
  • so if i am corret it is a decoder that has 2 parts of decodeing right? – MitchGamesNL Nov 15 '21 at 16:07
  • Correct, there is a Base58 Decoding that occurs, followed by asn1decode. Both of those encoding/decoding schemes are well known / defined, so you should have no issue reproducing them. The serialization piece is slightly more complex, because it's a custom algorithm, but it looks like the main idea happens in `decode_int`, which requires the least significant bit to be `1`, if so that bit is shifted off, and the result is interpreted as a Big Endian Int. – h0r53 Nov 15 '21 at 16:14
  • ther is also i blog page that has more information about the decoding prosecc. # See his blog post: # https://www.bartwolff.com/Blog/2021/08/21/decoding-the-dutch-domestic-coronacheck-qr-code that was also in the code but i removed it. – MitchGamesNL Nov 15 '21 at 17:45
  • is there a way to split the parts up so decode part 1 en part 2. or is there a way to view the procces with like a console log or somthing – MitchGamesNL Nov 16 '21 at 15:00

1 Answers1

0

I was also looking into the decode thing. In a file of them I saw asn1.Unmarshal which came after a base45.Base45Decode(https://github.com/minvws/nl-covid19-coronacheck-idemix/blob/main/verifier/verifier.go). You are doing a base45.b58decode and then a asn1.decoder, can't imagine they are the same?

Remco
  • 41
  • 1
  • 5