Python: working with AES 256 GCM

be a code ninja

Introduction

Using encryption solves the business problem of securing sensitive data and communications.

In today’s digital landscape, businesses face various risks related to data breaches, unauthorized access, and tampering of information. Encryption addresses these challenges by providing a robust encryption and authentication solution. Here are some specific business problems that encryption helps solve:

  • Confidentiality of data: Businesses often deal with sensitive and confidential information, such as customer data, financial records, trade secrets, and intellectual property. Using, for example, AES 256 ensures that this data remains confidential by encrypting it with a strong encryption algorithm, making it nearly impossible for unauthorized individuals to read or understand the encrypted information.
  • Secure communication: Many businesses rely on secure communication channels for transmitting sensitive information internally or with external parties. AES 256 GCM is commonly used in protocols like TLS (Transport Layer Security) to establish secure connections between clients and servers, protecting the confidentiality and integrity of data during transmission.
  • Compliance requirements: Businesses operate in industries that have strict regulatory requirements regarding the protection of sensitive information. AES 256 GCM is employed to meet these compliance standards. For example, industries such as finance (PCI DSS), healthcare (HIPAA), and government agencies have specific regulations mandating the use of strong encryption mechanisms to protect sensitive data.
  • Data storage security: Storing sensitive data securely is crucial for businesses. AES 256 GCM is employed in data storage systems, including databases, cloud storage, and backups, to encrypt data at rest. This ensures that even if the storage medium is compromised, the encrypted data remains protected and unreadable to unauthorized individuals.
  • Data integrity and authenticity: AES 256 GCM incorporates authentication mechanisms to verify the integrity and authenticity of data. This helps detect any unauthorized modifications or tampering attempts, ensuring that the received data is indeed from the expected source and has not been altered in transit.

By addressing these business problems, encryption enables organizations to protect their sensitive information, maintain compliance, establish secure communication channels, and ensure the integrity and authenticity of data. It provides businesses with the confidence that their critical data remains secure, minimizing the risks associated with data breaches and unauthorized access.

About AES 256 GCM

AES 256 GCM is used where strong security is essential for communication, data storage, and file encryption. Its adoption is driven by the need for confidentiality, integrity, compliance, and widespread acceptance in various industries.

Why use AES 256 GCM:

  • Strong security: AES 256 GCM offers a high level of security for protecting sensitive information. It uses a strong encryption algorithm (AES 256) and adds integrity checks through the GCM mode, ensuring confidentiality and data integrity.
  • Widely accepted: AES 256 GCM is a widely adopted encryption standard recommended by security experts and used in various industries. Its widespread use ensures compatibility and interoperability between different systems.

Where AES 256 GCM is used:

  • Secure communication: AES 256 GCM is commonly used in secure communication protocols like Transport Layer Security (TLS) and Secure Shell (SSH). It ensures that data transmitted over networks, such as internet connections, remains confidential and protected from unauthorized access.
  • Data storage: AES 256 GCM is employed in data storage systems to encrypt sensitive data, protecting it from unauthorized access in databases, cloud storage, or backup systems.
  • File encryption: It is used to encrypt files and documents, ensuring their confidentiality and preventing unauthorized users from accessing the contents.

When to use AES 256 GCM:

  • When strong encryption is required: AES 256 GCM is suitable when a high level of encryption strength is needed, making it difficult for attackers to break the encryption and access the sensitive information.
  • Integrity and authenticity are crucial: AES 256 GCM provides built-in integrity checks, ensuring that data remains unchanged during transmission or storage. It verifies the authenticity of the data, allowing the receiver to trust the integrity of the information.
  • Compliance requirements: AES 256 GCM is often used when compliance with security standards and regulations is necessary. Industries such as finance, healthcare, and government entities may require strong encryption mechanisms to protect sensitive data.

What is AES 256 GCM:

AES 256 GCM (Advanced Encryption Standard 256-bit Galois/Counter Mode) is a widely used encryption algorithm that combines the AES symmetric encryption algorithm with the GCM mode of operation. It provides both confidentiality and integrity for data encryption.

