A secure password-to-hash tool for cryptsetup and disk encryption
hashpwd2 converts passwords into strong, deterministic base64-encoded hashes using Argon2id, perfect for use with cryptsetup LUKS encryption. It's designed to transform memorable passwords into cryptographically strong passphrases.
- 🔐 Argon2id hashing - Industry-standard memory-hard key derivation
- 🔄 Deterministic output - Same password + salt = same hash every time
- 🚰 Pipe-friendly - Seamlessly integrates with cryptsetup via stdin/stdout
- 🎯 Base64 encoding - Clean, filesystem-safe 86-character output
- 🛡️ No clipboard dependencies - Secure piped operation only
- 🐛 Debug mode - Inspect password/salt input for troubleshooting
- ⚡ Optimized parameters - 1GB memory, 16 iterations, 4 threads
yay -S hashpwd2
# or
paru -S hashpwd2wget https://github.com/mrwiora/hashpwd2/releases/latest/download/hashpwd2
chmod +x hashpwd2
sudo mv hashpwd2 /usr/local/bin/git clone https://github.com/mrwiora/hashpwd2.git
cd hashpwd2
make build
sudo make install-systemThe primary use case is piping the hash directly to cryptsetup:
# Open LUKS volume
./hashpwd2 | sudo cryptsetup luksOpen /dev/sda1 cryptsda1 --key-file=-
# Format new LUKS volume
./hashpwd2 | sudo cryptsetup luksFormat /dev/sda1 --key-file=-When you run the command, you'll be prompted:
Enter secret: [type your password]
Enter salt: [type your salt]
Please wait!
[hash is piped to cryptsetup]
# Generate hash and see output
./hashpwd2
Enter secret: mypassword
Enter salt: mysalt
Please wait!
HoTBwJKbaiIUMcK7xd2igzpjh1QFsAwCSA3jQb9Ai3iSPDTGM8yIk4UrYvFewW9+Y+GMU4rRqs/u/yUXCdzo1A# Provide password and salt via stdin
echo -e "mypassword\nmysalt" | ./hashpwd2 | cat
# Or use printf for better compatibility
printf 'mypassword\nmysalt\n' | ./hashpwd2 | cat# See what the application is receiving
echo -e "test\nsalt" | ./hashpwd2 --debug
Enter secret:
Enter salt:
DEBUG: Password length: 4
DEBUG: Password (hex): 74657374
DEBUG: Salt length: 4
DEBUG: Salt (hex): 73616c74
Please wait!
[hash output]./hashpwd2 --version
hashpwd2 version 0.0.1
commit: abc1234
built: 2025-12-30T03:45:00Z- Input: Reads password and salt from stdin (terminal or pipe)
- Processing: Applies Argon2id with these parameters:
- Memory: 1 GB (1,048,576 KB)
- Iterations: 16
- Parallelism: 4 threads
- Output length: 64 bytes
- Output: 86-character base64-encoded hash (RawStdEncoding, no padding)
- Password: Your memorable secret (e.g., "MySecurePassword123")
- Salt: Additional entropy, can be empty or another value (e.g., "server01" or "backup-disk")
- Result: Deterministic hash unique to the password+salt combination
Using different salts with the same password produces completely different hashes, allowing you to:
- Derive multiple encryption keys from one password
- Use the same password for different volumes securely
- Add context-specific entropy (hostname, disk label, etc.)
- Use strong, random passwords with the salt for maximum entropy
- Store salts separately from encrypted volumes (e.g., password manager, paper backup)
- Use different salts for different volumes/systems
- The hash is suitable for cryptsetup (86 characters of base64 = ~512 bits of entropy input)
- Same password + salt always produces the same hash (by design)
- The strength of your encryption depends on both password AND salt strength
- Argon2 is memory-hard but not immune to dedicated hardware attacks
- This tool doesn't replace good password management practices
Previous versions supported clipboard operations, but this introduced:
- X11 library dependencies (platform-specific)
- Security risks (clipboard history, other apps reading clipboard)
- Complexity for headless/CI environments
The current pipe-only design is simpler, more secure, and more portable.
# Create encrypted volume
printf 'MyStrongPassword\nserver-hostname\n' | sudo cryptsetup luksFormat /dev/sda1 --key-file=-
# Mount at boot (add to /etc/crypttab)
# cryptroot /dev/sda1 none luks
# Then use hashpwd2 in initramfs or boot script# Volume 1 with salt "backup"
printf 'MyPassword\nbackup\n' | sudo cryptsetup luksFormat /dev/sdb1 --key-file=-
# Volume 2 with salt "data"
printf 'MyPassword\ndata\n' | sudo cryptsetup luksFormat /dev/sdc1 --key-file=-
# Same password, different salts = different encryption keys#!/bin/bash
HOSTNAME=$(hostname)
printf 'BackupPassword\n%s\n' "$HOSTNAME" | \
sudo cryptsetup luksOpen /dev/sdd1 backup-$(date +%Y%m%d) --key-file=-- Go 1.19 or higher
- Standard build tools (make, gcc)
# Build binary
make build
# Build optimized (smaller binary)
make build-optimized
# Run tests
make test
# Install to /usr/local/bin
sudo make install-system
# Clean build artifacts
make clean
# Show version information
make versionThe project includes comprehensive integration tests:
# Run all tests
go test -v -timeout 10m ./...
# Run specific test
go test -v -run TestHashCalculation
# Run with debug output
go test -v -run TestDebugInputReadingTests verify:
- ✅ Correct hash generation for various inputs
- ✅ Proper stdin/stdout/stderr separation
- ✅ Special character handling
- ✅ Piped input/output behavior
- ✅ Consistent hashing (deterministic output)
┌─────────────┐
│ stdin │ ← Password + Salt (terminal or pipe)
└─────┬───────┘
│
v
┌─────────────────────────────┐
│ Password Reading │
│ - Terminal: term.ReadPassword (hidden)
│ - Piped: bufio.Reader (visible)
└─────┬───────────────────────┘
│
v
┌─────────────────────────────┐
│ Argon2id Key Derivation │
│ - Memory: 1 GB │
│ - Iterations: 16 │
│ - Parallelism: 4 │
│ - Output: 64 bytes │
└─────┬───────────────────────┘
│
v
┌─────────────────────────────┐
│ Base64 Encoding │
│ - RawStdEncoding (no pad) │
│ - Output: 86 chars │
└─────┬───────────────────────┘
│
v
┌─────────────┐
│ stdout │ → Hash (86-character base64 string)
└─────────────┘
┌─────────────┐
│ stderr │ → Prompts and status messages
└─────────────┘
Solution: Use debug mode to verify input:
printf 'test\nsalt\n' | ./hashpwd2 --debugCheck that password/salt lengths and hex values match expectations.
Possible causes:
- Different password or salt used during format vs open
- Extra newlines in input
- Shell escaping issues with special characters
Solution: Use printf with explicit newlines and test with debug mode first.
Solution: Use printf instead of echo, or quote properly:
# Good
printf 'p@ssw0rd!#$\ns@lt\n' | ./hashpwd2
# Also good
./hashpwd2 # Type interactivelyContributions welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass:
go test -v ./... - Submit a pull request
BSD-3-Clause License - See LICENSE file for details.
Matthias R. Wiora matthias@wiora.io
- cryptsetup - Linux disk encryption
- Argon2 - Password hashing competition winner
- LUKS - Linux Unified Key Setup
Note: This tool is designed for advanced users who understand disk encryption. Always keep secure backups of your encryption keys/passwords!