Python DES Encryption Code Example (Online Runner)
Python DES examples with mode, padding, and encoding controls to mirror the DES tool.
Online calculator: use the site DES tool.
Note: This snippet requires locally installed dependencies and will not run in the online runner.
Calculation method
The DES tool matches the AES controls: ECB/CBC/CFB/OFB/CTR modes, PKCS7 or zero padding for block modes, and hex or base64 ciphertext encodings. This helper mirrors those settings.
Install the dependency first: pip install pycryptodome.
Implementation notes
- Package:
pycryptodomeprovidesCrypto.Cipher.DESandCrypto.Util.Counter. - Implementation: keys and IVs are normalized to 8 bytes, and CTR uses the IV bytes to seed the counter.
- Notes: DES is considered insecure for modern use (56-bit key). Keep it for legacy compatibility only and prefer AES for new designs.
python
from __future__ import annotations
import base64
from typing import Literal
from Crypto.Cipher import DES
from Crypto.Util import Counter
Mode = Literal["ECB", "CBC", "CFB", "OFB", "CTR"]
Padding = Literal["PKCS7", "Zero"]
KeyEncoding = Literal["utf8", "hex"]
CipherEncoding = Literal["hex", "base64"]
BLOCK_SIZE = 8
def _decode_value(value: str, encoding: KeyEncoding) -> bytes:
return value.encode("utf-8") if encoding == "utf8" else bytes.fromhex(value)
def _encode_ciphertext(data: bytes, encoding: CipherEncoding) -> str:
return data.hex() if encoding == "hex" else base64.b64encode(data).decode("ascii")
def _decode_ciphertext(value: str, encoding: CipherEncoding) -> bytes:
return bytes.fromhex(value) if encoding == "hex" else base64.b64decode(value)
def _normalize_key(key: bytes) -> bytes:
return key[:BLOCK_SIZE].ljust(BLOCK_SIZE, b"\x00")
def _normalize_iv(iv: bytes | None) -> bytes:
return (iv or b"")[:BLOCK_SIZE].ljust(BLOCK_SIZE, b"\x00")
def _pkcs7_pad(data: bytes) -> bytes:
pad_len = BLOCK_SIZE - (len(data) % BLOCK_SIZE)
return data + bytes([pad_len] * pad_len)
def _pkcs7_unpad(data: bytes) -> 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) -> 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 _build_cipher(key: bytes, mode: Mode, iv: bytes | None) -> DES:
if mode == "ECB":
return DES.new(key, DES.MODE_ECB)
if mode == "CBC":
return DES.new(key, DES.MODE_CBC, iv=_normalize_iv(iv))
if mode == "CFB":
return DES.new(key, DES.MODE_CFB, iv=_normalize_iv(iv), segment_size=64)
if mode == "OFB":
return DES.new(key, DES.MODE_OFB, iv=_normalize_iv(iv))
counter = Counter.new(64, initial_value=int.from_bytes(_normalize_iv(iv), "big"))
return DES.new(key, DES.MODE_CTR, counter=counter)
def des_encrypt(
plaintext: str,
key: str,
*,
mode: Mode = "CBC",
padding: Padding = "PKCS7",
key_encoding: KeyEncoding = "hex",
iv: str | None = None,
iv_encoding: KeyEncoding = "hex",
output_encoding: CipherEncoding = "base64",
) -> str:
key_bytes = _normalize_key(_decode_value(key, key_encoding))
iv_bytes = _decode_value(iv, iv_encoding) if iv is not None else None
data = plaintext.encode("utf-8")
if mode in {"ECB", "CBC"}:
data = _pkcs7_pad(data) if padding == "PKCS7" else _zero_pad(data)
cipher = _build_cipher(key_bytes, mode, iv_bytes)
encrypted = cipher.encrypt(data)
return _encode_ciphertext(encrypted, output_encoding)
def des_decrypt(
ciphertext: str,
key: str,
*,
mode: Mode = "CBC",
padding: Padding = "PKCS7",
key_encoding: KeyEncoding = "hex",
iv: str | None = None,
iv_encoding: KeyEncoding = "hex",
input_encoding: CipherEncoding = "base64",
) -> str:
key_bytes = _normalize_key(_decode_value(key, key_encoding))
iv_bytes = _decode_value(iv, iv_encoding) if iv is not None else None
data = _decode_ciphertext(ciphertext, input_encoding)
cipher = _build_cipher(key_bytes, mode, iv_bytes)
decrypted = cipher.decrypt(data)
if mode in {"ECB", "CBC"}:
decrypted = _pkcs7_unpad(decrypted) if padding == "PKCS7" else _zero_unpad(decrypted)
return decrypted.decode("utf-8", errors="replace")
# Example usage
key_hex = "0123456789abcdef"
iv_hex = "a1b2c3d4e5f60708"
cipher = des_encrypt(
"hello",
key_hex,
mode="CBC",
padding="PKCS7",
key_encoding="hex",
iv=iv_hex,
iv_encoding="hex",
output_encoding="hex",
)
print(cipher)
plain = des_decrypt(
cipher,
key_hex,
mode="CBC",
padding="PKCS7",
key_encoding="hex",
iv=iv_hex,
iv_encoding="hex",
input_encoding="hex",
)
print(plain)
Complete script (implementation + tests)
python
from __future__ import annotations
import base64
from typing import Literal
from Crypto.Cipher import DES
from Crypto.Util import Counter
Mode = Literal["ECB", "CBC", "CFB", "OFB", "CTR"]
Padding = Literal["PKCS7", "Zero"]
KeyEncoding = Literal["utf8", "hex"]
CipherEncoding = Literal["hex", "base64"]
BLOCK_SIZE = 8
def _decode_value(value: str, encoding: KeyEncoding) -> bytes:
return value.encode("utf-8") if encoding == "utf8" else bytes.fromhex(value)
def _encode_ciphertext(data: bytes, encoding: CipherEncoding) -> str:
return data.hex() if encoding == "hex" else base64.b64encode(data).decode("ascii")
def _decode_ciphertext(value: str, encoding: CipherEncoding) -> bytes:
return bytes.fromhex(value) if encoding == "hex" else base64.b64decode(value)
def _normalize_key(key: bytes) -> bytes:
return key[:BLOCK_SIZE].ljust(BLOCK_SIZE, b"\x00")
def _normalize_iv(iv: bytes | None) -> bytes:
return (iv or b"")[:BLOCK_SIZE].ljust(BLOCK_SIZE, b"\x00")
def _pkcs7_pad(data: bytes) -> bytes:
pad_len = BLOCK_SIZE - (len(data) % BLOCK_SIZE)
return data + bytes([pad_len] * pad_len)
def _pkcs7_unpad(data: bytes) -> 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) -> 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 _build_cipher(key: bytes, mode: Mode, iv: bytes | None) -> DES:
if mode == "ECB":
return DES.new(key, DES.MODE_ECB)
if mode == "CBC":
return DES.new(key, DES.MODE_CBC, iv=_normalize_iv(iv))
if mode == "CFB":
return DES.new(key, DES.MODE_CFB, iv=_normalize_iv(iv), segment_size=64)
if mode == "OFB":
return DES.new(key, DES.MODE_OFB, iv=_normalize_iv(iv))
counter = Counter.new(64, initial_value=int.from_bytes(_normalize_iv(iv), "big"))
return DES.new(key, DES.MODE_CTR, counter=counter)
def des_encrypt(
plaintext: str,
key: str,
*,
mode: Mode = "CBC",
padding: Padding = "PKCS7",
key_encoding: KeyEncoding = "hex",
iv: str | None = None,
iv_encoding: KeyEncoding = "hex",
output_encoding: CipherEncoding = "base64",
) -> str:
key_bytes = _normalize_key(_decode_value(key, key_encoding))
iv_bytes = _decode_value(iv, iv_encoding) if iv is not None else None
data = plaintext.encode("utf-8")
if mode in {"ECB", "CBC"}:
data = _pkcs7_pad(data) if padding == "PKCS7" else _zero_pad(data)
cipher = _build_cipher(key_bytes, mode, iv_bytes)
encrypted = cipher.encrypt(data)
return _encode_ciphertext(encrypted, output_encoding)
def des_decrypt(
ciphertext: str,
key: str,
*,
mode: Mode = "CBC",
padding: Padding = "PKCS7",
key_encoding: KeyEncoding = "hex",
iv: str | None = None,
iv_encoding: KeyEncoding = "hex",
input_encoding: CipherEncoding = "base64",
) -> str:
key_bytes = _normalize_key(_decode_value(key, key_encoding))
iv_bytes = _decode_value(iv, iv_encoding) if iv is not None else None
data = _decode_ciphertext(ciphertext, input_encoding)
cipher = _build_cipher(key_bytes, mode, iv_bytes)
decrypted = cipher.decrypt(data)
if mode in {"ECB", "CBC"}:
decrypted = _pkcs7_unpad(decrypted) if padding == "PKCS7" else _zero_unpad(decrypted)
return decrypted.decode("utf-8", errors="replace")
def run_tests() -> None:
key = "0123456789abcdef"
iv = "a1b2c3d4e5f60708"
cipher = des_encrypt("hello", key, mode="CBC", padding="PKCS7", key_encoding="hex", iv=iv, iv_encoding="hex", output_encoding="hex")
recovered = des_decrypt(cipher, key, mode="CBC", padding="PKCS7", key_encoding="hex", iv=iv, iv_encoding="hex", input_encoding="hex")
assert recovered == "hello"
print("DES tests passed")
if __name__ == "__main__":
run_tests()