# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview This is a Python PBKDF2 password hashing utility with two implementations: - `salt.py`: Reference implementation with CLI that supports both `hash` and `verify` subcommands, plus a shortcut where running `python3 salt.py ` automatically invokes the hash command - `salt2.py`: Alternative CLI that imports from `salt.py` and requires explicit subcommands (`generate` and `verify`) Both implementations use PBKDF2-HMAC-SHA256 with configurable iteration counts (default: 200,000, overridable via `PBKDF2_ITERATIONS` env var). ## Common Commands ### Running the CLI ```bash # Hash a password (salt.py supports shortcut syntax) python3 salt.py "MyPassword" python3 salt.py hash "MyPassword" # Verify a password python3 salt.py verify # Alternative CLI (requires explicit subcommands) python3 salt2.py generate "MyPassword" python3 salt2.py verify ``` ### Testing ```bash # Run all tests python3 -m pytest # Run specific tests with verbose output python3 -m pytest -k verify --maxfail=1 -vv # Run tests for a specific module python3 -m pytest tests/test_hashing.py ``` ### Dependencies Dependencies are listed in `requirements.txt`. Install with: ```bash pip install -r requirements.txt ``` ## Code Architecture ### Module Structure - **salt.py**: Core module containing `hash_password()` and `verify_password()` functions, plus an integrated CLI via `main()` - **salt2.py**: Wrapper CLI that imports from `salt.py` and provides an alternative command structure - **tests/**: Test suite mirroring the module structure - `test_hashing.py`: Tests for core hashing/verification functions - `test_cli.py`: Tests for CLI behavior (specifically `salt.py`'s shortcut syntax) ### Key Functions **`hash_password(password, *, iterations=None, salt_bytes=16) -> tuple[str, str]`** - Generates a cryptographically secure random salt - Derives a hash using PBKDF2-HMAC-SHA256 - Returns base64-encoded (salt, hash) tuple **`verify_password(password, salt_b64, hash_b64, *, iterations=None) -> bool`** - Validates a password against stored salt/hash - Uses timing-safe comparison via `hmac.compare_digest()` - Returns `False` for invalid base64 without raising exceptions ### CLI Argument Handling The `salt.py` module includes `_normalize_args()` which allows shortcut syntax: if the first argument is not a subcommand (`hash`/`verify`) and not a flag, it's automatically prefixed with `hash`. This is tested in `tests/test_cli.py:test_main_supports_hash_shortcut()`. ## Development Guidelines ### Python Version and Style - Target Python 3.11+ - Use type annotations on public functions - 4-space indentation - Follow `lowercase_with_underscores` naming for functions and variables ### Security Practices - Always use `os.urandom()` for salt generation (never predictable values) - Use `hmac.compare_digest()` for hash comparison to prevent timing attacks - Validate base64 input with `validate=True` parameter - Handle encoding errors gracefully by returning `False` rather than raising exceptions ### Testing Requirements - Place tests in `tests/test_.py` matching the module name - Cover happy paths and error handling (invalid base64, wrong passwords) - Include round-trip tests: hash → verify with correct/incorrect passwords - Maintain >90% coverage for hashing utilities - When adding new hash algorithms, include regression tests with known salt/hash pairs ### Configuration - Iteration count defaults to 200,000 but respects `PBKDF2_ITERATIONS` environment variable - Salt size defaults to 16 bytes (configurable via `salt_bytes` parameter) ## Commit Guidelines Use imperative subject lines with conventional commit prefixes: - `feat:` for new features - `fix:` for bug fixes - `test:` for test additions/changes - `refactor:` for code restructuring Reference issues with `Fixes #ID` when applicable. PRs should only be opened after tests pass.