Skip to content

coreyleavitt/oxifish

Repository files navigation

oxifish

Python bindings for the RustCrypto Twofish block cipher implementation.

Installation

pip install oxifish

Usage

CBC Mode (with padding)

import 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 + ciphertext

Streaming API

For 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()

CTR Mode (no padding needed)

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)

ECB Mode (single blocks only)

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.

Available Modes

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

Padding Styles

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 padding
  • PaddingStyle.AnsiX923 - ANSI X9.23 padding

Security

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.

Development

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
pytest

License

MIT 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.

About

Python bindings for the RustCrypto Twofish block cipher implementation

Resources

License

Security policy

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •