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:
-
Fernet:
- Fernet is a symmetric encryption algorithm provided by the
cryptographylibrary. - 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) - Fernet is a symmetric encryption algorithm provided by the
-
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() -
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() ) -
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) -
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
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:
-
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 aFernetobject using the generated key.
The generated key is printed for informational purposes.
-
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.
-
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.
-
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.
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))-
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.
-
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.
-
Encryption:
def encrypt_message(message): key = load_key() encoded_message = message.encode() fernet = Fernet(key) encrypted_message = fernet.encrypt(encoded_message) return encrypted_messageencrypt_message(message): Encrypts the input message using the loaded Fernet key.
-
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.
-
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 usingdecrypt_message(). The original and decrypted messages are printed for verification.
- The
Symmetric encryption with the ciphers package
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:
-
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
cryptographylibrary.
- The code imports the necessary modules from the
-
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.
-
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.
-
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.
-
Finalizing Encryption:
cipher_text = message_encrypted + encryptor.finalize()encryptor.finalize(): Finalizes the encryption process.
-
Decryption:
decryptor = cipher.decryptor() plain_text = decryptor.update(cipher_text).decode()cipher.decryptor(): Creates a decryptor object.decryptor.update(): Decrypts the ciphertext.
-
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
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:
-
Password and Salt:
- The password is converted to bytes (
password = "password".encode("utf8")). - A random 16-byte salt is generated using
os.urandom(16).
- The password is converted to bytes (
-
PBKDF2 Key Derivation:
PBKDF2HMACis 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
derivemethod.
-
Password Verification:
- The
verifymethod is used to verify the password against the derived key.
- The
-
Key Encoding:
- The derived key is URL-safe base64 encoded using
base64.urlsafe_b64encode.
- The derived key is URL-safe base64 encoded using
-
Fernet Encryption:
- A Fernet cipher is initialized with the encoded key.
- A message (“Secret message”) is encrypted using
encryptand stored in thetokenvariable.
-
Print Results:
- The encrypted token and the decrypted message are printed.