Here’s a breakdown of the components and workings of the AES 256 GCM algorithm:

AES 256: AES, or the Advanced Encryption Standard, is a symmetric encryption algorithm approved by the U.S. National Institute of Standards and Technology (NIST). It operates on 128-bit blocks of data and supports key sizes of 128, 192, and 256 bits. AES 256 specifically refers to the variant that uses a 256-bit key size, providing a high level of security. It provides confidentiality by transforming plaintext data into ciphertext that can only be decrypted with the correct key. AES256 is a block cipher, meaning it encrypts and decrypts data in fixed-size blocks. It does not include features for authentication or integrity checks. Therefore, when using AES256 alone, additional measures such as message authentication codes (MACs) or digital signatures may be required to ensure data integrity and authenticity.

GCM mode: Galois/Counter Mode is a mode of operation for symmetric block ciphers, such as AES. GCM combines the encryption capability of the block cipher with the authentication and integrity checks provided by a hash function. GCM operates in two phases: the encryption phase and the authentication phase.

  • Encryption phase: In this phase, GCM uses a counter mode of operation to encrypt the data. A counter (nonce) is used to generate a unique keystream for each block of data. The keystream is then XORed with the plaintext to produce the ciphertext.
  • Authentication phase: GCM uses a technique called Galois field multiplication (GMAC) to calculate an authentication tag, also known as a message authentication code (MAC). The MAC is computed over the ciphertext and additional data, such as associated data (AAD) that may not be encrypted but still needs to be authenticated. The authentication tag provides integrity and authentication for the encrypted data.

Key generation: AES 256 GCM requires a 256-bit encryption key, which needs to be securely generated and shared between the communicating parties. The key should be kept confidential to ensure the security of the encrypted data.

Initialization Vector (IV): GCM requires a unique and unpredictable IV for each encryption operation. The IV is a nonce that is combined with the encryption key to generate a unique keystream. The IV should be randomly generated and never reused with the same encryption key.

Usage: To encrypt data using AES 256 GCM, the plaintext, encryption key, and IV are provided as input. The algorithm processes the data in blocks, encrypting each block using AES 256 in counter mode. It produces the ciphertext and the authentication tag as output.

Decryption and authentication: To decrypt the ciphertext, the encryption key, IV, ciphertext, and authentication tag are provided as input. The algorithm performs the reverse process, decrypting the ciphertext using AES 256 in counter mode and verifying the authenticity of the data using the authentication tag.

AES 256 GCM is considered a secure encryption algorithm that offers strong confidentiality and integrity protection. It is commonly used in various applications, such as secure communication protocols (e.g., TLS/SSL) and data storage systems, to ensure the confidentiality and integrity of sensitive information.

AES 256 GCM is a method used to protect information by encrypting it, making it unreadable to anyone without the right key. It ensures that the information remains confidential and maintains its integrity.

Still struggling, here’s a simpler explanation of AES 256 GCM:

AES 256 GCM is like a lockbox for your data. It uses a special code called a key to lock up your information so that only the people who have the right key can open it. The “256” part means it uses a very strong lock with a long and complex key, making it difficult for anyone to break in.

GCM is the way this lockbox works. It not only locks your data but also adds a special code to make sure no one tampers with it. It does this by using a unique number called a nonce to mix up the code each time, so even if someone intercepts your locked data, they can’t understand it without the right key and the specific mixing code.

When you want to send a message, AES 256 GCM takes your message and the key, and scrambles it up using the strong lock. It also adds that special mixing code to protect the message from being changed without your knowledge. This way, even if someone tries to read or modify the message while it’s being sent, they won’t be able to because they don’t have the right key and mixing code.

When the recipient gets the encrypted message, they use the same key and mixing code to unlock it. AES 256 GCM reverses the scrambling process, revealing the original message. It also checks if the message has been tampered with by comparing the mixing code. If everything matches, the recipient knows the message is authentic and hasn’t been changed during transmission.

AES 256 GCM is commonly used to secure sensitive information during communication and storage, ensuring that only authorized people can access and understand the data while protecting it from being modified or read by others.

