{"id":2018,"date":"2020-06-21T14:56:56","date_gmt":"2020-06-21T06:56:56","guid":{"rendered":"https:\/\/www.techcoil.com\/blog\/?p=2018"},"modified":"2020-06-21T14:57:48","modified_gmt":"2020-06-21T06:57:48","slug":"how-to-use-pycrypto-python-qrcode-and-flask-restplus-to-create-qr-codes-that-can-send-encrypted-data-to-an-endpoint","status":"publish","type":"post","link":"https:\/\/www.techcoil.com\/blog\/how-to-use-pycrypto-python-qrcode-and-flask-restplus-to-create-qr-codes-that-can-send-encrypted-data-to-an-endpoint\/","title":{"rendered":"How to use pycrypto, python-qrcode and Flask-RESTPlus to create QR codes that can send encrypted data to an endpoint"},"content":{"rendered":"<p>If you want to direct someone to a web page without saying a word, then you can use QR codes to do so.<\/p>\n<p>For example, your QR code reader will direct your phone's browser to visit our home page when you scan the following QR Code:<\/p>\n<p><img decoding=\"async\" width=\"330\" height=\"330\" src=\"https:\/\/www.techcoil.com\/blog\/wp-content\/uploads\/techcoil_home_page_qrcode.png\" alt=\"Techcoil home page QRCode\" class=\"aligncenter size-full wp-image-2033\" \/><\/p>\n<p>Given that, you can use QR codes to send <a href=\"https:\/\/www.techcoil.com\/glossary\/http-request\/\" rel=\"noopener\" target=\"_blank\">HTTP requests<\/a> to an endpoint of your <a href=\"https:\/\/www.techcoil.com\/glossary\/http-server\/\" rel=\"noopener\" target=\"_blank\">HTTP server<\/a>. In addition, you can embed data that you wish to send to the endpoint in the QR codes.<\/p>\n<p>With this in mind, let's look at how we can use <a href=\"https:\/\/pypi.org\/project\/pycrypto\/\" rel=\"noopener\" target=\"_blank\">pycrypto<\/a>, <a href=\"https:\/\/pypi.org\/project\/qrcode\/\" rel=\"noopener\" target=\"_blank\">python-qrcode<\/a> and <a href=\"https:\/\/flask-restplus.readthedocs.io\/en\/stable\/\" rel=\"noopener\" target=\"_blank\">Flask-RESTPlus<\/a> to create QR codes that can send encrypted data to an endpoint. <\/p>\n<h2>What happens when a QR code reader picks up an URL<\/h2>\n<p>When QR code readers pick up an URL in a QR code image, they start a web browser to retrieve the resource from the URL. Given that, the browser sends a HTTP GET request to that URL. In this situation, we can send data to the server through query string variables.<\/p>\n<p>Given that, we will be able to embed some data in our QR code for a reader to send to a server endpoint. When we do so, we can fulfil functionalities to trigger a server action through a QR code.<\/p>\n<h2>Generating a QR Code image with <code>python-qrcode<\/code><\/h2>\n<p>Previously, I discussed how we can <a href=\"https:\/\/www.techcoil.com\/blog\/how-to-create-an-api-endpoint-that-generates-a-qr-code-image-with-python-3-flask-restplus-and-python-qrcode\/\" rel=\"noopener\" target=\"_blank\">create an API endpoint that generates a QR Code image, with Python 3 Flask-RESTPlus and python-qrcode<\/a>.  <\/p>\n<p>When we run the sample script, we get an endpoint that receives HTTP POST requests made to \/api\/qrcode. If we post the following JSON model:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n{\r\n  &quot;value&quot;: &quot;https:\/\/www.techcoil.com&quot;\r\n}\r\n<\/pre>\n<p>then we will get the QR code image shown earlier in the <a href=\"https:\/\/www.techcoil.com\/glossary\/http-response\/\" target=\"_blank\" rel=\"noopener\">HTTP response<\/a>.<\/p>\n<p>Given that, we can put the logic that returns a string value as a QR code image into a function:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nfrom flask import send_file\r\nfrom io import BytesIO\r\nimport qrcode\r\n\r\ndef qr_code_send_file(value_to_turn_into_qrcode):\r\n    pil_img = qrcode.make(value_to_turn_into_qrcode)\r\n    img_io = BytesIO()\r\n    pil_img.save(img_io, 'PNG')\r\n    img_io.seek(0)\r\n    return send_file(img_io, mimetype='image\/png')\r\n<\/pre>\n<h2>Encrypting and decrypting data with pycrypto<\/h2>\n<p>Once we have the Python 3 codes to convert string values into QR code image, let's look at the encryption part.<\/p>\n<p>But couldn't we pass the data as query string variables along with the URL as a string input to <code>qr_code_send_file<\/code>?<\/p>\n<p>Although we can do so, we may want to encrypt the data before embedding it as an QR code for security reasons.<\/p>\n<p>Given that, let's look at how we can encrypt and decrypt data in Python 3.<\/p>\n<p>Previously, I discussed <a href=\"https:\/\/www.techcoil.com\/blog\/how-to-encrypt-and-decrypt-data-in-python-3-using-pycrypto\/\" rel=\"noopener\" target=\"_blank\">how we can encrypt and decrypt data in Python 3<\/a>. <\/p>\n<p>When you look at that post, you can find the following functions that we can use in this discussion:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nfrom Crypto.Cipher import AES\r\n \r\nimport base64, json, math\r\n \r\n# AES key must be either 16, 24, or 32 bytes long\r\nCOMMON_ENCRYPTION_KEY='asdjk@15r32r1234asdsaeqwe314SEFT'\r\n# Make sure the initialization vector is 16 bytes\r\nCOMMON_16_BYTE_IV_FOR_AES='IVIVIVIVIVIVIVIV'\r\n \r\ndef get_common_cipher():\r\n    return AES.new(COMMON_ENCRYPTION_KEY,\r\n                   AES.MODE_CBC,\r\n                   COMMON_16_BYTE_IV_FOR_AES)\r\n \r\ndef encrypt_with_common_cipher(cleartext):\r\n    common_cipher = get_common_cipher()\r\n    cleartext_length = len(cleartext)\r\n    nearest_multiple_of_16 = 16 * math.ceil(cleartext_length\/16)\r\n    padded_cleartext = cleartext.rjust(nearest_multiple_of_16)\r\n    raw_ciphertext = common_cipher.encrypt(padded_cleartext)\r\n    return base64.b64encode(raw_ciphertext).decode('utf-8')\r\n \r\n \r\ndef decrypt_with_common_cipher(ciphertext):\r\n    common_cipher = get_common_cipher()\r\n    raw_ciphertext = base64.b64decode(ciphertext)\r\n    decrypted_message_with_padding = common_cipher.decrypt(raw_ciphertext)\r\n    return decrypted_message_with_padding.decode('utf-8').strip()\r\n \r\n \r\ndef encrypt_json_with_common_cipher(json_obj):\r\n    json_string = json.dumps(json_obj)\r\n    return encrypt_with_common_cipher(json_string)\r\n \r\n \r\ndef decrypt_json_with_common_cipher(json_ciphertext):\r\n    json_string = decrypt_with_common_cipher(json_ciphertext)\r\n    return json.loads(json_string)\r\n<\/pre>\n<p>When we have the above functions, we will be able to:<\/p>\n<ul>\n<li>encrypt a JSON object into a cipher text string.<\/li>\n<li>decrypt a cipher text string back into a JSON object.<\/li>\n<\/ul>\n<h2>Demonstrating that a QR code can send encrypted data to an endpoint which decrypts the data<\/h2>\n<p>In order to have visualize how to put the various parts together, let's build a demo app with two endpoints.<\/p>\n<h3>An endpoint that creates a QR Code representing a URL with a cipher text as a query string variable<\/h3>\n<p>First, let's create an endpoint that will take a JSON object and encrypt it into a cipher text. Once it had done so, it will include the cipher text as a query string variable in a URL:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nfrom flask_restplus import Namespace, Resource, fields\r\nimport urllib.parse\r\n\r\n# Create namespace for containing Qr Code related operations\r\nqrcode_namespace = Namespace('QrCode', description='Qr code related operations')\r\n\r\n# Define input model\r\nqrcode_creation_input = qrcode_namespace.model('QRCode creation Input', {\r\n    'id': fields.String(required=True, description='An Id'),\r\n    'amount': fields.Integer(required=True, description='An amount')\r\n})\r\n\r\n@qrcode_namespace.route('\/encrypted-payload')\r\nclass CreateInvoiceQrCode(Resource):\r\n\r\n    @qrcode_namespace.expect(qrcode_creation_input)\r\n    @qrcode_namespace.doc('Creates a QR code image that will bring the QR code reader to endpoint that will decrypt the contents.')\r\n    @qrcode_namespace.produces(&#x5B;'image\/png'])\r\n    def post(self):\r\n\r\n        thing_data_dict = request.get_json()\r\n        cipher_text = encrypt_json_with_common_cipher(thing_data_dict)\r\n        payload_decryption_url = '%s\/api\/decrypt\/qrcode-details?ctext=%s' % (current_app.config&#x5B;'APP_URL'], urllib.parse.quote(cipher_text))\r\n\r\n        return qr_code_send_file(payload_decryption_url)\r\n<\/pre>\n<h3>An endpoint that decrypts the cipher text from a query string variable<\/h3>\n<p>After the QR code scans the QR Code image that was created by the endpoint earlier, it will hit the endpoint that decrypts the cipher text:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nfrom json import JSONDecodeError\r\n\r\ndecrypt_namespace = Namespace('Decrypt', description='Decryption operations')\r\n\r\n@decrypt_namespace.route('\/qrcode-details')\r\nclass PayToQrCodeInvoice(Resource):\r\n\r\n    @decrypt_namespace.doc('Url for QR code reader to reach in order to decrypt contents')\r\n    def get(self):\r\n        try:\r\n            cipher_text = request.args.get('ctext')\r\n            decrypted_json = decrypt_json_with_common_cipher(cipher_text)\r\n            return decrypted_json, 200\r\n        except JSONDecodeError as jde:\r\n            print(jde)\r\n            return 'Invalid cipher text provided', 400\r\n        except TypeError as te:\r\n            print(te)\r\n            return 'Invalid cipher text provided', 400\r\n<\/pre>\n<h3>Putting everything together<\/h3>\n<p>Given that we have explored the various code segments for the demo app, we can now build the following script:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\n#### Encryption \/ Decryption\r\n\r\nfrom Crypto.Cipher import AES\r\n\r\nimport base64, json, math\r\n\r\n# AES key must be either 16, 24, or 32 bytes long\r\nCOMMON_ENCRYPTION_KEY = 'asdjk@15r32r1234asdsaeqwe314SEFT'\r\n# Make sure the initialization vector is 16 bytes\r\nCOMMON_16_BYTE_IV_FOR_AES = 'IVIVIVIVIVIVIVIV'\r\n\r\ndef get_common_cipher():\r\n    return AES.new(COMMON_ENCRYPTION_KEY,\r\n                   AES.MODE_CBC,\r\n                   COMMON_16_BYTE_IV_FOR_AES)\r\n\r\ndef encrypt_with_common_cipher(cleartext):\r\n    common_cipher = get_common_cipher()\r\n    cleartext_length = len(cleartext)\r\n    nearest_multiple_of_16 = 16 * math.ceil(cleartext_length \/ 16)\r\n    padded_cleartext = cleartext.rjust(nearest_multiple_of_16)\r\n    raw_ciphertext = common_cipher.encrypt(padded_cleartext)\r\n    return base64.b64encode(raw_ciphertext).decode('utf-8')\r\n\r\n\r\ndef decrypt_with_common_cipher(ciphertext):\r\n    common_cipher = get_common_cipher()\r\n    raw_ciphertext = base64.b64decode(ciphertext)\r\n    decrypted_message_with_padding = common_cipher.decrypt(raw_ciphertext)\r\n    return decrypted_message_with_padding.decode('utf-8').strip()\r\n\r\n\r\ndef encrypt_json_with_common_cipher(json_obj):\r\n    json_string = json.dumps(json_obj)\r\n    return encrypt_with_common_cipher(json_string)\r\n\r\n\r\ndef decrypt_json_with_common_cipher(json_ciphertext):\r\n    json_string = decrypt_with_common_cipher(json_ciphertext)\r\n    return json.loads(json_string)\r\n\r\n#### QrCode generation\r\n\r\nfrom flask import send_file\r\nfrom io import BytesIO\r\nimport qrcode\r\n\r\n\r\ndef qr_code_send_file(value_to_turn_into_qrcode):\r\n    pil_img = qrcode.make(value_to_turn_into_qrcode)\r\n    img_io = BytesIO()\r\n    pil_img.save(img_io, 'PNG')\r\n    img_io.seek(0)\r\n    return send_file(img_io, mimetype='image\/png')\r\n\r\n\r\n#### Endpoints\r\n\r\nfrom flask import Blueprint, current_app, Flask, request\r\nfrom flask_restplus import Api\r\n\r\napi_blueprint = Blueprint('API', __name__)\r\n\r\napi = Api(api_blueprint,\r\n    title='Encrypted payload within QR Code sample',\r\n    version='1.0',\r\n    description='API for demonstrating pass of encrypted payload from a QR code back to the server.'\r\n    # All API metadatas\r\n)\r\n\r\nfrom flask_restplus import Namespace, Resource, fields\r\nimport urllib.parse\r\n\r\n# Create namespace for containing Qr Code related operations\r\nqrcode_namespace = Namespace('QrCode', description='Qr code related operations')\r\n\r\n# Define input model\r\nqrcode_creation_input = qrcode_namespace.model('QRCode creation Input', {\r\n    'id': fields.String(required=True, description='An Id'),\r\n    'amount': fields.Integer(required=True, description='An amount')\r\n})\r\n\r\n@qrcode_namespace.route('\/encrypted-payload')\r\nclass CreateInvoiceQrCode(Resource):\r\n\r\n    @qrcode_namespace.expect(qrcode_creation_input)\r\n    @qrcode_namespace.doc('Creates a QR code image that will bring the QR code reader to endpoint that will decrypt the contents.')\r\n    @qrcode_namespace.produces(&#x5B;'image\/png'])\r\n    def post(self):\r\n\r\n        thing_data_dict = request.get_json()\r\n        cipher_text = encrypt_json_with_common_cipher(thing_data_dict)\r\n        payload_decryption_url = '%s\/api\/decrypt\/qrcode-details?ctext=%s' % (current_app.config&#x5B;'APP_URL'], urllib.parse.quote(cipher_text))\r\n\r\n        return qr_code_send_file(payload_decryption_url)\r\n\r\napi.add_namespace(qrcode_namespace, path='\/qrcode')\r\n\r\n# Create namespace for decrypting payload\r\n\r\nfrom json import JSONDecodeError\r\n\r\ndecrypt_namespace = Namespace('Decrypt', description='Decryption operations')\r\n\r\n@decrypt_namespace.route('\/qrcode-details')\r\nclass ShowDecryptedPayload(Resource):\r\n\r\n    @decrypt_namespace.doc('Url for QR code reader to reach in order to decrypt contents')\r\n    def get(self):\r\n        try:\r\n            cipher_text = request.args.get('ctext')\r\n            decrypted_json = decrypt_json_with_common_cipher(cipher_text)\r\n            return decrypted_json, 200\r\n        except JSONDecodeError as jde:\r\n            print(jde)\r\n            return 'Invalid cipher text provided', 400\r\n        except TypeError as te:\r\n            print(te)\r\n            return 'Invalid cipher text provided', 400\r\n\r\n\r\napi.add_namespace(decrypt_namespace, path='\/decrypt')\r\n\r\napp = Flask(__name__)\r\n# Change this to the URL where you host your app\r\napp.config&#x5B;'APP_URL'] = 'https:\/\/qrcode.example.com'\r\napp.register_blueprint(api_blueprint, url_prefix='\/api')\r\napp.run(host='0.0.0.0', port=12345)\r\n<\/pre>\n<h3>Installing the dependencies<\/h3>\n<p>Before you can run the script, install the following dependencies into your Python 3 environment:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nflask-restplus==0.12.1\r\npycrypto==2.6.1\r\nPillow\r\nqrcode==6.1\r\nWerkzeug==0.16.1\r\n<\/pre>\n<h3>Running the demo script<\/h3>\n<p>Once you have installed the dependencies, change <code>app.config['APP_URL']<\/code> to reflect the URL to reach your Python 3 application.<\/p>\n<p>When you run the script, you will find the two endpoints:<\/p>\n<ul>\n<li><code>\/api\/qrcode\/encrypted-payload<\/code> that handles HTTP POST requests.<\/li>\n<li><code>\/api\/decrypt\/qrcode-details<\/code> that handles HTTP GET requests.<\/li>\n<\/ul>\n<p>After you send a JSON object in a HTTP POST request to <code>\/api\/qrcode\/encrypted-payload<\/code>, you will be able to get a QR code image in the HTTP response.<\/p>\n<p>If you point your QR code reader at the image, you will then be redirected to <code>\/api\/decrypt\/qrcode-details<\/code> which reveals the JSON object.<\/p>\n\n      <ul id=\"social-sharing-buttons-list\">\n        <li class=\"facebook\">\n          <a href=\"https:\/\/www.facebook.com\/sharer\/sharer.php?u=https%3A%2F%2Fwp.me%2Fp245TQ-wy\" target=\"_blank\" role=\"button\" rel=\"nofollow\">\n            <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/Facebook.png\" alt=\"Facebook icon\"> Share\n          <\/a>\n        <\/li>\n        <li class=\"twitter\">\n          <a href=\"https:\/\/twitter.com\/intent\/tweet?text=&url=https%3A%2F%2Fwp.me%2Fp245TQ-wy&via=Techcoil_com\" target=\"_blank\" role=\"button\" rel=\"nofollow\">\n          <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/Twitter.png\" alt=\"Twitter icon\"> Tweet\n          <\/a>\n        <\/li>\n        <li class=\"linkedin\">\n          <a href=\"https:\/\/www.linkedin.com\/shareArticle?mini=1&title=&url=https%3A%2F%2Fwp.me%2Fp245TQ-wy&source=https:\/\/www.techcoil.com\" target=\"_blank\" role=\"button\" rel=\"nofollow\">\n          <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/linkedin.png\" alt=\"Linkedin icon\"> Share\n          <\/a>\n        <\/li>\n        <li class=\"pinterest\">\n          <a href=\"https:\/\/pinterest.com\/pin\/create\/button\/?url=https%3A%2F%2Fwww.techcoil.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F2018&description=\" class=\"pin-it-button\" target=\"_blank\" role=\"button\" rel=\"nofollow\" count-layout=\"horizontal\">\n          <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/Pinterest.png\" alt=\"Pinterest icon\"> Save\n          <\/a>\n        <\/li>\n      <\/ul>\n    ","protected":false},"excerpt":{"rendered":"<p>If you want to direct someone to a web page without saying a word, then you can use QR codes to do so.<\/p>\n<p>For example, your QR code reader will direct your phone&#8217;s browser to visit our home page when you scan the following QR Code:<\/p>\n<p><img decoding=\"async\" width=\"330\" height=\"330\" src=\"https:\/\/www.techcoil.com\/blog\/wp-content\/uploads\/techcoil_home_page_qrcode.png\" alt=\"Techcoil home page QRCode\" class=\"aligncenter size-full wp-image-2033\" \/><\/p>\n<p>Given that, you can use QR codes to send <a href=\"https:\/\/www.techcoil.com\/glossary\/http-request\/\" rel=\"noopener\" target=\"_blank\">HTTP requests<\/a> to an endpoint of your <a href=\"https:\/\/www.techcoil.com\/glossary\/http-server\/\" rel=\"noopener\" target=\"_blank\">HTTP server<\/a>. In addition, you can embed data that you wish to send to the endpoint in the QR codes.<\/p>\n<p>With this in mind, let&#8217;s look at how we can use <a href=\"https:\/\/pypi.org\/project\/pycrypto\/\" rel=\"noopener\" target=\"_blank\">pycrypto<\/a>, <a href=\"https:\/\/pypi.org\/project\/qrcode\/\" rel=\"noopener\" target=\"_blank\">python-qrcode<\/a> and <a href=\"https:\/\/flask-restplus.readthedocs.io\/en\/stable\/\" rel=\"noopener\" target=\"_blank\">Flask-RESTPlus<\/a> to create QR codes that can send encrypted data to an endpoint. <\/p>\n","protected":false},"author":1,"featured_media":2033,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"footnotes":""},"categories":[375],"tags":[584,640,730,226,233,639,641,622],"jetpack_featured_media_url":"https:\/\/www.techcoil.com\/blog\/wp-content\/uploads\/techcoil_home_page_qrcode.png","jetpack_shortlink":"https:\/\/wp.me\/p245TQ-wy","jetpack-related-posts":[],"jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/posts\/2018"}],"collection":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/comments?post=2018"}],"version-history":[{"count":0,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/posts\/2018\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/media\/2033"}],"wp:attachment":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/media?parent=2018"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/categories?post=2018"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/tags?post=2018"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}