summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--Pipfile4
-rw-r--r--Pipfile.lock134
-rw-r--r--README.md39
-rw-r--r--verify.py91
5 files changed, 247 insertions, 27 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..70a84af
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+
+# Pycharm
+.idea/
diff --git a/Pipfile b/Pipfile
new file mode 100644
index 0000000..5300670
--- /dev/null
+++ b/Pipfile
@@ -0,0 +1,4 @@
+[packages]
+cryptography = "*"
+pillow = "*"
+pyzbar = "*"
diff --git a/Pipfile.lock b/Pipfile.lock
new file mode 100644
index 0000000..ea45a3b
--- /dev/null
+++ b/Pipfile.lock
@@ -0,0 +1,134 @@
+{
+ "_meta": {
+ "hash": {
+ "sha256": "88288ba4a29083a5f9a6ec0d894e55dc651b0227f35984fdfde3c7fa0e66f228"
+ },
+ "pipfile-spec": 6,
+ "requires": {},
+ "sources": [
+ {
+ "name": "pypi",
+ "url": "https://pypi.org/simple",
+ "verify_ssl": true
+ }
+ ]
+ },
+ "default": {
+ "cffi": {
+ "hashes": [
+ "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813",
+ "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06",
+ "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea",
+ "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee",
+ "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396",
+ "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73",
+ "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315",
+ "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1",
+ "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49",
+ "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892",
+ "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482",
+ "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058",
+ "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5",
+ "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53",
+ "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045",
+ "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3",
+ "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5",
+ "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e",
+ "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c",
+ "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369",
+ "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827",
+ "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053",
+ "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa",
+ "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4",
+ "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322",
+ "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132",
+ "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62",
+ "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa",
+ "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0",
+ "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396",
+ "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e",
+ "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991",
+ "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6",
+ "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1",
+ "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406",
+ "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d",
+ "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"
+ ],
+ "version": "==1.14.5"
+ },
+ "cryptography": {
+ "hashes": [
+ "sha256:066bc53f052dfeda2f2d7c195cf16fb3e5ff13e1b6b7415b468514b40b381a5b",
+ "sha256:0923ba600d00718d63a3976f23cab19aef10c1765038945628cd9be047ad0336",
+ "sha256:2d32223e5b0ee02943f32b19245b61a62db83a882f0e76cc564e1cec60d48f87",
+ "sha256:4169a27b818de4a1860720108b55a2801f32b6ae79e7f99c00d79f2a2822eeb7",
+ "sha256:57ad77d32917bc55299b16d3b996ffa42a1c73c6cfa829b14043c561288d2799",
+ "sha256:5ecf2bcb34d17415e89b546dbb44e73080f747e504273e4d4987630493cded1b",
+ "sha256:600cf9bfe75e96d965509a4c0b2b183f74a4fa6f5331dcb40fb7b77b7c2484df",
+ "sha256:66b57a9ca4b3221d51b237094b0303843b914b7d5afd4349970bb26518e350b0",
+ "sha256:93cfe5b7ff006de13e1e89830810ecbd014791b042cbe5eec253be11ac2b28f3",
+ "sha256:9e98b452132963678e3ac6c73f7010fe53adf72209a32854d55690acac3f6724",
+ "sha256:df186fcbf86dc1ce56305becb8434e4b6b7504bc724b71ad7a3239e0c9d14ef2",
+ "sha256:fec7fb46b10da10d9e1d078d1ff8ed9e05ae14f431fdbd11145edd0550b9a964"
+ ],
+ "index": "pypi",
+ "version": "==3.4.6"
+ },
+ "pillow": {
+ "hashes": [
+ "sha256:165c88bc9d8dba670110c689e3cc5c71dbe4bfb984ffa7cbebf1fac9554071d6",
+ "sha256:1d208e670abfeb41b6143537a681299ef86e92d2a3dac299d3cd6830d5c7bded",
+ "sha256:22d070ca2e60c99929ef274cfced04294d2368193e935c5d6febfd8b601bf865",
+ "sha256:2353834b2c49b95e1313fb34edf18fca4d57446675d05298bb694bca4b194174",
+ "sha256:39725acf2d2e9c17356e6835dccebe7a697db55f25a09207e38b835d5e1bc032",
+ "sha256:3de6b2ee4f78c6b3d89d184ade5d8fa68af0848f9b6b6da2b9ab7943ec46971a",
+ "sha256:47c0d93ee9c8b181f353dbead6530b26980fe4f5485aa18be8f1fd3c3cbc685e",
+ "sha256:5e2fe3bb2363b862671eba632537cd3a823847db4d98be95690b7e382f3d6378",
+ "sha256:604815c55fd92e735f9738f65dabf4edc3e79f88541c221d292faec1904a4b17",
+ "sha256:6c5275bd82711cd3dcd0af8ce0bb99113ae8911fc2952805f1d012de7d600a4c",
+ "sha256:731ca5aabe9085160cf68b2dbef95fc1991015bc0a3a6ea46a371ab88f3d0913",
+ "sha256:7612520e5e1a371d77e1d1ca3a3ee6227eef00d0a9cddb4ef7ecb0b7396eddf7",
+ "sha256:7916cbc94f1c6b1301ac04510d0881b9e9feb20ae34094d3615a8a7c3db0dcc0",
+ "sha256:81c3fa9a75d9f1afafdb916d5995633f319db09bd773cb56b8e39f1e98d90820",
+ "sha256:887668e792b7edbfb1d3c9d8b5d8c859269a0f0eba4dda562adb95500f60dbba",
+ "sha256:93a473b53cc6e0b3ce6bf51b1b95b7b1e7e6084be3a07e40f79b42e83503fbf2",
+ "sha256:96d4dc103d1a0fa6d47c6c55a47de5f5dafd5ef0114fa10c85a1fd8e0216284b",
+ "sha256:a3d3e086474ef12ef13d42e5f9b7bbf09d39cf6bd4940f982263d6954b13f6a9",
+ "sha256:b02a0b9f332086657852b1f7cb380f6a42403a6d9c42a4c34a561aa4530d5234",
+ "sha256:b09e10ec453de97f9a23a5aa5e30b334195e8d2ddd1ce76cc32e52ba63c8b31d",
+ "sha256:b6f00ad5ebe846cc91763b1d0c6d30a8042e02b2316e27b05de04fa6ec831ec5",
+ "sha256:bba80df38cfc17f490ec651c73bb37cd896bc2400cfba27d078c2135223c1206",
+ "sha256:c3d911614b008e8a576b8e5303e3db29224b455d3d66d1b2848ba6ca83f9ece9",
+ "sha256:ca20739e303254287138234485579b28cb0d524401f83d5129b5ff9d606cb0a8",
+ "sha256:cb192176b477d49b0a327b2a5a4979552b7a58cd42037034316b8018ac3ebb59",
+ "sha256:cdbbe7dff4a677fb555a54f9bc0450f2a21a93c5ba2b44e09e54fcb72d2bd13d",
+ "sha256:cf6e33d92b1526190a1de904df21663c46a456758c0424e4f947ae9aa6088bf7",
+ "sha256:d355502dce85ade85a2511b40b4c61a128902f246504f7de29bbeec1ae27933a",
+ "sha256:d673c4990acd016229a5c1c4ee8a9e6d8f481b27ade5fc3d95938697fa443ce0",
+ "sha256:dc577f4cfdda354db3ae37a572428a90ffdbe4e51eda7849bf442fb803f09c9b",
+ "sha256:dd9eef866c70d2cbbea1ae58134eaffda0d4bfea403025f4db6859724b18ab3d",
+ "sha256:f50e7a98b0453f39000619d845be8b06e611e56ee6e8186f7f60c3b1e2f0feae"
+ ],
+ "index": "pypi",
+ "version": "==8.1.0"
+ },
+ "pycparser": {
+ "hashes": [
+ "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0",
+ "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"
+ ],
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+ "version": "==2.20"
+ },
+ "pyzbar": {
+ "hashes": [
+ "sha256:0e204b904e093e5e75aa85e0203bb0e02888105732a509b51f31cff400f34265",
+ "sha256:496249b546be70ec98c0ff0ad9151e73daaffff129266df86150a15dcd8dac4c",
+ "sha256:7d6c01d2c0a352fa994aa91b5540d1caeaeaac466656eb41468ca5df33be9f2e"
+ ],
+ "index": "pypi",
+ "version": "==0.1.8"
+ }
+ },
+ "develop": {}
+}
diff --git a/README.md b/README.md
index 5dfd3f7..4c86597 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,44 @@ As (not really) specified in https://github.com/MohGovIL/Ramzor
A pythonic implementation of the verification process can be found in [`verify.py`](verify.py).
-It requires the [`cryptography`](https://pypi.org/project/cryptography/) package to be installed.
+### Setup
+
+Install [`pipenv`](https://pypi.org/project/pipenv/) and execute:
+```bash
+pipenv install
+```
+
+### Usage
+
+#### Option 1 - from QR code image
+Save your Green Pass as a `.png` file and execute:
+```bash
+pipenv run python verify.py -i green_pass_image.png
+```
+
+#### Option 2 - from QR code decoded textual content
+
+Decode the QR code payload yourself, put it in a txt file:
+
+*textual_payload.txt*
+```json
+base64EncodedSignature==#{"id":"01/IL/ABCD1234ABCD1234ABCD1234ABCD1234#ABCD1234","et":1,"ct":1,"c":"IL MOH","cn":null,"fn":null,"g":null,"f":null,"gl":null,"fl":null,"idp":null,"idl":null,"b":"0001-01-01","e":"0001-01-01","a":"0001-01-01","p":[{"idl":"012345678","e":"2021-01-01"}]}
+```
+
+And then execute:
+
+```bash
+pipenv run python verify.py -t textual_payload.txt
+```
+
+### Output example
+
+```
+Valid signature!
+Israeli ID Number 012345678
+ID valid by 2021-01-01
+Cert Unique ID 01/IL/ABCD1234ABCD1234ABCD1234ABCD1234#ABCD1234
+```
## Verification Process Details
diff --git a/verify.py b/verify.py
index 6192457..fe873b3 100644
--- a/verify.py
+++ b/verify.py
@@ -1,37 +1,76 @@
+import argparse
import base64
import json
+from pathlib import Path
+
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
-sig = base64.b64decode("base64EncodedSignature==")
+from PIL import Image
+from pyzbar import pyzbar
+
+
+def cert(name):
+ return Path(__file__).absolute().parent / 'certs' / name
+
+
+def verify(qr_code_bytes):
+ b64, payload = qr_code_bytes.split(b'#', maxsplit=1)
+ sig = base64.decodebytes(b64)
+
+ h = hashes.Hash(hashes.SHA256())
+ h.update(payload.decode().encode('utf8'))
+ digest = h.finalize()
+
+ with open(cert("RamzorQRPubKey.pem"), "rb") as f:
+ k = serialization.load_pem_public_key(f.read())
+ k.verify(
+ sig,
+ digest,
+ padding.PKCS1v15(),
+ hashes.SHA256(),
+ )
+
+ print("Valid signature!")
+
+ data = json.loads(payload)
+ if data['ct'] == 1:
+ for i in range(len(data['p'])):
+ print(f"Details of person number {i+1}:")
+ print(f"\tIsraeli ID Number {data['p'][i]['idl']}")
+ print(f"\tID valid by {data['p'][i]['e']}")
+ print(f"Cert Unique ID {data['id']}")
+ elif data['ct'] == 2:
+ print(f"Israeli ID Number {data['idl']}")
+ print(f"ID valid by {data['e']}")
+ print(f"Cert Unique ID {data['id']}")
+ else:
+ print("Unsupported certificate type")
+
+
+def read_qr_code(image_path):
+ return pyzbar.decode(Image.open(image_path))[0].data
-payload = '{"id":"01/IL/ABCD1234ABCD1234ABCD1234ABCD1234#ABCD1234","et":1,"ct":1,"c":"IL MOH","cn":null,"fn":null,"g":null,"f":null,"gl":null,"fl":null,"idp":null,"idl":null,"b":"0001-01-01","e":"0001-01-01","a":"0001-01-01","p":[{"idl":"0123456789","e":"2021-01-01"}]}'
-h = hashes.Hash(hashes.SHA256())
-h.update(payload.encode("utf-8"))
-digest = h.finalize()
+def create_arg_parser():
+ parser = argparse.ArgumentParser("GreenPass QR code verifier")
+ group = parser.add_mutually_exclusive_group(required=True)
+ group.add_argument(
+ "-i", "--image_path", type=Path, help="Path to an image with the QR code", default=None)
+ group.add_argument(
+ "-t", "--txt_path", type=Path, help="Path to decoded QR code textual content", default=None)
+ return parser
-with open("certs/RamzorQRPubKey.pem", "rb") as f:
- k = serialization.load_pem_public_key(f.read())
- k.verify(
- sig,
- digest,
- padding.PKCS1v15(),
- hashes.SHA256(),
- )
+if __name__ == '__main__':
+ # Parse arguments
+ parser = create_arg_parser()
+ args = parser.parse_args()
-data = json.loads(payload)
-if data['ct'] == 1:
- for i in range(len(data['p'])):
- print(f"Details of person number {i+1}:")
- print(f"\tIsraeli ID Number {data['p'][i]['idl']}")
- print(f"\tID valid by {data['p'][i]['e']}")
- print(f"Cert Unique ID {data['id']}")
-elif data['ct'] == 2:
- print(f"Israeli ID Number {data['idl']}")
- print(f"ID valid by {data['e']}")
- print(f"Cert Unique ID {data['id']}")
-else:
- print("Unsupported certificate type")
+ # Choose correct input
+ if args.image_path:
+ verify(read_qr_code(args.image_path))
+ elif args.txt_path:
+ with open(args.txt_path, 'rb') as f:
+ verify(f.read().strip())