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: pycryptodome provides 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()