# PYTHON-CRYPTO-SEC-002: Blowfish Cipher Usage via cryptography Library

> **Severity:** HIGH | **CWE:** CWE-327 | **OWASP:** A02:2021

- **Language:** Python
- **Category:** Cryptography
- **URL:** https://codepathfinder.dev/registry/python/cryptography/PYTHON-CRYPTO-SEC-002
- **Detection:** `pathfinder scan --ruleset python/PYTHON-CRYPTO-SEC-002 --project .`

## Description

This rule detects instantiation of the Blowfish algorithm via the `cryptography`
library's `cryptography.hazmat.primitives.ciphers.algorithms.Blowfish` class.
Blowfish uses a 64-bit block size, which makes it susceptible to the Sweet32
birthday attack once approximately 32GB of data is encrypted under the same key.

The Sweet32 attack (CVE-2016-2183) exploits the birthday paradox: with a 64-bit
block cipher in CBC mode, after 2^32 blocks (roughly 32GB), the probability of
a block collision exceeds 50%. An attacker who can observe enough ciphertext
can exploit these collisions to recover plaintext, including session cookies in
HTTPS traffic. All major browsers and TLS stacks have disabled 64-bit block
cipher suites as a result.

The rule matches `CryptoCipherAlgorithms.method("Blowfish")`. Blowfish's key
flexibility (32 to 448 bits) does not mitigate the block size problem. The
companion rule PYTHON-CRYPTO-SEC-002a covers Blowfish in PyCryptodome.


## Vulnerable Code

```python
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

# Blowfish has a 64-bit block size vulnerable to birthday attacks
bf_key = b'\x00' * 16
cipher = Cipher(algorithms.Blowfish(bf_key), modes.CBC(b'\x00' * 8), backend=default_backend())
```

## Secure Code

```python
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os

# SECURE: AES-256-GCM provides both confidentiality and integrity
key = AESGCM.generate_key(bit_length=256)
aesgcm = AESGCM(key)
nonce = os.urandom(12)
ct = aesgcm.encrypt(nonce, b"sensitive data", associated_data=None)

```

## Detection Rule (Python SDK)

```python
from rules.python_decorators import python_rule
from codepathfinder import calls, flows, QueryType
from codepathfinder.presets import PropagationPresets

class CryptoCipherAlgorithms(QueryType):
    fqns = ["cryptography.hazmat.primitives.ciphers.algorithms"]


@python_rule(
    id="PYTHON-CRYPTO-SEC-002",
    name="Insecure Blowfish Cipher",
    severity="HIGH",
    category="cryptography",
    cwe="CWE-327",
    tags="python,cryptography,blowfish,weak-cipher,CWE-327",
    message="Blowfish has a 64-bit block size vulnerable to birthday attacks. Use AES instead.",
    owasp="A02:2021",
)
def detect_blowfish_cipher():
    """Detects Blowfish cipher usage in cryptography lib."""
    return CryptoCipherAlgorithms.method("Blowfish")
```

## How to Fix

- Replace Blowfish with AES-256-GCM (AESGCM from cryptography.hazmat.primitives.ciphers.aead) for authenticated encryption
- Use ChaCha20-Poly1305 as an alternative when hardware AES acceleration is not available
- If using a block cipher mode manually (CBC, CTR), always pair it with a separate HMAC-SHA256 to detect tampering
- Rotate keys and re-encrypt any data stored with Blowfish under AES-256-GCM
- Audit TLS configuration to confirm no 64-bit block cipher suites remain enabled alongside this code-level fix

## Security Implications

- **Sweet32 Birthday Attack After 32GB of Data:** With a 64-bit block cipher, the birthday bound is 2^32 blocks (~32GB). Once
this threshold is crossed under the same key, block collisions become likely.
In CBC mode, an attacker who observes a collision can XOR the surrounding
blocks to recover the repeated plaintext. For long-lived TLS sessions or bulk
data encryption, this threshold is reachable in hours on a busy server.

