33 β Password, Crypto and Secrets Tools
Level: Intermediate Β· Time: ~20 min Β· Prerequisites: Lesson 32 β Host Security and Audit Tools
Why this matters
Almost every incident starts with a credential. Not a clever exploit β a password that was reused, a token left in a repository, a key that never expired, an internal service still offering a protocol from 2009. The tools in this lesson are how you find out whether your own credentials would survive contact with an attacker, how you check that the cryptography you depend on is actually doing its job, and how you stop secrets from living in places where everyone can read them. Used on your own systems, they are the cheapest risk reduction available to a small team.
The mental model: one family per question
| The question | The tool | What it tells you |
|---|---|---|
| Would this password survive a real cracking attempt? | hashcat or John the Ripper, against a hash from your own lab | how many minutes of GPU time your policy buys |
| Is this service's certificate valid, and until when? | openssl s_client and openssl x509 |
expiry, issuer, the names it covers, chain completeness |
| Does this service still accept an obsolete TLS version? | openssl s_client with an explicit protocol version |
a real, common and easily fixed finding |
| Is this download the file I think it is? | sha256sum plus a signature |
integrity, and authenticity if signed |
| Where are the humans' passwords? | a password manager: local file, or self-hosted for a team | unique passwords and a single strong passphrase |
| Where are the machines' secrets? | encrypted secrets files with the key delivered separately, or a secrets server | no credentials in code, config or chat |
[!IMPORTANT] Password cracking tools test your own hashes, from your own systems, with written authorisation. A cracking rig plus a hash database you did not create is a criminal combination, and running these tools against a corporate system without a signed scope is how careers end. Everything below assumes your lab, your credentials, your rules.
Cracking your own hashes to prove a policy
First, understand which game you are playing. Online guessing is limited by the service; offline cracking is limited only by your hardware.
| Online guessing | Offline cracking | |
|---|---|---|
| Where the work happens | against a live login | on your hardware, against a file of hashes |
| Speed limit | rate limits, lockouts, MFA | whatever your GPU can do |
| Visible to you? | yes, in your authentication logs | no β and the breach already happened when the dump was taken |
| What it needs | a network path and a list of accounts | the hashes |
| What defends it | lockouts, MFA, distributed-failure alerting | hash strength, password length, and not losing the dump |
Two open-source crackers cover the ground. hashcat is GPU-first with a very large catalogue of hash modes and two strong attack engines: wordlists with mangling rules, and masks for passwords of a known shape. John the Ripper (the community "jumbo" build) is excellent on the CPU and supports an enormous range of formats, including old and unusual ones. When both support the format, prefer hashcat for speed; reach for John when the hash is exotic.
# Wordlist plus bundled mangling rules β the realistic-attack default
hashcat -m 1000 -a 0 ntlm.txt /usr/share/wordlists/rockyou.txt \
-r /usr/share/hashcat/rules/best64.rule
hashcat -m 1000 ntlm.txt --show # what has been recovered so far
hashcat -b # benchmark: know your own rate before quoting numbers
# Mask attack: uppercase, lowercase, digits, of a length you observed
hashcat -m 0 -a 3 md5.txt ?u?l?l?l?l?d?d
john --format=nt --wordlist=rockyou.txt --rules=Jumbo ntlm.txt
john --show --format=nt ntlm.txt
| Flag | Meaning |
|---|---|
-m 1000 |
hash mode. 0 is raw MD5, 1000 is NTLM, 1800 is SHA-512 crypt, 3200 is bcrypt, 22000 is WPA |
-a 0 / -a 3 / -a 6 |
attack mode: wordlist / mask / hybrid wordlist plus mask |
-r file.rule |
apply mangling rules (password becomes P@ssw0rd1, Password2026, and so on) |
--show, -o, --runtime |
read results back, write them out, bound the run |
--format, --incremental, --fork |
John's equivalents: hash type, expanding search, parallel processes |
The reason this matters is that wordlist plus rules is not brute force. A hundred million realistic variants of human-chosen passwords will beat an astronomically large search that never finishes. The payoff of running it in your lab is a number you can take to management: at our current minimum length, a stolen database gives an attacker the average user's password in under a day.
Now the defence, and why some hashes are boring to crack:
- A salt (random data stored with each hash) makes precomputed tables useless and forces cracking to be done per account. Two users with the same password no longer share a hash.
- Deliberately slow functions β bcrypt, scrypt, Argon2 β are tunable: they attach a cost parameter (iterations, memory, or both) so each guess takes real time. Cracking them still works, but the rate collapses from billions of guesses a second to thousands, and the honest-looking difference between a two-hour crack and a two-century one is the whole argument.
- Length multiplies work. Every added character multiplies the search space; a trailing
!is predicted by every rule set in existence.
So the policy changes these tools justify: raise the minimum length to something a person needs a phrase for, screen new passwords against known-breached lists (a service can do this without ever seeing the password, by sending only a short prefix of the hash), drop forced composition and arbitrary expiry rules in favour of length and screening, and put MFA and a password manager behind it. The current NIST digital identity guidance (SP 800-63B) says the same thing β length and breach screening over composition rules β and it is the standard your auditor or insurer is most likely to accept.
Certificates and TLS with the crypto command-line toolkit
openssl is the multi-tool you already have. Five jobs cover most of the work.
# 1. Create a private key and a certificate signing request
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out server.key
openssl req -new -key server.key -out server.csr -subj "/CN=web.example.com"
# 2. Read what is actually in a certificate
openssl x509 -in server.crt -noout -subject -issuer -dates
# 3. Inspect a live service: chain, names, dates
echo | openssl s_client -connect www.example.com:443 -servername www.example.com 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates
# 4. Expiry across a list of hosts β the five-minute monthly check
for h in mail.example.com www.example.com vpn.example.com; do
printf '%-24s ' "$h"
echo | openssl s_client -connect "$h:443" -servername "$h" 2>/dev/null | openssl x509 -noout -enddate
done
# 5. Does this service still accept an obsolete protocol version?
echo | openssl s_client -connect www.example.com:443 -tls1_1 2>&1 | grep -E 'Protocol|alert'
-servername sends the SNI name, which is required whenever several sites share an address, and 2>/dev/null discards the handshake detail you asked not to see. In check 5, a completed handshake is the finding: if the connection succeeds and the negotiated protocol line shows the old version, the service still offers it and a client can negotiate down to it. Remove old versions from the server configuration and re-test until only the current ones answer. nmap --script ssl-enum-ciphers -p 443 host from Lesson 30 does the same job across a range of hosts and lists the accepted ciphers with a strength grade.
What to check, and what each answer means:
Read four things in every certificate: the subject and subject alternative names (does it cover the name clients actually use?), the issuer and the chain sent with it (from a CA you expect, with the intermediates clients need?), the date range (expiry, and whether a long-lived service has a suspiciously new certificate), and the key size and signature algorithm (anything older than your policy allows?). openssl verify -CAfile ca.pem server.crt checks your own internal chain end to end. An expired certificate is an outage, a self-signed one on an internal service is a routine finding, and a certificate from a public CA for an internal name is either a mistake or a sign somebody is intercepting your traffic.
Hashing, encryption and signing in daily use
Integrity first, because it is the boring half that everything else depends on:
sha256sum image.iso # compute; Get-FileHash -Algorithm SHA256 on Windows
sha256sum -c SHA256SUMS # verify a published list of checksums
cmp file1 file2 # byte-for-byte comparison of two files
MD5 and SHA-1 are broken for security purposes β do not use them for anything that matters, and treat a published MD5 as an integrity hint rather than a guarantee. A checksum also proves nothing about who published the file: an attacker who can change the file can change the checksum beside it. That is what signatures are for.
# Symmetric: one passphrase, and the same one to decrypt
gpg --symmetric --cipher-algo AES256 backup.tar.gz
gpg --decrypt backup.tar.gz.gpg > backup.tar.gz
# Keypair: encrypt to a recipient's public key, sign with your private one
gpg --encrypt --recipient colleague@example.com report.pdf
gpg --detach-sign --armor release.tar.gz # a signature file alongside the artefact
gpg --verify release.tar.gz.asc release.tar.gz
GPG and age are the two common open-source tools. age is deliberately simpler: one short key file, one command, no web of trust, which is why it has become the default for encrypting files and backups. Symmetric encryption is the right choice when you are the only person who needs to read the file (encrypting a backup before it leaves your control); keypair encryption is the right choice when you are sending to someone else, and it is the only shape that can prove authorship, because signing uses a private key only the author has.
| Job | Approach |
|---|---|
| Encrypt a backup before it leaves your control | age -r <public key> -o backup.age backup.tar.gz, private key stored separately |
| Send a sensitive file to a colleague | encrypt to their public key, or to a shared team key stored in your password manager |
| Verify a downloaded installer is genuine | check the publisher's signature, not just the checksum |
Password managers, secrets and SSH keys
A password manager is the single most effective personal security control, because it makes unique passwords per service the easy option rather than the disciplined one. Two models, and you can use both:
| Model | Examples | Trade-off |
|---|---|---|
| Local file-based | KeePassXC (.kdbx file, optional key file) |
nothing to host, no cloud dependency; you must sync and back up the file yourself |
| Self-hosted server | Vaultwarden with compatible clients, or Passbolt for team sharing | shared vaults with an audit trail and per-user access; you must run, patch and back up the server |
Run one for the team and set the rules: the manager's own account has MFA, shared credentials live in a shared vault (never in chat or a spreadsheet), everyone can see who has access, and the vault is backed up somewhere you can restore from. Losing the vault without a backup is an incident of its own.
Secrets management is the same discipline for machines. The problem: credentials in code, in configuration files, in chat, in a shared spreadsheet, and in the CI logs nobody reads. The practices are not complicated:
- Separate development from production β different credentials, different scope, different storage.
- Never commit a secret. Add a scanner to your workflow (
gitleaks detect --source .on a repository, and a staged-changes check before commit) so a mistake becomes a failed build rather than a disclosure. - Rotate on a schedule and immediately on suspicion β including every credential the suspect host could have read.
- Prefer short-lived credentials where the platform supports them: instance roles rather than long-lived keys, dynamically issued database credentials, tokens with an expiry.
- Encrypt at rest with the key delivered separately. An encrypted secrets file (for example with SOPS, using age or GPG, or an Ansible vault file for the labs later in this course) is safe to keep in version control only because the key is not with it. A secrets server goes further: it stores them, issues them, and logs who read what.
SSH key hygiene, in one table:
| Practice | How |
|---|---|
| Generate a modern key with a passphrase | ssh-keygen -t ed25519 -a 100 -C "laptop 2026" |
| Add a passphrase to an existing key | ssh-keygen -p -f ~/.ssh/id_ed25519 |
| No world- or group-readable key files | find ~/.ssh -type f -perm /077 should return nothing |
| Server refuses passwords and root logins | sudo sshd -T \| grep -Ei 'passwordauth\|permitrootlogin\|pubkey' |
| Remove what nobody uses | one key per device, a comment naming the device, and unused authorized_keys entries deleted |
[!TIP] Rotating one credential is rarely enough. When a host is compromised, rotate everything it could have read β service accounts, database passwords, API tokens, deployment keys β because you know it had access and you do not know what it copied.
The secrets-hygiene checklist
- Every credential has an owner and a documented location β no credentials in chat, tickets, spreadsheets or code.
- A secret scanner runs before commits, and a finding blocks the change.
- Development and production never share credentials or scope.
- Rotation is scheduled, and immediate on any suspicion, including everything a suspect host could read.
- Long-lived static credentials are replaced by short-lived ones wherever the platform allows.
- MFA protects every account that can reach production, with phishing-resistant factors for administrators.
- Humans use a password manager; machines use an encrypted secrets store with the key delivered separately.
- SSH has one passphrase-protected key per device, password authentication switched off, and no orphan keys.
Why this matters more than the tooling: leaked credentials are found by machines, not people. Automated scanners watch public source repositories continuously, including the history of a repository, branches that were deleted, and forks nobody remembers. Secrets also escape through container image layers (a token in a layer survives its removal from the final image), mobile app bundles that can be unpacked in minutes, build and CI logs, job postings with a convenient example configuration, screenshots in documentation, and paste sites and breach dumps where a 2019 leak is still searchable today. So "it was in a private repository" is not a defence: it is one mis-click, one over-permissive collaborator or one compromised developer account away from being public, and the history is already cloned onto every laptop that ever pulled it. Treat anything that has ever been committed, logged or shipped as disclosed.
Attack it / Defend it
| The attack | How it works | The control that stops it |
|---|---|---|
| Password spraying | one common password against many accounts | MFA, banned-password lists, alerting on distributed failures |
| Credential stuffing | passwords leaked from another breach, reused by your staff | MFA, breach screening at password change, a manager that prevents reuse |
| Offline cracking of a stolen dump | crack the hashes at leisure | slow salted hashing, long passphrases, and preventing the dump |
| Secrets harvested from a public repository | automated scanning of commits, history and forks | pre-commit scanning, rotation on exposure, short-lived credentials, never committing the key |
| Token stolen from a container image | read a credential out of a published layer | build-time secret scanning, build args and multi-stage builds that exclude secrets, rotation |
| Man-in-the-middle against a badly configured service | negotiate an obsolete protocol version or a weak cipher | disable old protocol versions, test with s_client and cipher scanning, HSTS |
| Forged or tampered download | replace an installer and its checksum | signed releases verified with GPG or age keys, signature checked before execution |
| Reused or orphaned SSH key | use an old key left in authorized_keys |
one key per device, passphrases, password authentication off, periodic key review |
Key takeaways
- These tools exist to test your own systems. Authorisation is the boundary between a security audit and a crime.
- Wordlist plus rules beats brute force, and running it in your lab produces the one number that changes policy: how long your users' passwords survive.
- Salt and slow hashing are why "the hashes were strong" is a real answer β strength here means an attacker's cost, not secrecy.
- A checksum proves integrity, a signature proves origin. Only one of them survives an attacker who can edit the file.
- Treat anything ever committed, logged or shipped as disclosed β and rotate on suspicion, not on certainty.
Check yourself
- You crack your own NTLM dump in two hours with a bundled rules file. Name the three policy changes that would make the same dump useless next year.
- What does a salt prevent, and what does a slow hashing function prevent that a salt does not?
- A host still completes a TLS 1.1 handshake. Why is that a finding, and how do you test it from the command line?
- A colleague sends you a file and a
.ascsignature. What does verifying it actually prove, and what does a checksum alone fail to prove? - Your team stores the production database password in a private repository, arguing nobody outside can see it. Give three ways it could still escape.