From 629bbc155bd42a72a4a1ff0f7540efa8a37cd6fd Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Tue, 7 Jun 2022 17:20:13 +0200 Subject: [PATCH] qrcode_certificate: prototype --- qrcode-certificate/v0/certificate.png | Bin 0 -> 1829 bytes .../v0/check_qrcode_certificate.py | 24 +++++ .../v0/make_qrcode_certificate.py | 49 ++++++++++ .../v0/qrcode-reader/index.html | 89 ++++++++++++++++++ 4 files changed, 162 insertions(+) create mode 100644 qrcode-certificate/v0/certificate.png create mode 100644 qrcode-certificate/v0/check_qrcode_certificate.py create mode 100644 qrcode-certificate/v0/make_qrcode_certificate.py create mode 100644 qrcode-certificate/v0/qrcode-reader/index.html diff --git a/qrcode-certificate/v0/certificate.png b/qrcode-certificate/v0/certificate.png new file mode 100644 index 0000000000000000000000000000000000000000..518072065bec61ccf8ce430711821dc56745b9bc GIT binary patch literal 1829 zcmV+=2io|FP) zQEKEm5Jhi28}cc`EFep4!0Co|(#VJ^2ge(9= zrc>$#?B(V1*rz0t$frcks;asH^0onbNe4tG07$A>Wdx9JqVF<7F90xagX$$605GVk zs5ZawrVi6rtFkqBOMHr`aT6RnqQqnWh^U{HINw0LgG2d5*W=(!Qu z4Kk?5{`oPOW9^jjYS`J3_ki-i8k8*TlvfqN*h6Gj zNR;hSz=BA!ozWbHE&$5%<|v=oTw8kN2_It*ksTt7dP;^tSm?|fEW@BC7pNXtGbR6^ zO!F>DsU9LbLpJL1RZN)8C66vC4nbV^9R4oVLu5zDFmto1TAiS|8HX^N157<-HfM?g z*F8k`hHPVxTWecc%E0aD3*Z*DhKU?q10s7xmK;~B;-&7O93rAHo#F;84uQx4eJzVz?*&DK%mX$6A#gi^x zTK!>CJ3>k+^W2E+6&Z3v>up{96i>kogT^{2I&yE0>LIcxWSF^`7K#k+ntw!JAeAK# zYC`q~F!m7H7t&WYo=uS4u?FyQ;!ce-b#NW`J-#@RM1KAX>mGB^{PLJ$+oRsLEi80u zx(?MtWN*m0&;fw3-&4x2T|%Dc2H3mxV~(PFi0lR#Jn8D7Syqm(fNXhFKXH^^qQz+g zyCD+UFETf-9&-;w0E6ZhJL_cGZL+|mCNd4G7o1`-Y9E1lJH;Z?_xj>Q68TA_s@|kl zkJ{g^rV5eCQm$peDFEzmc3Wn6vOM-Fi6rv5kRiDsU)eR-0EC=2_^r>^054+5ALD)x zk-Z_~x~EMVuo~@DcY{n;p^vphoyEK^yR1cBeAe&CS8@v>|3Zf>17BSVn1{cI82viS|eIY+cn=U#E zJq&8YgPPdpa#8oVx$YsdL!`WIKt8L-D-Y~;J0-tb=v0+Rj(stfhDYoh-K>J5%YG6ojspJ zkqFjlu=D8G*W(`ffTtvq$Y(+}9jQWyaT9t&>;j*=hqy&uYvSs~*h6G5$Pb$6cyGhn zLDWkU)YB2Xr%r6KL-i2Z6SC<7pXy<8N9?4Nf4E4zJiE~rcT0)v4H;^xQBNkdtb;*o z?wbwX;Kkcba|2Tp)k9=|$Xo>HCL1s)*69>|f4vEiZssH`=>XR06cH&$(Z5|^^aJDr zo{~r+p9&e%rY~N>qgz|1kcY-0^%&E7(kW+dMD~SjDimtJg5)N`hO)u4)gwoacD3V& zlu$iH_JnNDEd}6}2gN_ovX_cDxr<${0mQy<-{XrDN#y6RyWN_Y^SL2T+B^!Cr4fQx zP}^ElJw$ecY~n}lDwS#psrqUMAzdd- 0: + raw += b'=' * (4 - rem) + return base64.urlsafe_b64decode(raw) + + +hex_verify_key = '79a441b73a99ead8c4446aa36c973dd23787d459122fe2169232a07a181e37a9' + +verify_key = nacl.signing.VerifyKey(binascii.unhexlify(hex_verify_key)) + +message = 'eyJ0eXBlIjogImNlcnRpZmljYXQtemZlIiwgImltbWF0cmljdWxhdGlvbiI6ICJBWi0xMjM0LUJFIiwgIm5vbSI6ICJKZWFuIE1hcmMgRHVwb25kIiwgImRhdGVfZW1pc3Npb24iOiAiMjAyMi0wNi0wNyJ9.Nno9aCyay5sxducJtpmuBDP8VBoRdwe4rfw3ohBP1bSBnmFJf17sXQdMDGDXt6eN6bzyfeI3mDrmpTnVDf81DQ' + +parts = message.encode().split(b'.') +payload = base64url_decode(parts[0]) +signature = base64url_decode(parts[1]) + +assert verify_key.verify(payload, signature) diff --git a/qrcode-certificate/v0/make_qrcode_certificate.py b/qrcode-certificate/v0/make_qrcode_certificate.py new file mode 100644 index 0000000..335a44d --- /dev/null +++ b/qrcode-certificate/v0/make_qrcode_certificate.py @@ -0,0 +1,49 @@ +import base64 +import binascii +import json + +import nacl.signing +import qrcode +import qrcode.constants +import qrcode.image.svg + + +def base64url_decode(raw): + rem = len(raw) % 4 + if rem > 0: + raw += b'=' * (4 - rem) + return base64.urlsafe_b64decode(raw) + + +def base64url_encode(raw): + return base64.urlsafe_b64encode(raw).rstrip(b'=') + + +key = nacl.signing.SigningKey(seed=b'1234' * 8) +print('Hex verify key:', binascii.hexlify(key.verify_key.encode()).decode()) +doc = { + 'type': 'certificat-zfe', + 'immatriculation': 'AZ-1234-BE', + 'nom': 'Jean Marc Dupond', + 'date_emission': '2022-06-07', +} + +payload = json.dumps(doc).encode() +signed = key.sign(payload) +certificate = b'%s.%s' % (base64url_encode(payload), base64url_encode(signed.signature)) + +# verify +b64_payload, b64_signature = certificate.split(b'.') +assert key.verify_key.verify(base64url_decode(b64_payload), base64url_decode(b64_signature)) + +print(f'Certificate({len(certificate)} bytes):', certificate) + +qr = qrcode.QRCode( + error_correction=qrcode.constants.ERROR_CORRECT_L, + # image_factory=qrcode.image.svg.SvgPathImage, +) +qr.add_data(certificate) +qr.make(fit=True) +img = qr.make_image(fill_color='black', back_color='white') +with open('certificate.png', 'wb') as fd: + img.save(fd) diff --git a/qrcode-certificate/v0/qrcode-reader/index.html b/qrcode-certificate/v0/qrcode-reader/index.html new file mode 100644 index 0000000..18069b1 --- /dev/null +++ b/qrcode-certificate/v0/qrcode-reader/index.html @@ -0,0 +1,89 @@ + + + + + + + + +
+ +
+ +

+            
+ + + + +