For Example, Alice and Bob want to send secret messages to each other without anyone else being able to read or tamper with them. They decide to use a special method called AES 256 GCM to protect their messages.

Alice starts by putting her message inside a locked box. She uses a strong lock that requires a special key to open it. In this case, the lock is AES 256, which is a very secure type of lock, and the key is a long and complex code known only to Alice and Bob.

But Alice wants to make sure that even if someone intercepts the locked box, they can’t tamper with it or read its contents. That’s where GCM comes in. GCM adds an extra layer of protection. It mixes up the locked box even more by using a unique mixing code called a nonce. This makes it even harder for anyone to figure out what’s inside the box without the right key and mixing code.

Alice sends the locked box to Bob, and he receives it. Bob knows the secret key and mixing code, so he uses them to unlock the box. The lock is removed, and Bob can now see Alice’s original message.

But there’s more to it. GCM also checks if the locked box has been tampered with during its journey from Alice to Bob. It does this by comparing the mixing code. If the code matches, Bob knows that the message is authentic and hasn’t been changed along the way.

So, Alice and Bob can have private conversations without worrying about others eavesdropping or altering their messages. They trust AES 256 GCM to keep their communications secure and ensure that only they can access and understand their messages.

you can easily find resources and implementations for AES 256 and AES 256 GCM through online search Using relevant keywords like “AES 256 GCM implementation,” “AES GCM code example,” or specifying the programming language you are using can help narrow down the results to find the most relevant resources.

Here are some general suggestions to find relevant information:

NIST Publications: The National Institute of Standards and Technology (NIST) provides official documentation and standards related to AES. You can search for publications like NIST Special Publication 800-38D, which specifically covers the GCM mode of operation.

Cryptography Libraries and APIs: Many programming languages and cryptographic libraries provide implementations of AES and AES GCM. Popular libraries include OpenSSL, Bouncy Castle, Cryptography.io, and libsodium. You can search for documentation and examples specific to the library or API you are using.

Technical Blogs and Tutorials: There are numerous technical blogs and tutorial websites that provide explanations and code examples for AES 256 and AES 256 GCM implementations. Websites like Medium, Towards Data Science, or cryptography-specific blogs can be good sources of information.

Cryptography Forums and Communities: Participating in cryptography forums or communities can be a great way to connect with experts and practitioners in the field. Websites like Stack Overflow, Cryptography Stack Exchange, or Reddit’s r/cryptography subreddit can be helpful for finding discussions and resources related to AES and AES GCM.

Remember to exercise some caution when implementing cryptographic algorithms, as their incorrect usage can lead to security vulnerabilities. It’s always recommended to follow best practices, consult official documentation, and seek expert advice when working with cryptography.

Python cryptography Library

The cryptography.hazmat.primitives module is part of the cryptography library in Python. It provides low-level cryptographic primitives that are used for building higher-level cryptographic functions and protocols.

Here’s an explanation of the key components within the cryptography.hazmat.primitives module:

  • Symmetric Encryption Primitives: This includes algorithms such as AES (Advanced Encryption Standard), which is widely used for symmetric encryption. The module provides classes for AES, modes of operation (e.g., GCM, CBC), and cipher objects for encryption and decryption.
  • Asymmetric Encryption Primitives: This includes algorithms such as RSA (Rivest-Shamir-Adleman) used for asymmetric encryption. The module provides classes for RSA keys, key generation, encryption, and decryption.
  • Hash Functions: This includes cryptographic hash functions like SHA-256, SHA-512, etc., which are used for generating fixed-length message digests. The module provides classes for hash functions, allowing you to calculate hash values of data.
  • Key Derivation Functions: This includes functions like PBKDF2 (Password-Based Key Derivation Function 2), which are used to derive cryptographic keys from passwords or passphrases. The module provides classes for key derivation functions, enabling the derivation of secure encryption keys.
  • Digital Signatures: This includes algorithms such as RSA and ECDSA (Elliptic Curve Digital Signature Algorithm) used for creating and verifying digital signatures. The module provides classes for digital signature generation and verification.
  • Message Authentication Codes (MAC): This includes algorithms like HMAC (Hash-based Message Authentication Code) used for ensuring data integrity and authenticity. The module provides classes for HMAC algorithms and objects for generating and verifying MACs.
  • Padding: This includes padding schemes like PKCS7, which are used to add padding to data before encryption. The module provides classes for different padding schemes, allowing you to pad or unpad data.

