Encrypting and Decrypting information with cryptography

Encrypting and Decrypting information with cryptography

The cryptography module in Python is a widely used library for providing cryptographic recipes and primitives. It is designed to be easy to use and follows the principle of “cryptography should be easy.” The module is focused on providing strong, secure cryptographic algorithms and implementations.

Here are some key features and components of the cryptography module:

  1. Fernet:

    • Fernet is a symmetric encryption algorithm provided by the cryptography library.
    • It ensures that a message encrypted using it cannot be manipulated or read without the key.

    Example:

    from cryptography.fernet import Fernet
    
    key = Fernet.generate_key()
    cipher_suite = Fernet(key)
    
    encrypted_text = cipher_suite.encrypt(b"Hello, world!")
    decrypted_text = cipher_suite.decrypt(encrypted_text)
    
  2. Hazardous Materials:

    • The library separates “safe” and “unsafe” cryptographic operations.
    • The “hazmat” (hazardous materials) subpackage contains low-level cryptographic primitives for advanced use cases.

    Example:

    from cryptography.hazmat.primitives import hashes
    from cryptography.hazmat.backends import default_backend
    
    digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
    digest.update(b"Hello, world!")
    hashed_message = digest.finalize()
    
  3. X.509 and Asymmetric Cryptography:

    • Provides tools for working with X.509 certificates.
    • Supports asymmetric algorithms like RSA and Elliptic Curve Cryptography (ECC).

    Example:

    from cryptography.hazmat.primitives import serialization
    from cryptography.hazmat.primitives.asymmetric import rsa
    
    private_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=2048,
        backend=default_backend()
    )
    
    private_key_pem = private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.TraditionalOpenSSL,
        encryption_algorithm=serialization.NoEncryption()
    )
    
  4. Password Hashing:

    • Provides secure password hashing functions.

    Example:

    from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
    from cryptography.hazmat.backends import default_backend
    
    password = b"my_secure_password"
    salt = b"random_salt"
    
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        iterations=100000,
        salt=salt,
        length=32,
        backend=default_backend()
    )
    
    key = kdf.derive(password)
    
  5. Key Derivation Functions (KDFs):

    • Provides KDFs for deriving cryptographic keys from passwords.

    Example:

    from cryptography.hazmat.primitives.kdf.hkdf import HKDF
    from cryptography.hazmat.backends import default_backend
    
    secret_key = b"my_secret_key"
    salt = b"random_salt"
    
    kdf = HKDF(
        algorithm=hashes.SHA256(),
        length=32,
        salt=salt,
        info=b"additional_info",
        backend=default_backend()
    )
    
    derived_key = kdf.derive(secret_key)
    

Symmetric encryption with the fernet package

Python
from cryptography.fernet import Fernet

key = Fernet.generate_key()
cipher_suite = Fernet(key)
print("Key "+str(cipher_suite))

message = "Secret message".encode("utf8")
cipher_text = cipher_suite.encrypt(message)
plain_text = cipher_suite.decrypt(cipher_text)

print("Cipher text: "+str(cipher_text.decode()))
print("Plain text: "+str(plain_text.decode()))

It demonstrates the use of the cryptography.fernet module to encrypt and decrypt a message using the Fernet symmetric encryption algorithm. Fernet is an implementation of symmetric (also known as “secret key”) authenticated cryptography.

Break down the code step by step:

  1. Key Generation:

    key = Fernet.generate_key()
    cipher_suite = Fernet(key)
    print("Key "+str(cipher_suite))
    
    • Fernet.generate_key(): Generates a new Fernet key. The key is used for both encryption and decryption.
    • Fernet(key): Creates a Fernet object using the generated key.

    The generated key is printed for informational purposes.

  2. Encryption:

    message = "Secret message".encode("utf8")
    cipher_text = cipher_suite.encrypt(message)
    
    • message = "Secret message".encode("utf8"): Converts the string “Secret message” into bytes using UTF-8 encoding.
    • cipher_suite.encrypt(message): Encrypts the message using the Fernet key, producing the cipher text.
  3. Decryption:

    plain_text = cipher_suite.decrypt(cipher_text)
    
    • cipher_suite.decrypt(cipher_text): Decrypts the cipher text using the Fernet key, producing the original message.
  4. Output:

    print("Cipher text: "+str(cipher_text.decode()))
    print("Plain text: "+str(plain_text.decode()))
    
    • cipher_text.decode(): Decodes the encrypted bytes into a string for display.
    • plain_text.decode(): Decodes the decrypted bytes into the original string for display.
Python
from cryptography.fernet import Fernet

def generate_key():
    key = Fernet.generate_key()
    with open("secret.key", "wb") as key_file:
        key_file.write(key)

def load_key():
    return open("secret.key", "rb").read()

def encrypt_message(message):
    key = load_key()
    encoded_message = message.encode()
    fernet = Fernet(key)
    encrypted_message = fernet.encrypt(encoded_message)
    return encrypted_message

def decrypt_message(encrypted_message):
    key = load_key()
    fernet = Fernet(key)
    decrypted_message = fernet.decrypt(encrypted_message)
    return decrypted_message.decode()

