Introduction to Basic Cryptography with Python: A Beginner's Guide

administrator   20 May 2024



Introduction

Cryptography is essential for securing data in our digital world. It enables us to protect sensitive information from unauthorized access, ensuring privacy and security. In this tutorial, we will explore the basics of cryptography and demonstrate how to implement simple cryptographic techniques using Python. By the end of this guide, you will have a fundamental understanding of cryptographic concepts and how to apply them in your Python projects.

What is Cryptography?

Cryptography is the practice of securing information by transforming it into an unreadable format, so only those with the correct key can decode and understand it. Key concepts in cryptography include:
  • Encryption: Converting plaintext into ciphertext using an algorithm and a key.
  • Decryption: Reversing the process to transform ciphertext back into plaintext using the key.
  • Symmetric Key Cryptography: Using the same key for both encryption and decryption.
  • Asymmetric Key Cryptography: Using a pair of keys (public and private) for encryption and decryption.

Setting Up Your Python Environment

Before we begin, ensure you have Python installed on your system. You can download it from python.org. Additionally, we will use the cryptography library, which can be installed using pip:
pip install cryptography


Symmetric Key Encryption

Symmetric key encryption uses the same key for both encryption and decryption. One common algorithm for symmetric encryption is the Advanced Encryption Standard (AES). Let's see how to use AES with the cryptography library.

Encrypting Data

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend
import os

def encrypt(plaintext, key):
# Generate a random initialization vector (IV)
iv = os.urandom(16)

# Create an AES cipher object
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
encryptor = cipher.encryptor()

# Pad the plaintext to ensure it is a multiple of the block size
padder = padding.PKCS7(algorithms.AES.block_size).padder()
padded_plaintext = padder.update(plaintext) + padder.finalize()

# Encrypt the padded plaintext
ciphertext = encryptor.update(padded_plaintext) + encryptor.finalize()

return iv + ciphertext

key = os.urandom(32) # AES-256 requires a 32-byte key
plaintext = b"Hello, World!"
ciphertext = encrypt(plaintext, key)
print(f"Ciphertext: {ciphertext}")

Decrypting Data

def decrypt(ciphertext, key):

# Extract the IV from the beginning of the ciphertext
iv = ciphertext[:16]
actual_ciphertext = ciphertext[16:]

# Create an AES cipher object
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
decryptor = cipher.decryptor()

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

# Unpad the plaintext
unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
plaintext = unpadder.update(padded_plaintext) + unpadder.finalize()

return plaintext

decrypted_plaintext = decrypt(ciphertext, key) # example
print(f"Decrypted plaintext: {decrypted_plaintext}")

Asymmetric Key Encryption

Asymmetric key encryption uses a pair of keys: a public key for encryption and a private key for decryption. One widely-used algorithm for asymmetric encryption is RSA. Let's explore how to use RSA with the cryptography library.

Generating Keys

from cryptography.hazmat.primitives.asymmetric import rsa

from cryptography.hazmat.primitives import serialization

'''
Generate a private key
'''
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)

'''
Generate the corresponding public key
'''
public_key = private_key.public_key()

'''
Serialize and save the keys
'''
private_pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)

public_pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)

with open("private_key.pem", "wb") as f:
f.write(private_pem)

with open("public_key.pem", "wb") as f:
f.write(public_pem)

Encrypting Data

from cryptography.hazmat.primitives.asymmetric import padding

from cryptography.hazmat.primitives import hashes

def encrypt_asymmetric(plaintext, public_key):
ciphertext = public_key.encrypt(
plaintext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return ciphertext

'''
Example usage
'''
ciphertext = encrypt_asymmetric(plaintext, public_key)
print(f"Ciphertext: {ciphertext}")

Decrypting Data

def decrypt_asymmetric(ciphertext, private_key):

plaintext = private_key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return plaintext

'''
Example usage
'''
decrypted_plaintext = decrypt_asymmetric(ciphertext, private_key)
print(f"Decrypted plaintext: {decrypted_plaintext}")

Conclusion

In this tutorial, we covered the basics of cryptography, including symmetric and asymmetric encryption, using Python and the cryptography library. These foundational concepts and techniques will help you secure your data and protect sensitive information in your applications. As you advance, consider exploring more complex cryptographic techniques and best practices to further enhance your security knowledge.