The cryptography.hazmat.primitives module provides a foundation for building secure cryptographic systems in Python. It focuses on low-level cryptographic operations and ensures the implementation of strong cryptographic primitives, making it suitable for developing secure applications and protocols.

To load the cryptography library in Python, you need to install it first using a package manager like pip.

Here are the steps to install and load the cryptography library:

Installation: Open your command-line interface (CLI) or terminal and run the following command to install the cryptography library:

pip install cryptography

This command will download and install the library and its dependencies on your system.

Importing the Library: In your Python code, you can import the cryptography library using the import statement:

import cryptography

This command will download and install the library and its dependencies on your system.

After importing the library, you can access its modules and classes to perform cryptographic operations.

It’s important to note that the cryptography library may have additional dependencies or system requirements depending on your operating system. Make sure you have the necessary dependencies installed and meet the system requirements specified by the library.

Once the library is successfully loaded, you can utilize its functionality, such as symmetric and asymmetric encryption, hashing, key derivation, digital signatures, and more, by importing the relevant modules from cryptography.hazmat.primitives as needed. For example:

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa

The above code imports the hashes module for cryptographic hash functions and the rsa module for asymmetric encryption using the RSA algorithm.

By loading the cryptography library and utilizing its modules, you can leverage its robust cryptographic primitives and functions to build secure applications or perform cryptographic operations in Python.

import os
import base64
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.backends import default_backend

def encode(message, password):
    """
    Encodes a message using AES-256 GCM encryption.

    Args:
        message (str): The message to be encoded.
        password (str): The password used for key derivation.

    Returns:
        str: The encoded message.

    Raises:
        ValueError: If an invalid key size is encountered.

    """
    # Generate a secure encryption key using a password-based key derivation function (PBKDF2)
    salt = b'\x12\x34\x56\x78\x9a\xbc\xde\xf0'  # Salt for key derivation
    backend = default_backend()
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,  # AES-256 key length
        salt=salt,
        iterations=100000,  # Number of iterations for key stretching
        backend=backend
    )
    key = base64.urlsafe_b64encode(kdf.derive(password.encode()))

    # Decode the Base64-encoded key
    key = base64.urlsafe_b64decode(key)

    # Generate a random Initialization Vector (IV)
    iv = os.urandom(16)  # 16 bytes for AES-256

    # Create an AES-GCM cipher instance with the generated key and IV
    cipher = Cipher(algorithms.AES(key), modes.GCM(iv), backend=backend)
    encryptor = cipher.encryptor()

    # Encrypt the message
    ciphertext = encryptor.update(message.encode()) + encryptor.finalize()

    # Get the authentication tag
    tag = encryptor.tag

    # Combine the IV, ciphertext, and tag
    encoded_message = base64.urlsafe_b64encode(iv + ciphertext + tag).decode()

    return encoded_message


def decode(encoded_message, password):
    """
    Decodes an encoded message using AES-256 GCM decryption.

    Args:
        encoded_message (str): The encoded message to be decoded.
        password (str): The password used for key derivation.

    Returns:
        str: The decoded message.

    Raises:
        ValueError: If an invalid key size is encountered.

    """
    # Generate a secure encryption key using a password-based key derivation function (PBKDF2)
    salt = b'\x12\x34\x56\x78\x9a\xbc\xde\xf0'  # Salt for key derivation
    backend = default_backend()
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,  # AES-256 key length
        salt=salt,
        iterations=100000,  # Number of iterations for key stretching
        backend=backend
    )
    key = base64.urlsafe_b64encode(kdf.derive(password.encode()))

    # Decode the Base64-encoded key
    key = base64.urlsafe_b64decode(key)

    # Decode the Base64-encoded message
    decoded_message = base64.urlsafe_b64decode(encoded_message)

    # Extract the IV, ciphertext, and tag from the decoded message
    iv = decoded_message[:16]  # 16 bytes for AES-256
    ciphertext = decoded_message[16:-16]  # Remove the IV and tag from the message
    tag = decoded_message[-16:]  # Last 16 bytes are the tag

    # Create an AES-GCM cipher instance with the key, IV, and tag
    cipher = Cipher(algorithms.AES(key), modes.GCM(iv, tag), backend=backend)
    decryptor = cipher.decryptor()

    # Decrypt the ciphertext
    plaintext = decryptor.update(ciphertext) + decryptor.finalize()

    return plaintext.decode()


