trailofbits/algo · error
Private key must decode to exactly 32 bytes, got {len(priv_r
Error message
Private key must decode to exactly 32 bytes, got {len(priv_raw)} What it means
The base64 decoded successfully but did not produce exactly 32 bytes — X25519 private keys must be 32 bytes, so any other length (commonly 33 or 31 from a corrupted key) is rejected before key construction.
Source
Thrown at library/x25519_pubkey.py:91
msg=f"Private key file must be either base64 or exactly 32 raw bytes, got {len(data)} bytes"
)
priv_b64 = base64.b64encode(data).decode()
except OSError as e:
module.fail_json(msg=f"Failed to read private key file: {e}")
else:
priv_b64 = module.params["private_key_b64"]
# Validate input parameters
if not priv_b64:
module.fail_json(msg="No private key provided")
try:
priv_raw = base64.b64decode(priv_b64, validate=True)
except Exception as e:
module.fail_json(msg=f"Invalid base64 private key format: {e}")
if len(priv_raw) != 32:
module.fail_json(msg=f"Private key must decode to exactly 32 bytes, got {len(priv_raw)}")
try:
priv_key = x25519.X25519PrivateKey.from_private_bytes(priv_raw)
pub_key = priv_key.public_key()
pub_raw = pub_key.public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw)
pub_b64 = base64.b64encode(pub_raw).decode()
result["public_key"] = pub_b64
if module.params["public_key_path"]:
pub_path = module.params["public_key_path"]
existing = None
try:
with open(pub_path) as f:
existing = f.read().strip()
except OSError:
existing = None
View on GitHub (pinned to 20e22a8715)
Solutions
- Verify decode length in Python: len(base64.b64decode(key)) must equal 32
- Regenerate the key with wg genkey or cryptography's X25519PrivateKey.generate()
- Check you didn't concatenate public+private key material
- Ensure upstream generation writes exactly 32 raw bytes
Example fix
# python check
import base64
raw = base64.b64decode(open('priv.b64').read().strip(), validate=True)
assert len(raw) == 32, len(raw) Defensive patterns
Strategy: validation
Validate before calling
import base64
raw = base64.b64decode(priv_b64, validate=True)
assert len(raw) == 32, f'X25519 key must be 32 bytes, got {len(raw)}' Type guard
def is_32byte_key(b64: str) -> bool:
import base64
try:
return len(base64.b64decode(b64, validate=True)) == 32
except Exception:
return False Prevention
- Regenerate suspicious keys rather than hand-editing
- Keep key type consistent (X25519) across the whole pipeline
When it happens
Trigger: A valid-base64 string encoding 33/31/64 bytes: e.g. a key with one extra character encoded, an Ed25519 or hex key mislabeled as X25519, or double-encoded data.
Common situations: Mixing up key types between tools, encoding a 64-char hex string as base64, or hand-editing a key.
Related errors
- Private key file must be either base64 or exactly 32 raw byt
- Failed to read private key file: {e}
- No private key provided
- Invalid base64 private key format: {e}
- Failed to write public key file: {e}
AI-assisted analysis of trailofbits/algo@20e22a8715 (2026-08-28).
Data as JSON: /api/errors/2b4ed3cf7dd0517c.
Report an issue: GitHub.