# Security
## Overview
ExkPasswd is designed with security as the highest priority. This document outlines the security measures, testing methodology, and known considerations.
## Cryptographic Guarantees
### Random Number Generation
All randomness uses `:crypto.strong_rand_bytes/1` with **rejection sampling** to eliminate modulo bias:
```elixir
# Unbiased random integer generation
def integer(max) do
range_size = 0x1_0000_0000 # 2^32
threshold = range_size - rem(range_size, max)
integer_unbiased(max, threshold)
end
defp integer_unbiased(max, threshold) do
value = :crypto.strong_rand_bytes(4) |> :binary.decode_unsigned()
if value < threshold, do: rem(value, max), else: integer_unbiased(max, threshold)
end
```
**Benefits**:
- Perfectly uniform distribution (no modulo bias)
- Cryptographically secure randomness
- Verified via chi-square statistical tests
- Zero performance impact (rejection rate < 0.001%)
### Dictionary
- Uses EFF Large Wordlist (7,826 words)
- Pre-computed at compile time for O(1) access
- All words verified reachable through statistical testing
- No filtering bias detected
## Security Testing
### Test Suite
Run comprehensive security tests:
```bash
# All security tests
mix test test/exk_passwd/security_test.exs
# Adversarial attack simulations
mix test test/exk_passwd/adversarial_test.exs
```
### Adversarial Testing
The test suite simulates real attack scenarios:
1. **Statistical bias detection** - Chi-square tests for uniformity
2. **Collision resistance** - Birthday attack validation
3. **State correlation** - Batch generation independence
4. **Dictionary coverage** - Complete word space accessibility
5. **Entropy validation** - Collision rate analysis
6. **Pattern detection** - ML-resistant password structure
7. **Distribution analysis** - Word length, digits, case transforms
8. **Parallel safety** - Process independence verification
**Test Coverage**: 100% with 835 tests (136 doctests + 699 unit tests), all passing.
## Security Considerations
### Entropy Calculations
Theoretical entropy is calculated assuming:
- Perfect uniform random selection
- Known configuration parameters
- EFF Large Wordlist (7,826 words)
For 4-word password: ~52 bits of entropy (2^52 ≈ 4.5 quadrillion combinations)
### Preset Configurations
Public presets (`:default`, `:xkcd`, `:wifi`, etc.) have predictable structure.
**Recommendation**: Use custom `Config` for high-security applications:
```elixir
config = Config.new!(
num_words: 5,
separator: "+",
word_length: 6..9,
case_transform: :random,
digits: {3, 3}
)
password = ExkPasswd.generate(config)
```
### Known Limitations
1. **Preset fingerprinting** - Passwords generated with public presets can be identified by structure
2. **Dictionary knowledge** - Attackers knowing the EFF wordlist reduces search space
3. **Configuration leakage** - Password structure reveals some configuration parameters
These are **inherent to structured passphrases**, not implementation bugs.
**Mitigation**: Users should use custom configurations for sensitive applications.
## Vulnerability Disclosure
If you discover a security vulnerability:
1. **DO NOT** open a public GitHub issue
2. Email security concerns to the maintainers
3. Include clear reproduction steps
4. Allow reasonable time for a fix before disclosure
## Testing Methodology
### Chi-Square Test
Validates uniform distribution of random values:
```elixir
chi_square = Enum.reduce(frequencies, 0, fn {_, observed}, acc ->
acc + :math.pow(observed - expected, 2) / expected
end)
# For df degrees of freedom at 99.9% confidence:
critical_value = df + :math.sqrt(2 * df) * 3.29
assert chi_square < critical_value
```
### Collision Rate Analysis
Validates entropy claims via birthday paradox:
```elixir
# Generate samples, check collision rate
unique = Enum.uniq(passwords) |> length()
collision_rate = (total - unique) / total
# Should be near 0 for high-entropy passwords
assert collision_rate < 0.001
```
## Best Practices
### For Library Users
1. **Use custom configs** for sensitive applications (avoid public presets)
2. **Increase word count** for higher security (6+ words recommended)
3. **Add randomization** to separators and padding when possible
4. **Monitor entropy** using `ExkPasswd.Entropy.calculate/2` or `ExkPasswd.Strength.analyze/2`
### For Contributors
1. **Never use `:rand` module** - always use `ExkPasswd.Random`
2. **Avoid Enum.random/1** - not cryptographically secure
3. **Run security tests** before committing: `mix test test/exk_passwd/security_test.exs`
4. **Maintain test coverage** 95%+ overall, 100% for crypto code
## Compliance
### NIST Guidelines
ExkPasswd follows NIST SP 800-63B recommendations:
- ✅ Minimum 64 bits entropy for high-value passwords (achieved with 5+ words)
- ✅ Cryptographically secure random number generation
- ✅ No weak patterns or predictable structures
- ✅ Resistance to dictionary attacks (large word space)
### OWASP Recommendations
- ✅ Use of secure random number generator
- ✅ Sufficient entropy for password generation
- ✅ No hardcoded secrets or predictable patterns
- ✅ Regular security testing and validation
## References
- [EFF Wordlist](https://www.eff.org/deeplinks/2016/07/new-wordlists-random-passphrases)
- [NIST SP 800-63B](https://pages.nist.gov/800-63-3/sp800-63b.html)
- [OWASP Password Guidelines](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html)
- [Modulo Bias Explained](https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/)
- [Rejection Sampling](https://en.wikipedia.org/wiki/Rejection_sampling)
## Contact
For security-related questions or concerns, please contact the maintainers through the project's GitHub repository.
---
**Last Updated**: 2026-04-03