summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Dauvergne <bdauvergne@entrouvert.com>2022-06-07 15:20:13 (GMT)
committerBenjamin Dauvergne <bdauvergne@entrouvert.com>2022-06-08 04:36:27 (GMT)
commit95398b71b1fcb86c7840717dae0ba95d050e10f4 (patch)
tree207d6da3c2590d7de8300292e46c37a835fc24f3
parent362d6321eff5006b174f65b290502b6560d160b2 (diff)
downloadmisc-bdauvergne-master.zip
misc-bdauvergne-master.tar.gz
misc-bdauvergne-master.tar.bz2
qrcode_certificate: prototypeHEADmaster
-rw-r--r--qrcode-certificate/v0/certificate.pngbin0 -> 1829 bytes
-rw-r--r--qrcode-certificate/v0/check_qrcode_certificate.py24
-rw-r--r--qrcode-certificate/v0/make_qrcode_certificate.py49
-rw-r--r--qrcode-certificate/v0/qrcode-reader/index.html89
4 files changed, 162 insertions, 0 deletions
diff --git a/qrcode-certificate/v0/certificate.png b/qrcode-certificate/v0/certificate.png
new file mode 100644
index 0000000..5180720
--- /dev/null
+++ b/qrcode-certificate/v0/certificate.png
Binary files differ
diff --git a/qrcode-certificate/v0/check_qrcode_certificate.py b/qrcode-certificate/v0/check_qrcode_certificate.py
new file mode 100644
index 0000000..571b513
--- /dev/null
+++ b/qrcode-certificate/v0/check_qrcode_certificate.py
@@ -0,0 +1,24 @@
+import base64
+import binascii
+
+import nacl.signing
+
+
+def base64url_decode(raw):
+ rem = len(raw) % 4
+ if rem > 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 @@
+<html>
+ <head>
+ <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/js-nacl/1.4.0/nacl_factory.min.js"></script>
+ <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Base64/1.1.0/base64.min.js"></script>
+ <script type="text/javascript" src="https://unpkg.com/html5-qrcode"></script>
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
+ </head>
+ <body>
+ <div class="container">
+ <label>SCAN QR CODE</label>
+ <div id="reader" style="width: 70vmin"></div>
+ <label>RESULT</label>
+ <pre id="text" style="font-size: 2rem; white-space: pre-wrap;"></pre>
+ </div>
+ </div>
+
+ <script>
+ var base64url_to_base64 = function(input) {
+ // Replace non-url compatible chars with base64 standard chars
+ input = input
+ .replace(/-/g, '+')
+ .replace(/_/g, '/');
+
+ // Pad out with standard base64 required padding characters
+ var pad = input.length % 4;
+ if(pad) {
+ if(pad === 1) {
+ throw new Error('InvalidLengthError: Input base64url string is the wrong length to determine padding');
+ }
+ input += new Array(5-pad).join('=');
+ }
+
+ return input;
+ }
+ function b64urldecode(base64url) {
+ var binary_string = window.atob(base64url_to_base64(base64url));
+ console.log('binary string', binary_string)
+ var len = binary_string.length;
+ var bytes = new Uint8Array(len);
+ for (var i = 0; i < len; i++) {
+ bytes[i] = binary_string.charCodeAt(i);
+ }
+ return bytes;
+ }
+ nacl_factory.instantiate(function (nacl) {
+ let key = '79a441b73a99ead8c4446aa36c973dd23787d459122fe2169232a07a181e37a9';
+ let uint8_key = nacl.from_hex(key);
+
+ function onScanSuccess(c, decodedResult) {
+ // handle the scanned code as you like, for example:
+ let pre = document.getElementById('text');
+ pre.textContent = 'Decoding "' + c + '"\n';
+ console.log('1');
+ let parts = c.split('.');
+ console.log('2');
+ if (parts.length != 2) {
+ pre.textContent += "ERROR wrong length";
+ return true;
+ }
+ try {
+ let b64_payload = parts[0];
+ let b64_signature = parts[1];
+ let payload = b64urldecode(b64_payload);
+ let signature = b64urldecode(b64_signature);
+ let decoder = new TextDecoder('utf-8');
+ const jsonString = decoder.decode(payload);
+ const signatureString = decoder.decode(signature);
+ const data = JSON.parse(jsonString)
+ console.log(signature);
+ console.log(nacl.to_hex(signature));
+ } catch (e) {
+ pre.textContent += 'ERROR ' + e;
+ }
+ if (! nacl.crypto_sign_verify_detached(signature, payload, uint8_key)) {
+ pre.textContent += "ERROR wrong signature";
+ return true;
+ }
+
+ pre.textContent = "signature OK\n" + JSON.stringify(data, null, " ");
+ return true;
+ }
+
+
+ let scanner = new Html5Qrcode("reader");
+ scanner.start({ facingMode: "environment" }, { fps: 10, qrbox: {width: 500, height: 500} }, onScanSuccess);
+ });
+ </script>
+ </body>
+</html>