PyCryptodomeX
PyCryptodomeX is a self-contained Python package providing low-level cryptographic primitives. It is a fork of the unmaintained PyCrypto library, offering numerous enhancements like authenticated encryption modes, Hybrid Public Key Encryption (HPKE), accelerated AES, and elliptic curve cryptography. It is actively maintained, with version 3.23.0 being the latest, and releases occur frequently. It supports Python 2.7, Python 3.7 and newer, and PyPy.
Warnings
- breaking Support for Python 3.6 was removed in PyCryptodomeX version 3.22.0. Users on Python 3.6 must use an older version (<= 3.21.x) or upgrade their Python interpreter.
- gotcha PyCryptodomeX imports its modules under the `Cryptodome` namespace, not `Crypto`. Attempting to import from `Crypto` (e.g., `from Crypto.Cipher import AES`) will result in a `ModuleNotFoundError` if `pycryptodome` (which uses `Crypto`) is not installed, or can lead to subtle bugs and security issues if both `pycryptodome` and `pycryptodomex` are present, as `Crypto` might resolve to the wrong package.
- deprecated ECB (Electronic Codebook) mode for symmetric ciphers (e.g., AES) is no longer the default and is explicitly discouraged for most uses due to its lack of semantic security. Since version 3.5.0, `AES.new(key)` will raise an error, requiring the mode to be explicitly specified.
- breaking Older versions of PyCryptodome (prior to v3.19.1) had a side-channel leakage vulnerability in OAEP decryption that could be exploited to carry out a Manger attack. This was fixed in v3.19.1.
- gotcha In version 3.22.0, CCM ciphers were updated to fail before encrypting or decrypting data if the data length exceeds the limit imposed by the nonce length. This prevents potential issues with integrity and confidentiality.
- gotcha An infinite loop issue with RC4 for data larger than 4GB was resolved in version 3.22.0. Users processing very large data with RC4 in older versions may encounter this.
Install
-
pip install pycryptodomex
Imports
- AES
from Cryptodome.Cipher import AES
- get_random_bytes
from Cryptodome.Random import get_random_bytes
- PKCS7
from Cryptodome.Util.Padding import PKCS7
Quickstart
from Cryptodome.Cipher import AES
from Cryptodome.Random import get_random_bytes
from Cryptodome.Util.Padding import pad, unpad
# --- Encryption ---
# Generate a random 16-byte key for AES-128
key = get_random_bytes(16)
# Generate a random 16-byte IV for CBC mode
iv = get_random_bytes(16)
# The data to encrypt must be bytes
data_to_encrypt = b"My secret message that needs to be encrypted."
# Create an AES cipher object in CBC mode
cipher = AES.new(key, AES.MODE_CBC, iv)
# Pad the data to be a multiple of the block size (16 bytes for AES)
padded_data = pad(data_to_encrypt, AES.block_size)
# Encrypt the padded data
ciphertext = cipher.encrypt(padded_data)
print(f"Original data: {data_to_encrypt}")
print(f"Key (hex): {key.hex()}")
print(f"IV (hex): {iv.hex()}")
print(f"Ciphertext (hex): {ciphertext.hex()}")
# --- Decryption ---
# In a real scenario, key, iv, and ciphertext would be transmitted
# to the receiver. For this example, we reuse them.
# Create a new AES cipher object for decryption (same key and IV)
decipher = AES.new(key, AES.MODE_CBC, iv)
# Decrypt the ciphertext
decrypted_padded_data = decipher.decrypt(ciphertext)
# Unpad the decrypted data to get the original plaintext
decrypted_data = unpad(decrypted_padded_data, AES.block_size)
print(f"Decrypted data: {decrypted_data}")
assert decrypted_data == data_to_encrypt
print("Encryption and decryption successful!")