Python bindings for the RustCrypto Twofish block cipher implementation.
pip install oxifishimport secrets
from oxifish import TwofishCBC, pad, unpad, PaddingStyle
key = secrets.token_bytes(16) # 16, 24, or 32 bytes
iv = secrets.token_bytes(16) # MUST be unique per encryption
cipher = TwofishCBC(key)
# Encrypt with PKCS7 padding
plaintext = b'Hello, World!'
padded = pad(plaintext, cipher.block_size, PaddingStyle.Pkcs7)
ciphertext = cipher.encrypt(padded, iv)
# Decrypt
decrypted = cipher.decrypt(ciphertext, iv)
result = unpad(decrypted, cipher.block_size, PaddingStyle.Pkcs7)
# b'Hello, World!'
# Store IV with ciphertext (IV is not secret)
encrypted_message = iv + ciphertextFor processing large data or when you need incremental encryption:
from oxifish import TwofishCBC, pad, PaddingStyle
cipher = TwofishCBC(key)
# Streaming encryption
enc = cipher.encryptor(iv)
ciphertext = enc.update(pad(chunk1, 16, PaddingStyle.Pkcs7))
ciphertext += enc.update(pad(chunk2, 16, PaddingStyle.Pkcs7))
ciphertext += enc.finalize()
# Streaming decryption
dec = cipher.decryptor(iv)
plaintext = dec.update(ciphertext)
plaintext += dec.finalize()import secrets
from oxifish import TwofishCTR
key = secrets.token_bytes(16)
nonce = secrets.token_bytes(16) # MUST be unique per encryption
cipher = TwofishCTR(key)
ciphertext = cipher.encrypt(b'any length data', nonce)
plaintext = cipher.decrypt(ciphertext, nonce)import secrets
from oxifish import TwofishECB
key = secrets.token_bytes(16)
cipher = TwofishECB(key)
ciphertext = cipher.encrypt_block(b'16 byte block!!')
plaintext = cipher.decrypt_block(ciphertext)Warning: ECB mode does NOT provide semantic security. Use CBC, CTR, or other modes for general encryption.
| Mode | Padding | Use Case |
|---|---|---|
TwofishCBC |
Use pad()/unpad() |
General encryption |
TwofishCTR |
Not needed | Stream encryption |
TwofishCFB |
Not needed | Stream encryption |
TwofishOFB |
Not needed | Stream encryption |
TwofishECB |
N/A (block-level) | Building blocks, compatibility |
Use the standalone pad() and unpad() functions with PaddingStyle:
PaddingStyle.Pkcs7- Standard PKCS#7 padding (recommended)PaddingStyle.Zeros- Zero padding (cannot roundtrip data ending with zeros)PaddingStyle.Iso7816- ISO/IEC 7816-4 paddingPaddingStyle.AnsiX923- ANSI X9.23 padding
This library is primarily intended for compatibility with existing systems that require Twofish, such as KeePass databases.
Note: Twofish is not constant-time due to key-dependent S-boxes. This is fine for local file decryption but not suitable for server-side encryption where timing attacks are feasible. For new projects, prefer AES-GCM or ChaCha20-Poly1305.
See SECURITY.md for vulnerability reporting and details on key zeroization.
Requires Rust and Python 3.10+.
# Install uv if you haven't
curl -LsSf https://astral.sh/uv/install.sh | sh
# Create venv and install maturin
uv venv
source .venv/bin/activate # or .venv\Scripts\activate on Windows
uv pip install maturin
# Build and install in development mode
maturin develop
# Run tests
uv pip install pytest
pytestMIT License. See LICENSE for details.
This project uses the RustCrypto twofish crate which is dual-licensed under MIT/Apache-2.0. We use it under the MIT license.