Python File Encryption Code Example (Online Runner)
Python file encryption examples for AES/DES with mode, padding, key size, and encoding controls matching the file tool.
Online calculator: use the site File encryption tool.
Note: This snippet requires locally installed dependencies and will not run in the online runner.
Calculation method
The file encryption tool supports AES or DES with the same modes and padding options as the text tools. Use hex or UTF-8 keys and IVs, and remember that stream modes ignore padding.
Install the dependency first: pip install pycryptodome.
Implementation notes
- Package:
pycryptodomeprovides AES/DES ciphers and CTR counters. - Implementation: the helper reads raw file bytes, applies padding only for ECB/CBC, then returns encrypted bytes (no metadata or headers are added).
- Notes: for real files, store the algorithm, IV, and mode alongside the ciphertext. Use a random IV per file; reusing IVs with the same key can leak data.
python
from __future__ import annotations
from pathlib import Path
from typing import Literal
from Crypto.Cipher import AES, DES
from Crypto.Util import Counter
Algorithm = Literal["aes", "des"]
Mode = Literal["ECB", "CBC", "CFB", "OFB", "CTR"]
Padding = Literal["PKCS7", "Zero"]
KeyEncoding = Literal["utf8", "hex"]
AES_BLOCK = 16
DES_BLOCK = 8
def _decode_value(value: str, encoding: KeyEncoding) -> bytes:
return value.encode("utf-8") if encoding == "utf8" else bytes.fromhex(value)
def _pkcs7_pad(data: bytes, block_size: int) -> bytes:
pad_len = block_size - (len(data) % block_size)
return data + bytes([pad_len] * pad_len)
def _pkcs7_unpad(data: bytes, block_size: int) -> bytes:
if not data:
return data
pad_len = data[-1]
if pad_len < 1 or pad_len > block_size:
raise ValueError("Invalid PKCS7 padding")
if data[-pad_len:] != bytes([pad_len] * pad_len):
raise ValueError("Invalid PKCS7 padding")
return data[:-pad_len]
def _zero_pad(data: bytes, block_size: int) -> bytes:
if len(data) % block_size == 0:
return data
pad_len = block_size - (len(data) % block_size)
return data + b"\x00" * pad_len
def _zero_unpad(data: bytes) -> bytes:
return data.rstrip(b"\x00")
def _normalize_key(key: bytes, key_size: int) -> bytes:
return key[:key_size].ljust(key_size, b"\x00")
def _normalize_iv(iv: bytes | None, block_size: int) -> bytes:
return (iv or b"")[:block_size].ljust(block_size, b"\x00")
def _build_cipher(algorithm: Algorithm, key: bytes, mode: Mode, iv: bytes | None):
if algorithm == "aes":
if mode == "ECB":
return AES.new(key, AES.MODE_ECB)
if mode == "CBC":
return AES.new(key, AES.MODE_CBC, iv=_normalize_iv(iv, AES_BLOCK))
if mode == "CFB":
return AES.new(key, AES.MODE_CFB, iv=_normalize_iv(iv, AES_BLOCK), segment_size=128)
if mode == "OFB":
return AES.new(key, AES.MODE_OFB, iv=_normalize_iv(iv, AES_BLOCK))
counter = Counter.new(128, initial_value=int.from_bytes(_normalize_iv(iv, AES_BLOCK), "big"))
return AES.new(key, AES.MODE_CTR, counter=counter)
if mode == "ECB":
return DES.new(key, DES.MODE_ECB)
if mode == "CBC":
return DES.new(key, DES.MODE_CBC, iv=_normalize_iv(iv, DES_BLOCK))
if mode == "CFB":
return DES.new(key, DES.MODE_CFB, iv=_normalize_iv(iv, DES_BLOCK), segment_size=64)
if mode == "OFB":
return DES.new(key, DES.MODE_OFB, iv=_normalize_iv(iv, DES_BLOCK))
counter = Counter.new(64, initial_value=int.from_bytes(_normalize_iv(iv, DES_BLOCK), "big"))
return DES.new(key, DES.MODE_CTR, counter=counter)
def encrypt_file(
path: Path,
*,
algorithm: Algorithm = "aes",
mode: Mode = "CBC",
padding: Padding = "PKCS7",
key: str,
key_encoding: KeyEncoding = "hex",
iv: str | None = None,
iv_encoding: KeyEncoding = "hex",
key_size: int = 32,
) -> bytes:
data = path.read_bytes()
key_bytes = _decode_value(key, key_encoding)
iv_bytes = _decode_value(iv, iv_encoding) if iv is not None else None
if algorithm == "aes":
key_bytes = _normalize_key(key_bytes, key_size)
block_size = AES_BLOCK
else:
key_bytes = _normalize_key(key_bytes, DES_BLOCK)
block_size = DES_BLOCK
if mode in {"ECB", "CBC"}:
data = _pkcs7_pad(data, block_size) if padding == "PKCS7" else _zero_pad(data, block_size)
cipher = _build_cipher(algorithm, key_bytes, mode, iv_bytes)
return cipher.encrypt(data)
def decrypt_file(
path: Path,
*,
algorithm: Algorithm = "aes",
mode: Mode = "CBC",
padding: Padding = "PKCS7",
key: str,
key_encoding: KeyEncoding = "hex",
iv: str | None = None,
iv_encoding: KeyEncoding = "hex",
key_size: int = 32,
) -> bytes:
data = path.read_bytes()
key_bytes = _decode_value(key, key_encoding)
iv_bytes = _decode_value(iv, iv_encoding) if iv is not None else None
if algorithm == "aes":
key_bytes = _normalize_key(key_bytes, key_size)
block_size = AES_BLOCK
else:
key_bytes = _normalize_key(key_bytes, DES_BLOCK)
block_size = DES_BLOCK
cipher = _build_cipher(algorithm, key_bytes, mode, iv_bytes)
plaintext = cipher.decrypt(data)
if mode in {"ECB", "CBC"}:
plaintext = _pkcs7_unpad(plaintext, block_size) if padding == "PKCS7" else _zero_unpad(plaintext)
return plaintext
# Example usage
from pathlib import Path
import tempfile
with tempfile.TemporaryDirectory() as temp_dir:
sample_path = Path(temp_dir) / "sample.bin"
sample_path.write_bytes(b"hello")
encrypted = encrypt_file(
sample_path,
algorithm="aes",
mode="CBC",
padding="PKCS7",
key="00112233445566778899aabbccddeeff",
key_encoding="hex",
iv="0102030405060708090a0b0c0d0e0f10",
iv_encoding="hex",
key_size=16,
)
print(encrypted.hex())
Complete script (implementation + tests)
python
from __future__ import annotations
import tempfile
from pathlib import Path
from typing import Literal
from Crypto.Cipher import AES, DES
from Crypto.Util import Counter
Algorithm = Literal["aes", "des"]
Mode = Literal["ECB", "CBC", "CFB", "OFB", "CTR"]
Padding = Literal["PKCS7", "Zero"]
KeyEncoding = Literal["utf8", "hex"]
AES_BLOCK = 16
DES_BLOCK = 8
def _decode_value(value: str, encoding: KeyEncoding) -> bytes:
return value.encode("utf-8") if encoding == "utf8" else bytes.fromhex(value)
def _pkcs7_pad(data: bytes, block_size: int) -> bytes:
pad_len = block_size - (len(data) % block_size)
return data + bytes([pad_len] * pad_len)
def _pkcs7_unpad(data: bytes, block_size: int) -> bytes:
if not data:
return data
pad_len = data[-1]
if pad_len < 1 or pad_len > block_size:
raise ValueError("Invalid PKCS7 padding")
if data[-pad_len:] != bytes([pad_len] * pad_len):
raise ValueError("Invalid PKCS7 padding")
return data[:-pad_len]
def _zero_pad(data: bytes, block_size: int) -> bytes:
if len(data) % block_size == 0:
return data
pad_len = block_size - (len(data) % block_size)
return data + b"\x00" * pad_len
def _zero_unpad(data: bytes) -> bytes:
return data.rstrip(b"\x00")
def _normalize_key(key: bytes, key_size: int) -> bytes:
return key[:key_size].ljust(key_size, b"\x00")
def _normalize_iv(iv: bytes | None, block_size: int) -> bytes:
return (iv or b"")[:block_size].ljust(block_size, b"\x00")
def _build_cipher(algorithm: Algorithm, key: bytes, mode: Mode, iv: bytes | None):
if algorithm == "aes":
if mode == "ECB":
return AES.new(key, AES.MODE_ECB)
if mode == "CBC":
return AES.new(key, AES.MODE_CBC, iv=_normalize_iv(iv, AES_BLOCK))
if mode == "CFB":
return AES.new(key, AES.MODE_CFB, iv=_normalize_iv(iv, AES_BLOCK), segment_size=128)
if mode == "OFB":
return AES.new(key, AES.MODE_OFB, iv=_normalize_iv(iv, AES_BLOCK))
counter = Counter.new(128, initial_value=int.from_bytes(_normalize_iv(iv, AES_BLOCK), "big"))
return AES.new(key, AES.MODE_CTR, counter=counter)
if mode == "ECB":
return DES.new(key, DES.MODE_ECB)
if mode == "CBC":
return DES.new(key, DES.MODE_CBC, iv=_normalize_iv(iv, DES_BLOCK))
if mode == "CFB":
return DES.new(key, DES.MODE_CFB, iv=_normalize_iv(iv, DES_BLOCK), segment_size=64)
if mode == "OFB":
return DES.new(key, DES.MODE_OFB, iv=_normalize_iv(iv, DES_BLOCK))
counter = Counter.new(64, initial_value=int.from_bytes(_normalize_iv(iv, DES_BLOCK), "big"))
return DES.new(key, DES.MODE_CTR, counter=counter)
def encrypt_file(
path: Path,
*,
algorithm: Algorithm = "aes",
mode: Mode = "CBC",
padding: Padding = "PKCS7",
key: str,
key_encoding: KeyEncoding = "hex",
iv: str | None = None,
iv_encoding: KeyEncoding = "hex",
key_size: int = 32,
) -> bytes:
data = path.read_bytes()
key_bytes = _decode_value(key, key_encoding)
iv_bytes = _decode_value(iv, iv_encoding) if iv is not None else None
if algorithm == "aes":
key_bytes = _normalize_key(key_bytes, key_size)
block_size = AES_BLOCK
else:
key_bytes = _normalize_key(key_bytes, DES_BLOCK)
block_size = DES_BLOCK
if mode in {"ECB", "CBC"}:
data = _pkcs7_pad(data, block_size) if padding == "PKCS7" else _zero_pad(data, block_size)
cipher = _build_cipher(algorithm, key_bytes, mode, iv_bytes)
return cipher.encrypt(data)
def decrypt_file(
path: Path,
*,
algorithm: Algorithm = "aes",
mode: Mode = "CBC",
padding: Padding = "PKCS7",
key: str,
key_encoding: KeyEncoding = "hex",
iv: str | None = None,
iv_encoding: KeyEncoding = "hex",
key_size: int = 32,
) -> bytes:
data = path.read_bytes()
key_bytes = _decode_value(key, key_encoding)
iv_bytes = _decode_value(iv, iv_encoding) if iv is not None else None
if algorithm == "aes":
key_bytes = _normalize_key(key_bytes, key_size)
block_size = AES_BLOCK
else:
key_bytes = _normalize_key(key_bytes, DES_BLOCK)
block_size = DES_BLOCK
cipher = _build_cipher(algorithm, key_bytes, mode, iv_bytes)
plaintext = cipher.decrypt(data)
if mode in {"ECB", "CBC"}:
plaintext = _pkcs7_unpad(plaintext, block_size) if padding == "PKCS7" else _zero_unpad(plaintext)
return plaintext
def run_tests() -> None:
with tempfile.TemporaryDirectory() as temp_dir:
sample_path = Path(temp_dir) / "sample.bin"
sample_path.write_bytes(b"hello")
encrypted = encrypt_file(
sample_path,
algorithm="aes",
mode="CBC",
padding="PKCS7",
key="00112233445566778899aabbccddeeff",
key_encoding="hex",
iv="0102030405060708090a0b0c0d0e0f10",
iv_encoding="hex",
key_size=16,
)
enc_path = Path(temp_dir) / "sample.bin.aes"
enc_path.write_bytes(encrypted)
decrypted = decrypt_file(
enc_path,
algorithm="aes",
mode="CBC",
padding="PKCS7",
key="00112233445566778899aabbccddeeff",
key_encoding="hex",
iv="0102030405060708090a0b0c0d0e0f10",
iv_encoding="hex",
key_size=16,
)
assert decrypted == b"hello"
print("File encryption tests passed")
if __name__ == "__main__":
run_tests()