- **No Authenticated Encryption -- Padding Oracle Risk:** Blowfish as exposed through the cryptography hazmat API does not provide
authenticated encryption. Using it in CBC mode without a separate MAC creates
padding oracle vulnerability surfaces. An attacker can submit modified
ciphertexts and observe error responses to decrypt content without the key.

- **Deprecated by All Major TLS Implementations:** Following CVE-2016-2183 (Sweet32), all major TLS stacks -- OpenSSL, NSS,
GnuTLS, and Java's JSSE -- disabled 64-bit block cipher suites by default.
Blowfish usage in new code runs counter to the established security consensus
and will be flagged in any TLS configuration audit.

- **Design-Era Limitations Relative to AES:** Blowfish was designed in 1993 as a free alternative to DES. AES was
standardized in 2001 after an open competition and has a 128-bit block
size that eliminates the Sweet32 class of attacks entirely. There is no
scenario where Blowfish is the right choice for new code.


## FAQ

**Q: Blowfish supports up to 448-bit keys. Doesn't that make it secure?**

Key length and block size are separate properties. Blowfish's key size is indeed
flexible and large, but the Sweet32 attack targets the 64-bit block size, not
the key. Once 2^32 blocks are encrypted under any Blowfish key of any length,
the birthday bound is reached and block collisions become exploitable. AES
eliminates this with its 128-bit block size.


**Q: We only encrypt small files with Blowfish. Is the 32GB limit still relevant?**

For truly isolated, small, one-off files with key rotation between each file,
the practical risk is reduced. However, the 32GB limit is a per-key bound --
if the same key is reused across many small files, the total ciphertext volume
accumulates. The safer path is to use AES-GCM, which has a 128-bit block size
and eliminates the Sweet32 class of attacks entirely regardless of data volume.


**Q: How does the Sweet32 attack actually work in practice?**

In CBC mode, each plaintext block is XORed with the previous ciphertext block
before encryption. When two blocks encrypt to the same ciphertext (a birthday
collision), an attacker can XOR the two ciphertext blocks with each other and
with the preceding blocks to recover the plaintext of one block if the other
is known. In HTTPS sessions, an attacker can inject known content (e.g., CSRF
tokens in form data) and wait for the collision to reveal the session cookie.


**Q: How do I handle key rotation if I must keep Blowfish temporarily during migration?**

If an immediate replacement is not feasible, limit each Blowfish key to
encrypting no more than 4GB (well below the 32GB birthday bound), rotate keys
frequently, and add a separate HMAC-SHA256 over each ciphertext to detect
tampering. Document this as a temporary measure with a hard cutoff date and
migrate to AES-256-GCM before that date.


**Q: Does this rule flag Blowfish in bcrypt, which uses Blowfish internally?**

No. The rule specifically matches the Blowfish symmetric cipher constructor via
cryptography.hazmat.primitives.ciphers.algorithms.Blowfish. The bcrypt password
hashing function uses the Blowfish key schedule in a different way and is not
flagged by this rule. Bcrypt is appropriate for password hashing; symmetric
Blowfish is not appropriate for data encryption.


## References

- [CWE-327: Use of a Broken or Risky Cryptographic Algorithm](https://cwe.mitre.org/data/definitions/327.html)
- [Sweet32: Birthday attacks on 64-bit block ciphers in TLS and OpenVPN](https://sweet32.info/)
- [CVE-2016-2183: Sweet32 vulnerability](https://nvd.nist.gov/vuln/detail/CVE-2016-2183)
- [NIST SP 800-131A Rev 2: Transitioning the Use of Cryptographic Algorithms](https://csrc.nist.gov/publications/detail/sp/800-131a/rev-2/final)
- [OWASP Cryptographic Failures](https://owasp.org/Top10/A02_2021-Cryptographic_Failures/)

---

Source: https://codepathfinder.dev/registry/python/cryptography/PYTHON-CRYPTO-SEC-002
Code Pathfinder — Open source, type-aware SAST with cross-file dataflow analysis