def test_encode_decode():
    """
    Test case to take input, encode, decode, and present the output.
    """
    # Take user input
    message = input("Enter a message: ")
    password = input("Enter a password: ")

    # Encode the message
    encoded_message = encode(message, password)
    print("Encoded message:", encoded_message)

    # Decode the message
    decoded_message = decode(encoded_message, password)
    print("Decoded message:", decoded_message)


# Run the test case
test_encode_decode()

Here’s a written summary of the functions in the code:

  1. encode(message, password): This function takes a message and a password as input and encodes the message using AES-256 GCM encryption. It generates a secure encryption key by deriving it from the provided password using PBKDF2 key derivation function. The message is then encrypted using the key and a randomly generated Initialization Vector (IV). The encoded message, which includes the IV, ciphertext, and authentication tag, is returned as a Base64-encoded string.
  2. decode(encoded_message, password): This function takes an encoded message and a password as input and decodes the message using AES-256 GCM decryption. It derives the same encryption key from the provided password using PBKDF2 key derivation function. The encoded message, which is in Base64 format, is decoded. The IV, ciphertext, and authentication tag are extracted from the decoded message, and a decryption operation is performed using the key, IV, and tag. The decoded message is returned as a string.
  3. test_encode_decode(): This function serves as a test case for the encoding and decoding functionality. It prompts the user to enter a message and a password. It then calls the encode function to encode the message and the decode function to decode the encoded message. Finally, it prints the encoded and decoded messages for verification.

These functions work together to demonstrate how to encode a message using AES-256 GCM encryption and then decode it back to its original form using a password for encryption and decryption operations.

Encode Example

The updated version of the encode function that takes input text and password, and outputs the encoded message to a file:

import os
import base64
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.backends import default_backend

def encode(message, password, output_file):
    """
    Encodes a message using AES-256 GCM encryption and writes the encoded message to a file.

    Args:
        message (str): The message to be encoded.
        password (str): The password used for key derivation.
        output_file (str): The path to the output file where the encoded message will be written.

    Raises:
        ValueError: If an invalid key size is encountered.
        IOError: If there are any issues writing to the output file.

    """
    # Generate a secure encryption key using a password-based key derivation function (PBKDF2)
    salt = b'\x12\x34\x56\x78\x9a\xbc\xde\xf0'  # Salt for key derivation
    backend = default_backend()
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,  # AES-256 key length
        salt=salt,
        iterations=100000,  # Number of iterations for key stretching
        backend=backend
    )
    key = base64.urlsafe_b64encode(kdf.derive(password.encode()))

    # Decode the Base64-encoded key
    key = base64.urlsafe_b64decode(key)

    # Generate a random Initialization Vector (IV)
    iv = os.urandom(16)  # 16 bytes for AES-256

    # Create an AES-GCM cipher instance with the generated key and IV
    cipher = Cipher(algorithms.AES(key), modes.GCM(iv), backend=backend)
    encryptor = cipher.encryptor()

    # Encrypt the message
    ciphertext = encryptor.update(message.encode()) + encryptor.finalize()

    # Get the authentication tag
    tag = encryptor.tag

    # Combine the IV, ciphertext, and tag
    encoded_message = base64.urlsafe_b64encode(iv + ciphertext + tag).decode()

    # Write the encoded message to the output file
    try:
        with open(output_file, "w") as file:
            file.write(encoded_message)
        print("Encoded message written to", output_file)
    except IOError:
        print("Error writing encoded message to file:", output_file)


# Example usage
message = input("Enter a message: ")
password = input("Enter a password: ")
output_file = "encoded_message.txt"

encode(message, password, output_file)

In this code, the encode function accepts an additional output_file parameter, which specifies the path to the file where the encoded message will be written. The function writes the encoded message to the file specified, and if successful, it prints a message indicating the location of the output file.

You can customize the output_file variable to specify your desired file name and path. When you run the code, it will prompt you to enter a message and a password, and then it will encode the message and write the encoded message to the specified output file.

Decode Example

The decode function that takes an input message file containing the encoded message and outputs the decoded text:

import base64
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.backends import default_backend

def decode(input_file, password):
    """
    Decodes an encoded message from a file using AES-256 GCM decryption and returns the decoded text.

    Args:
        input_file (str): The path to the input file containing the encoded message.
        password (str): The password used for key derivation.

    Returns:
        str: The decoded text.

    Raises:
        ValueError: If an invalid key size is encountered.
        IOError: If there are any issues reading from the input file.

    """
    # Generate a secure encryption key using a password-based key derivation function (PBKDF2)
    salt = b'\x12\x34\x56\x78\x9a\xbc\xde\xf0'  # Salt for key derivation
    backend = default_backend()
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,  # AES-256 key length
        salt=salt,
        iterations=100000,  # Number of iterations for key stretching
        backend=backend
    )
    key = base64.urlsafe_b64encode(kdf.derive(password.encode()))

    # Decode the Base64-encoded key
    key = base64.urlsafe_b64decode(key)

    # Read the encoded message from the input file
    try:
        with open(input_file, "r") as file:
            encoded_message = file.read()
    except IOError:
        print("Error reading input file:", input_file)
        return

    # Decode the Base64-encoded message
    decoded_message = base64.urlsafe_b64decode(encoded_message)

    # Extract the IV, ciphertext, and tag from the decoded message
    iv = decoded_message[:16]  # 16 bytes for AES-256
    ciphertext = decoded_message[16:-16]  # Remove the IV and tag from the message
    tag = decoded_message[-16:]  # Last 16 bytes are the tag

    # Create an AES-GCM cipher instance with the key, IV, and tag
    cipher = Cipher(algorithms.AES(key), modes.GCM(iv, tag), backend=backend)
    decryptor = cipher.decryptor()

    # Decrypt the ciphertext
    plaintext = decryptor.update(ciphertext) + decryptor.finalize()

    return plaintext.decode()


# Example usage
input_file = "encoded_message.txt"
password = input("Enter the password: ")

decoded_text = decode(input_file, password)
if decoded_text:
    print("Decoded text:", decoded_text)

In this code, the decode function accepts an input_file parameter, which specifies the path to the file containing the encoded message. The function reads the encoded message from the input file, decodes it, and then performs AES-256 GCM decryption to retrieve the original text. The decoded text is returned as a string.

You can customize the input_file variable to point to the file that contains the encoded message. When you run the code, it will prompt you to enter the password.

The function will then decode the message from the input file and print the decoded text if successful.

Encode GUI

The updated version of the encode function that includes a simple graphical user interface (GUI) using the Tkinter library to capture the text input, password, and save the encoded message to a file:

import os
import base64
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.backends import default_backend
import tkinter as tk
from tkinter import filedialog


