# PYTHON-CRYPTO-SEC-024: Insufficient DSA Key Size (PyCryptodome)

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

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

## Description

Detects DSA key generation using `DSA.generate(bits)` from PyCryptodome where the first positional argument (key size in bits) is less than 2048. This rule uses a `.where(0, lt(2048))` predicate targeting position 0 — it fires only on provably undersized keys and does not flag 2048-bit or larger keys.
DSA with small keys is vulnerable to discrete logarithm attacks. A 1024-bit DSA key can have its private key recovered through index calculus methods, enabling an attacker to forge arbitrary signatures. NIST SP 800-131A formally deprecated 1024-bit DSA in 2013 and requires 2048-bit minimum. Beyond the key size risk, DSA signing requires a cryptographically random per-signature nonce (k): a reused nonce across two signatures algebraically exposes the private key regardless of key size, as demonstrated in the 2010 Sony PlayStation 3 master key extraction. For new applications, prefer ECDSA (ECC.generate(curve='P-256')) or avoid DSA entirely.


## Vulnerable Code

```python
from cryptography.hazmat.primitives.asymmetric import rsa, dsa, ec
from cryptography.hazmat.backends import default_backend

# SEC-024: DSA in PyCryptodome (audit)
from Crypto.PublicKey import DSA
dsa_key_pc = DSA.generate(1024)
```

## Secure Code

```python
from Crypto.PublicKey import DSA, ECC

# SECURE: DSA 2048-bit key (NIST SP 800-131A minimum)
key = DSA.generate(2048)

# SECURE: DSA 3072-bit key (recommended for post-2030)
key = DSA.generate(3072)

# PREFERRED: ECC P-256 replaces DSA for new systems
key = ECC.generate(curve='P-256')

# PREFERRED: ECC P-384 for high-value signing keys
key = ECC.generate(curve='P-384')

```

## Detection Rule (Python SDK)

```python
from rules.python_decorators import python_rule
from codepathfinder import calls, flows, QueryType
from codepathfinder.qualifiers import lt


class PyCryptoDSA(QueryType):
    fqns = ["Crypto.PublicKey.DSA", "Cryptodome.PublicKey.DSA"]


@python_rule(
    id="PYTHON-CRYPTO-SEC-024",
    name="Insufficient DSA Key Size (PyCryptodome)",
    severity="HIGH",
    category="cryptography",
    cwe="CWE-326",
    tags="python,pycryptodome,dsa,key-size,CWE-326,OWASP-A02",
    message="DSA key size is less than 2048 bits.",
    owasp="A02:2021",
)
def detect_dsa_keygen_pycrypto():
    """Detects DSA key generation with insufficient key size in PyCryptodome."""
    return PyCryptoDSA.method("generate").where(0, lt(2048))
```

## How to Fix

- Use DSA.generate(2048) as the absolute minimum; use DSA.generate(3072) for systems requiring protection beyond 2030.
- Consider replacing DSA with ECC (curve='P-256' or 'P-384') for new applications — smaller keys, faster operations, and immune to nonce-reuse catastrophe when using EdDSA.
- If DSA must be used, ensure the per-signature nonce (k) is generated from a CSPRNG; never reuse a nonce across two signatures with the same key.
- Audit all DSA key material and schedule rotation of any keys below 2048 bits.

## FAQ

**Q: Does this rule flag DSA.generate(2048)?**

No. The rule uses `.where(0, lt(2048))` which only fires when the bits argument is strictly less than 2048. DSA.generate(2048) does NOT trigger this rule.


**Q: What key size should I use for new DSA applications?**

Use DSA.generate(2048) as the minimum, or DSA.generate(3072) for data requiring protection beyond 2030. However, for any new system seriously consider replacing DSA with ECC.generate(curve='P-256') — it is faster, has smaller signatures, and if using Ed25519-style deterministic signing avoids the nonce-reuse vulnerability entirely.


**Q: How does this rule differ from SEC-021 (DSA in the cryptography lib)?**

Both rules flag DSA keys below 2048 bits. The difference is the target library and API: SEC-021 targets `cryptography`'s `dsa.generate_private_key(key_size=...)` named-argument API, while SEC-024 targets PyCryptodome's `DSA.generate(bits)` positional-argument API and uses `.where(0, lt(2048))` to check position 0.


**Q: What attack does a small DSA key enable?**

Small DSA keys are vulnerable to the index calculus algorithm for computing discrete logarithms. With a 1024-bit modulus an attacker can recover the private key and forge signatures on arbitrary messages — enabling code signing bypass, authentication impersonation, or certificate forgery depending on how the key is used.


**Q: Why is DSA particularly dangerous compared to RSA?**

Beyond key size, DSA has a catastrophic nonce-reuse vulnerability: if the per-signature random value k is ever reused across two signatures (even with a large key), an attacker can algebraically derive the private key from those two signatures. This happened to Sony in 2010 and to Bitcoin wallet implementations that used flawed RNGs. RSA signing does not have this property. EdDSA (Ed25519) mitigates it by deriving k deterministically.


**Q: How does this rule detect the key size when it is a positional argument?**

PyCryptodome's DSA.generate() accepts key size as position 0. The rule uses `.where(0, lt(2048))` to filter on the first positional argument. If the key size is passed as a variable whose value cannot be statically resolved, this rule may not fire (under-approximation). Use literal integer values for key sizes in production code to ensure static detectability.


## References

- [CWE-326: Inadequate Encryption Strength](https://cwe.mitre.org/data/definitions/326.html)
- [NIST SP 800-57 Part 1 Rev 5: Recommendation for Key Management](https://csrc.nist.gov/publications/detail/sp/800-57-part-1/rev-5/final)
- [NIST SP 800-131A Rev 2: Transitioning the Use of Cryptographic Algorithms and Key Lengths](https://csrc.nist.gov/publications/detail/sp/800-131a/rev-2/final)
- [PyCryptodome Documentation: DSA.generate()](https://pycryptodome.readthedocs.io/en/latest/src/public_key/dsa.html)
- [Sony PS3 DSA Nonce Reuse Attack (2010) — private key recovered from two signatures](https://www.bbc.co.uk/news/technology-12116051)
- [OWASP Cryptographic Failures (A02:2021)](https://owasp.org/Top10/A02_2021-Cryptographic_Failures/)

---

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