Activity #44: Documentation of Python Flask Encryption and Decryption

Create folder:

Inside your folder, click the search bar and type CMD and press ENTER

Install virtualenv in your CMD.

While Python 3.3+ has venv built-in, you can also use virtualenv, which is a popular tool to create virtual environments.

To install virtualenv, you can run:

pip install virtualenv

Alternatively, you can use the built-in venv module (we'll be using this method in the next steps).

Create a Virtual Environment

Navigate to your project directory and create a virtual environment. You can do this by running:

python -m venv venv

This will create a directory named venv (you can choose another name) which contains the isolated Python environment.

Activate the Virtual Environment

Next, you'll need to activate the virtual environment. The activation command differs based on your operating system:

  venv\Scripts\activate

After activation, you should see the environment name (e.g., (venv)) in your terminal prompt, indicating that the virtual environment is active.

5. Install Dependencies

Once the virtual environment is activated, you can install the necessary libraries for your project, like Flask and cryptography. Run the following command:

pip install Flask cryptography

This will install both Flask and cryptography in your isolated virtual environment.

Create a requirements.txt (optional)

It's a good practice to create a requirements.txt file for your project, which will list all of your dependencies. You can generate this file by running:

pip freeze > requirements.txt

The requirements.txt file will contain the following dependencies (or similar):

Flask==2.2.2
cryptography==43.0.3

Create the Flask Application with Encryption and Decryption Routes

Here’s an implementation of the Flask app that uses Fernet for encryption and decryption:

from flask import Flask, request, jsonify
from cryptography.fernet import Fernet

# Create Flask app
app = Flask(__name__)

# Generate a key for Fernet encryption/decryption
# Ideally, this should be stored securely and should not be regenerated each time the app runs.
key = Fernet.generate_key()
cipher = Fernet(key)

# POST route to encrypt data
@app.route('/encrypt', methods=['POST'])
def encrypt():
    try:
        # Get data from the POST request
        data = request.get_json()

        # Extract the text to be encrypted
        text = data.get("text", "")

        if not text:
            return jsonify({"error": "No text provided"}), 400

        # Encrypt the text using Fernet
        encrypted_text = cipher.encrypt(text.encode()).decode()

        return jsonify({
            "encrypted_text": encrypted_text
        }), 200

    except Exception as e:
        return jsonify({"error": str(e)}), 500


# POST route to decrypt data
@app.route('/decrypt', methods=['POST'])
def decrypt():
    try:
        # Get data from the POST request
        data = request.get_json()

        # Extract the encrypted text
        encrypted_text = data.get("encrypted_text", "")

        if not encrypted_text:
            return jsonify({"error": "No encrypted text provided"}), 400

        # Decrypt the text using Fernet
        decrypted_text = cipher.decrypt(encrypted_text.encode()).decode()

        return jsonify({
            "decrypted_text": decrypted_text
        }), 200

    except Exception as e:
        return jsonify({"error": str(e)}), 500


if __name__ == '__main__':
    app.run(debug=True)

Run the Application

To run this application, save it as app.py and run:

python app.py

Explanation of the Code:

  1. Key Generation:

    • We use Fernet.generate_key() to generate a random key for encryption and decryption. In a real application, you should store this key securely (e.g., in environment variables or a key vault) and not regenerate it every time.
  2. Encrypt Route (/encrypt):

    • This route accepts a POST request with JSON data containing the text to be encrypted.

    • The cipher.encrypt(text.encode()).decode() method encrypts the plaintext string into a ciphertext.

  3. Decrypt Route (/decrypt):

    • This route accepts a POST request with the encrypted text (as a string) and returns the decrypted plaintext.
  4. Error Handling:

    • If no text is provided in the request, the API returns a 400 status code with an appropriate error message.

    • If anything goes wrong during encryption or decryption, the API will return a 500 error with the exception message.

Sample Requests

1. Encrypt Text

{
    "text": "Celestial Spirits"
}

Response:

{
    "encrypted_text": "gAAAAABnNRTer7vTseG8gGcBrW20-5ZG5RXRcLa5ntJRlHkWuMqOlylapMrIEJr9qoU0AaYYaseGxRYvw9k9d3317yZbBsYvTCgtolHeaffIoDi78qNidRI="
}

2. Decrypt Text

{
    "encrypted_text": "gAAAAABnNRTer7vTseG8gGcBrW20-5ZG5RXRcLa5ntJRlHkWuMqOlylapMrIEJr9qoU0AaYYaseGxRYvw9k9d3317yZbBsYvTCgtolHeaffIoDi78qNidRI="
}

Response:

{
    "decrypted_text": "Celestial Spirits"
}