def encode_with_gui():
    """
    Encodes a message using AES-256 GCM encryption with a GUI for input and file save.

    """
    # Create the GUI window
    window = tk.Tk()
    window.title("Message Encoder")
    window.geometry("400x200")

    # Create input fields for message and password
    message_label = tk.Label(window, text="Enter the message:")
    message_label.pack()
    message_entry = tk.Entry(window, width=40)
    message_entry.pack()

    password_label = tk.Label(window, text="Enter the password:")
    password_label.pack()
    password_entry = tk.Entry(window, show="*", width=40)
    password_entry.pack()

    # Function to handle the Encode button click
    def encode_button_click():
        message = message_entry.get()
        password = password_entry.get()

        # Check if both message and password are provided
        if message and password:
            # Encode the message
            encoded_message = encode(message, password)

            # Save the encoded message to a file
            save_file_path = filedialog.asksaveasfilename(defaultextension=".txt")
            if save_file_path:
                try:
                    with open(save_file_path, "w") as file:
                        file.write(encoded_message)
                    result_label.config(text="Message encoded and saved to file successfully!")
                except IOError:
                    result_label.config(text="Error writing encoded message to file.")
            else:
                result_label.config(text="File save operation cancelled.")
        else:
            result_label.config(text="Please enter both message and password.")

    # Create the Encode button
    encode_button = tk.Button(window, text="Encode", command=encode_button_click)
    encode_button.pack()

    # Create a label for displaying the result
    result_label = tk.Label(window, text="")
    result_label.pack()

    # Run the GUI main loop
    window.mainloop()


def encode(message, password):
    """
    Encodes a message using AES-256 GCM encryption and returns the encoded message.

    Args:
        message (str): The message to be encoded.
        password (str): The password used for key derivation.

    Returns:
        str: The encoded message.

    Raises:
        ValueError: If an invalid key size is encountered.

    """
    # Generate a secure encryption key using a password-based key derivation function (PBKDF2)
    salt = b'\x12\x34\x56\x78\x9a\xbc\xde\xf0'  # Salt for key derivation
    backend = default_backend()
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,  # AES-256 key length
        salt=salt,
        iterations=100000,  # Number of iterations for key stretching
        backend=backend
    )
    key = base64.urlsafe_b64encode(kdf.derive(password.encode()))

    # Decode the Base64-encoded key
    key = base64.urlsafe_b64decode(key)

    # Generate a random Initialization Vector (IV)
    iv = os.urandom(16)  # 16 bytes for AES-256

    # Create an AES-GCM cipher instance with the generated key and IV
    cipher = Cipher(algorithms.AES(key), modes.GCM(iv), backend=backend)
    encryptor = cipher.encryptor()

    # Encrypt the message
    ciphertext = encryptor.update(message.encode()) + encryptor.finalize()

    # Get the authentication tag
    tag = encryptor.tag

    # Combine the IV, ciphertext, and tag
    encoded_message = base64.urlsafe_b64encode(iv + ciphertext + tag).decode()

    return encoded_message


# Run the encode_with_gui function to start the GUI
encode_with_gui()

When you run this code, it will open a GUI window where you can enter the message and password. After clicking the “Encode” button, it will prompt you to choose the file path where the encoded message should be saved. Once the file is saved, a message will be displayed indicating whether the encoding and file saving were successful or if any errors occurred.

Note: Make sure to have the Tkinter library installed to run the GUI successfully.

Decode GUI

Here’s an updated version of the decode function that includes a simple graphical user interface (GUI) using the Tkinter library to open a file, enter the password, and read the encoded message from the file:

import tkinter as tk
from tkinter import filedialog, messagebox
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.backends import default_backend
import base64

def decode_with_gui():
    def decode_button_click():
        password = password_entry.get()

        try:
            selected_file = filedialog.askopenfilename()
            with open(selected_file, 'r') as file:
                encoded_message = file.read().strip()
                decoded_text = decode(encoded_message, password)
                decoded_text_entry.delete(1.0, tk.END)
                decoded_text_entry.insert(tk.END, decoded_text)
        except FileNotFoundError:
            messagebox.showerror("File Error", "No file selected. Please choose a file.")
        except ValueError:
            messagebox.showerror("Decryption Error", "Invalid password. Please try again.")

    # Create the GUI window
    window = tk.Tk()
    window.title("Decode Message")
    window.geometry("400x300")

    # Create input fields and labels
    password_label = tk.Label(window, text="Password:")
    password_label.pack()
    password_entry = tk.Entry(window, show="*")
    password_entry.pack()

    # Create the decode button
    decode_button = tk.Button(window, text="Decode", command=decode_button_click)
    decode_button.pack()

    # Create the decoded text box
    decoded_text_label = tk.Label(window, text="Decoded Text:")
    decoded_text_label.pack()
    decoded_text_entry = tk.Text(window, height=10, width=40)
    decoded_text_entry.pack()

    # Run the GUI window
    window.mainloop()