if __name__ == "__main__":
    generate_key()
    message_encrypted = encrypt_message("encrypt this message")
    print('Message encrypted:', message_encrypted)
    print('Message decrypted:',decrypt_message(message_encrypted))
  1. Key Generation:

    def generate_key():
        key = Fernet.generate_key()
        with open("secret.key", "wb") as key_file:
            key_file.write(key)
    
    • generate_key(): Generates a new Fernet key and saves it to a file named “secret.key” in binary mode.
  2. Key Loading:

    def load_key():
        return open("secret.key", "rb").read()
    
    • load_key(): Reads the Fernet key from the “secret.key” file in binary mode and returns it.
  3. Encryption:

    def encrypt_message(message):
        key = load_key()
        encoded_message = message.encode()
        fernet = Fernet(key)
        encrypted_message = fernet.encrypt(encoded_message)
        return encrypted_message
    
    • encrypt_message(message): Encrypts the input message using the loaded Fernet key.
  4. Decryption:

    def decrypt_message(encrypted_message):
        key = load_key()
        fernet = Fernet(key)
        decrypted_message = fernet.decrypt(encrypted_message)
        return decrypted_message.decode()
    
    • decrypt_message(encrypted_message): Decrypts the input encrypted message using the loaded Fernet key.
  5. Main Execution:

    if __name__ == "__main__":
        generate_key()
        message_encrypted = encrypt_message("encrypt this message")
        print('Message encrypted:', message_encrypted)
        print('Message decrypted:', decrypt_message(message_encrypted))
    
    • The generate_key() function is called to create a new key and save it to “secret.key”.
    • A sample message is encrypted using encrypt_message() and then decrypted using decrypt_message(). The original and decrypted messages are printed for verification.

Symmetric encryption with the ciphers package

Python
import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

backend = default_backend()
key = os.urandom(32)
iv = os.urandom(16)
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)

encryptor = cipher.encryptor()
print(encryptor)

message_encrypted = encryptor.update("a secret message".encode("utf8"))

print("Cipher text: "+str(message_encrypted))
cipher_text =  message_encrypted + encryptor.finalize()

decryptor = cipher.decryptor()

print("Plain text: "+str(decryptor.update(cipher_text).decode()))

Explanation of the code:

  1. Importing Required Modules:

    import os
    from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
    from cryptography.hazmat.backends import default_backend
    
    • The code imports the necessary modules from the cryptography library.
  2. Generating Key and IV:

    backend = default_backend()
    key = os.urandom(32)
    iv = os.urandom(16)
    
    • default_backend(): Obtains the default cryptographic backend.
    • os.urandom(): Generates random bytes for the key and IV.
  3. Creating Cipher Object:

    cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
    
    • Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend): Creates a Cipher object using AES in CBC mode with the specified key and IV.
  4. Encryption:

    encryptor = cipher.encryptor()
    message_encrypted = encryptor.update("a secret message".encode("utf8"))
    
    • cipher.encryptor(): Creates an encryptor object.
    • encryptor.update(): Encrypts the input message.
  5. Finalizing Encryption:

    cipher_text = message_encrypted + encryptor.finalize()
    
    • encryptor.finalize(): Finalizes the encryption process.
  6. Decryption:

    decryptor = cipher.decryptor()
    plain_text = decryptor.update(cipher_text).decode()
    
    • cipher.decryptor(): Creates a decryptor object.
    • decryptor.update(): Decrypts the ciphertext.
  7. Printing Results:

    print("Cipher text: " + str(cipher_text))
    print("Plain text: " + plain_text)
    
    • The final ciphertext and the decrypted plaintext are printed for verification.

Encryption with the PBKDF2 submodule

Python
from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

import base64
import os

password = "password".encode("utf8")

salt = os.urandom(16)
pbkdf = PBKDF2HMAC(algorithm=hashes.SHA256(),length=32,salt=salt,iterations=100000,backend=default_backend())

key = pbkdf.derive(password)

pbkdf = PBKDF2HMAC(algorithm=hashes.SHA256(),length=32,salt=salt,iterations=100000,backend=default_backend())

pbkdf.verify(password, key)

key = base64.urlsafe_b64encode(key)
fernet = Fernet(key)
token = fernet.encrypt("Secret message".encode("utf8"))

print("Token: "+str(token))
print("Message: "+str(fernet.decrypt(token).decode()))

Explanation:

  1. Password and Salt:

    • The password is converted to bytes (password = "password".encode("utf8")).
    • A random 16-byte salt is generated using os.urandom(16).
  2. PBKDF2 Key Derivation:

    • PBKDF2HMAC is initialized with SHA256 as the hash function, the specified key length (32 bytes), the generated salt, and the iteration count.
    • The key is derived using the derive method.
  3. Password Verification:

    • The verify method is used to verify the password against the derived key.
  4. Key Encoding:

    • The derived key is URL-safe base64 encoded using base64.urlsafe_b64encode.
  5. Fernet Encryption:

    • A Fernet cipher is initialized with the encoded key.
    • A message (“Secret message”) is encrypted using encrypt and stored in the token variable.
  6. Print Results:

    • The encrypted token and the decrypted message are printed.
Total
4
Shares

Leave a Reply

Previous Post
Encrypting and encrypting information with pycryptodome

Encrypting and encrypting information with pycryptodome

Next Post
Steganography techniques for hiding information in images

Steganography techniques for hiding information in images

Related Posts