def read_file(file_path):
    """
    Reads the contents of a file.

    Args:
        file_path (str): The path to the file.

    Returns:
        str: The contents of the file.

    """
    try:
        with open(file_path, "r") as file:
            content = file.read()
        return content.strip()
    except IOError:
        return None


def decode(encoded_message, password):
    """
    Decodes an encoded message using AES-256 GCM decryption and returns the original message.

    Args:
        encoded_message (str): The encoded message.
        password (str): The password used for key derivation.

    Returns:
        str: The decoded message.

    Raises:
        ValueError: If an invalid key size is encountered or the password or encoded message is incorrect.

    """
    # Generate a secure encryption key using a password-based key derivation function (PBKDF2)
    salt = b'\x12\x34\x56\x78\x9a\xbc\xde\xf0'  # Salt for key derivation
    backend = default_backend()
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,  # AES-256 key length
        salt=salt,
        iterations=100000,  # Number of iterations for key stretching
        backend=backend
    )
    key = base64.urlsafe_b64encode(kdf.derive(password.encode()))

    # Decode the Base64-encoded key
    key = base64.urlsafe_b64decode(key)

    # Decode the Base64-encoded message
    decoded_message = base64.urlsafe_b64decode(encoded_message)

    # Extract the IV, ciphertext, and tag from the decoded message
    iv = decoded_message[:16]  # 16 bytes for AES-256
    ciphertext = decoded_message[16:-16]  # Remove the IV and tag from the message
    tag = decoded_message[-16:]  # Last 16 bytes are the tag

    # Create an AES-GCM cipher instance with the key, IV, and tag
    cipher = Cipher(algorithms.AES(key), modes.GCM(iv, tag), backend=backend)
    decryptor = cipher.decryptor()

    # Decrypt the ciphertext
    plaintext = decryptor.update(ciphertext)
    plaintext += decryptor.finalize()

    return plaintext.decode()


# Run the decode_with_gui function to start the GUI
decode_with_gui()

The main function, decode_with_gui(), provides a GUI window for decoding a message from a file. It defines an event handler, decode_button_click(), to handle the decoding process when the ‘Decode’ button is clicked. The function uses filedialog.askopenfilename() to allow the user to select a file, reads the encoded message from the file, attempts to decode it using the provided password, and displays the decoded text in a text box.

What have Learnt ?

You have learned several key concepts and implemented code related to encryption and decryption using the AES-256 GCM algorithm.

Here’s a summary of what you have learned:

  1. AES-256 GCM Algorithm: AES-256 GCM is a cryptographic algorithm used for secure encryption and decryption of data. It combines the AES-256 symmetric encryption algorithm with the Galois/Counter Mode (GCM) for authenticated encryption.
  2. Encoding and Decoding Functions: You have implemented functions for encoding and decoding messages using the AES-256 GCM algorithm. The encode() function takes a message and password as input, encrypts the message, and returns the encoded message. The decode() function takes an encoded message and password as input, decrypts the message, and returns the decoded plaintext.
  3. Key Derivation and Initialization: The encoding and decoding functions generate a secure encryption key using a password-based key derivation function (PBKDF2) and derive a random Initialization Vector (IV) for each encryption operation.
  4. Base64 Encoding: The encoded messages are represented as Base64 strings, which are safe for storing and transmitting binary data.
  5. GUI Integration: You have integrated a simple GUI using the Tkinter library to provide a user-friendly interface for inputting messages, passwords, and selecting files. The GUI allows users to encode and decode messages by interacting with buttons and text fields.
  6. Error Handling: Error handling has been added to handle scenarios such as file selection errors and incorrect passwords. Appropriate error messages are displayed to the user in case of such errors.

Overall, you have gained an understanding of AES-256 GCM encryption, implemented encoding and decoding functions, integrated a GUI for user interaction, and handled errors gracefully. These skills provide a foundation for working with encryption algorithms and building secure communication systems.