| |

LFCA 95 🐧 Passwords and Hashing

A Linux system never stores passwords in plain text. If it did, anyone with read access to the password file would know every user’s password. Instead, the system stores a hash — a cryptographic fingerprint of the password. When a user logs in, the system hashes the provided password and compares the result to the stored hash. If they match, the password is correct. If they do not, the login fails. The original password is never stored, never transmitted, and never recoverable from the hash.

The LFCA exam places this topic under Security Fundamentals, which carries 14–16% of the total weight . The study plan lists “encryption basics” including hashing as a core security topic . Passwords and hashing are the foundation of authentication — the “who are you?” question that every access control decision depends on.

Key point: A hash function is one-way. It takes an input of any length and produces a fixed-length output. The same input always produces the same output. But you cannot reverse the output to recover the input. This is what makes hashing suitable for passwords: the system can verify a password by hashing it, but an attacker who steals the hash cannot easily recover the password.


Why hashing matters

Storing passwords in plain text is a catastrophic security failure. Hashing solves the problem, but only if it is done correctly. A weak hash function, a missing salt, or a reused salt all undermine the protection.

The plain-text problem. A database of plain-text passwords is a treasure chest for an attacker. Every password is immediately usable. Users reuse passwords across services, so a breach of one service compromises accounts on many others. Hashing ensures that a stolen password file does not directly reveal the passwords.

The rainbow table problem. A rainbow table is a precomputed list of hashes for common passwords. If an attacker steals a password hash, they can look it up in the rainbow table and find the original password. The defense is a salt — a random value added to each password before hashing. The salt makes every hash unique, even for identical passwords. A rainbow table built without the salt is useless .

The brute-force problem. An attacker can try every possible password, hash it, and compare the result to the stolen hash. A fast hash function makes this practical. A slow hash function — one designed to be computationally expensive — makes brute-forcing impractical. Modern password hashing algorithms like yescrypt are deliberately slow .

The salt storage problem. The salt must be stored with the hash. The salt is not secret; it only needs to be unique. The system reads the salt, combines it with the provided password, hashes the result, and compares it to the stored hash. The salt is part of the hash string .

The trade-off. Strong password hashing adds CPU overhead to every login. A system with thousands of users logging in simultaneously may feel the cost. The trade-off is acceptable: the cost of a breach is far higher than the cost of a few milliseconds of CPU time per login.


a. How Linux Stores Password Hashes

Linux stores password hashes in /etc/shadow. The file is readable only by root and the shadow group . The /etc/passwd file, which is world-readable, contains a placeholder (usually x) in the password field. The real hash lives in /etc/shadow.

The format of a shadow entry is a colon-separated list:

username:password_hash:last_change:min_age:max_age:warn:inactive:expire:reserved

The password hash field itself has a specific structure:

$id$salt$hash

The $id$ prefix identifies the hashing algorithm. The salt is the random value used to salt the password. The hash is the resulting hash value. The $ characters separate the three parts .

The algorithm IDs are:

IDAlgorithmNotes
$1$MD5Legacy, weak
$2$ or $2a$Blowfish (bcrypt)Used on some systems
$5$SHA-256Stronger than MD5
$6$SHA-512Used on Ubuntu 14.04–20.04
$y$yescryptUsed on Ubuntu 22.04+

A $6$ hash is SHA-512. A $y$ hash is yescrypt. The prefix tells the system which algorithm to use when verifying the password.


b. Salting: Why It Matters

A salt is a random value generated for each password. The salt is combined with the password before hashing. The result is a hash that is unique even for identical passwords.

Without a salt, two users with the password password123 have the same hash. An attacker who cracks one hash knows the password for both users. With a salt, each user has a different salt, so the same password produces different hashes. The attacker must crack each hash separately .

The salt is stored in plain text alongside the hash. It does not need to be secret. Its purpose is to make precomputed attacks (rainbow tables) useless and to ensure that identical passwords produce different hashes.

The combination is:

hash = H(password + salt)

The system reads the salt from the stored hash, combines it with the provided password, hashes the result, and compares. If the comparison succeeds, the password is correct .


c. Modern Password Hashing: yescrypt

Ubuntu 22.04 LTS and later use yescrypt as the default password hashing algorithm . Yescrypt is based on scrypt, a computationally expensive key derivation function. The “expensive” part is deliberate: it makes brute-force attacks impractical.

Yescrypt has a cost parameter that controls how much CPU time and memory the hash consumes. Higher cost means slower hashing and stronger protection. The default cost provides a balance between security and login performance .

The advantage of yescrypt over SHA-512 is that SHA-512 is fast. A fast hash can be brute-forced quickly with modern hardware. Yescrypt is slow by design, so each guess is expensive, and brute-forcing a large search space becomes infeasible .

The authconfig --test | grep hash command shows which algorithm the system uses . The passwd command updates the user’s password and writes the new hash to /etc/shadow.


Complete Example Session

This session demonstrates how Linux stores and verifies password hashes.

# ============================================
# PART 1: VIEW A SHADOW ENTRY
# ============================================

sudo grep student /etc/shadow

# Output:
# student:$6$8oIjLCsc$/n1iQXYh1E6.uOEuJKgioqAtmqm2TQmkJGF2RwyteIr1tIfrPdiRYgWe6Sjen5/eMij2uHM/a1tue/QRlo3X80:18038:0:99999:7:::

# The entry is colon-separated.
# The password hash field starts with $6$, which means SHA-512.
# The salt is the string between the second and third $.

# ============================================
# PART 2: IDENTIFY THE ALGORITHM
# ============================================

# The $6$ prefix identifies SHA-512.
# Other prefixes:
# $1$ = MD5
# $2a$ = Blowfish (bcrypt)
# $5$ = SHA-256
# $y$ = yescrypt

# ============================================
# PART 3: CHECK THE SYSTEM'S HASHING ALGORITHM
# ============================================

authconfig --test | grep hash

# Output:
# password hashing algorithm is sha512

# On Ubuntu 22.04+, the output would show yescrypt.

# ============================================
# PART 4: CREATE A HASH MANUALLY
# ============================================

python3 -c 'import crypt; print(crypt.crypt("mypassword", "$6$mysalt"))'

# Output:
# $6$mysalt$fPiMsDoTHyyQ9R6qx3cIICWKOcQd8dfBzMTrF8rnRMHsETgsu...

# The output is a valid shadow hash.
# The salt is "mysalt".
# The hash is the string after the third $.

# ============================================
# PART 5: THE SALT IS NOT SECRET
# ============================================

# The salt is stored in plain text.
# It does not need to be secret.
# Its purpose is to make each hash unique.

# ============================================
# PART 6: THE SAME PASSWORD, DIFFERENT SALTS
# ============================================

python3 -c 'import crypt; print(crypt.crypt("mypassword", "$6$salt1"))'
python3 -c 'import crypt; print(crypt.crypt("mypassword", "$6$salt2"))'

# Output:
# $6$salt1$...different hash...
# $6$salt2$...different hash...

# The same password produces different hashes because the salts differ.

# ============================================
# PART 7: THE SAME PASSWORD, SAME SALT
# ============================================

python3 -c 'import crypt; print(crypt.crypt("mypassword", "$6$salt1"))'
python3 -c 'import crypt; print(crypt.crypt("mypassword", "$6$salt1"))'

# Output:
# $6$salt1$...same hash...
# $6$salt1$...same hash...

# The same password and the same salt produce the same hash.

# ============================================
# PART 8: VERIFY A PASSWORD
# ============================================

# The system reads the stored hash.
# It extracts the salt.
# It combines the salt with the provided password.
# It hashes the result.
# It compares the result to the stored hash.
# If they match, the password is correct.

# ============================================
# PART 9: CHANGE A PASSWORD
# ============================================

sudo passwd student

# The system prompts for the new password.
# It generates a new random salt.
# It hashes the password with the salt.
# It writes the new hash to /etc/shadow.
# The old hash is replaced.

# ============================================
# PART 10: THE HASHING PRINCIPLES
# ============================================

# One-way: cannot reverse the hash to get the password
# Deterministic: same input, same output
# Salted: random value added to each password
# Slow: expensive by design to resist brute force
# Algorithm-tagged: the $id$ prefix identifies the algorithm

The ten parts cover viewing a shadow entry, identifying the algorithm, checking the system’s algorithm, creating a hash manually, the salt is not secret, the same password with different salts, the same password with the same salt, verifying a password, changing a password, and the hashing principles.


Quick Reference

The Shadow File Format

FieldMeaning
UsernameThe user’s login name
Password hashThe $id$salt$hash string
Last changeDays since Jan 1, 1970
Min ageMinimum days before change
Max ageMaximum days before change
WarnDays before expiry to warn
InactiveDays after expiry before lock
ExpireDays since Jan 1, 1970 when account expires

The Hash Prefixes

PrefixAlgorithm
$1$MD5
$2$ or $2a$Blowfish (bcrypt)
$5$SHA-256
$6$SHA-512
$y$yescrypt

The Hashing Properties

PropertyMeaning
One-wayCannot reverse the hash
DeterministicSame input, same output
SaltedRandom value per password
SlowExpensive by design

The Key Commands

CommandPurpose
passwdChange a password
grep user /etc/shadowView a shadow entry
authconfig --testCheck the hashing algorithm
crypt (Python)Create a hash manually

Best Practices

✅ Do This:

# Use a modern hashing algorithm
# yescrypt is the default on Ubuntu 22.04+                      # ✅
# Use a unique salt for each password
# The salt is generated automatically by passwd                 # ✅
# Protect /etc/shadow
# Only root and the shadow group should read it                 # ✅
# Use MFA for sensitive accounts
# A stolen password is not enough without the second factor     # ✅

❌ Don’t Do This:

# Don't store passwords in plain text
# Always hash them                                              # ❌
# Don't reuse salts across users
# The salt must be unique                                       # ❌
# Don't use MD5 or SHA-1 for password hashing
# They are too fast and vulnerable to brute force               # ❌
# Don't make /etc/shadow world-readable
# The hashes would be exposed                                   # ❌

Common Pitfalls

PitfallWhy It HappensFix
Password hash visible/etc/shadow permissions wrongchmod 640 /etc/shadow
Same hash for same passwordNo saltUse a salted hash
Fast brute-forceWeak hash algorithmUse yescrypt or bcrypt
Cannot verify passwordWrong algorithm prefixCheck the $id$ prefix

Real-World Examples

1. View a Shadow Entry

sudo grep student /etc/shadow

2. Identify the Algorithm

# $6$ = SHA-512
# $y$ = yescrypt

3. Check the System Algorithm

authconfig --test | grep hash

4. Create a Hash

python3 -c 'import crypt; print(crypt.crypt("pass", "$6$salt"))'

5. Change a Password

sudo passwd username

6. The Salt

# The salt is between the second and third $

7. The Hash

# The hash is after the third $

8. Verify a Password

# The system hashes the provided password with the stored salt

9. MFA

# A stolen hash is not enough without the second factor

10. The Hash Prefix

# $id$salt$hash

Visual

The Shadow Entry

┌──────────────────────────────────────────────┐
│  student:$6$8oIjLCsc$/n1iQXYh...:18038:...   │
│         │  │         │                       │
│         │  │         └─ Hash                 │
│         │  └─ Salt                          │
│         └─ Algorithm ID ($6$ = SHA-512)     │
│                                              │
│  The hash field is $id$salt$hash.            │
│  The salt is stored in plain text.           │
│  The hash is the result.                     │
│                                              │
└──────────────────────────────────────────────┘

The Hashing Process

┌──────────────────────────────────────────────┐
│  PASSWORD + SALT ──> HASH FUNCTION ──> HASH  │
│                                              │
│  "mypassword" + "salt1" ──> $6$salt1$...     │
│  "mypassword" + "salt2" ──> $6$salt2$...     │
│                                              │
│  The same password produces different hashes │
│  because the salts differ.                   │
│                                              │
└──────────────────────────────────────────────┘

The Verification

┌──────────────────────────────────────────────┐
│  VERIFICATION                                │
│                                              │
│  User enters password                        │
│       │                                      │
│       ▼                                      │
│  System reads stored hash                    │
│       │                                      │
│       ▼                                      │
│  Extract salt                                │
│       │                                      │
│       ▼                                      │
│  Hash(password + salt)                       │
│       │                                      │
│       ▼                                      │
│  Compare to stored hash                      │
│       │                                      │
│    MATCH?                                    │
│    ├─ YES → Login succeeds                   │
│    └─ NO  → Login fails                      │
│                                              │
└──────────────────────────────────────────────┘

The Algorithm Evolution

┌──────────────────────────────────────────────┐
│  ALGORITHM EVOLUTION                         │
│                                              │
│  MD5 ($1$)      → Weak, fast                 │
│  Blowfish ($2$) → Strong, used on some systems│
│  SHA-256 ($5$)  → Stronger than MD5          │
│  SHA-512 ($6$)  → Ubuntu 14.04–20.04         │
│  yescrypt ($y$) → Ubuntu 22.04+              │
│                                              │
│  Modern systems use yescrypt.                │
│  Older systems use SHA-512.                  │
│                                              │
└──────────────────────────────────────────────┘

Summary

ItemValue
Password storage/etc/shadow
Hash format$id$salt$hash
SaltRandom value per password
Salt purposePrevent rainbow tables, unique hashes
Algorithm ID $6$SHA-512
Algorithm ID $y$yescrypt
Modern defaultyescrypt (Ubuntu 22.04+)
Legacy defaultSHA-512 (Ubuntu 14.04–20.04)
Hash propertyOne-way, deterministic, salted, slow
LFCA weightSecurity Fundamentals, 14–16%

Key takeaways:

  • Linux never stores plain-text passwords. It stores a cryptographic hash of the password. The hash is a fingerprint that cannot be reversed to recover the original password .
  • The salt is a random value added to each password before hashing. The salt ensures that identical passwords produce different hashes. It makes rainbow tables useless because the precomputed hashes do not include the unique salt .
  • The shadow file stores the hash in the format $id$salt$hash. The $id$ prefix identifies the algorithm. The salt is stored in plain text alongside the hash. The hash is the result of hashing the password with the salt .
  • Modern Linux distributions use yescrypt. Ubuntu 22.04 and later default to yescrypt, which is based on scrypt and is deliberately slow to resist brute-force attacks. Older systems use SHA-512, which is faster and less resistant to brute force .
  • A slow hash is a strong hash. The cost parameter in yescrypt controls how much CPU time the hash consumes. Higher cost means slower login but stronger protection against brute-force attacks .
  • The salt does not need to be secret. It only needs to be unique. The security comes from the combination of the salt and the slow hash function, not from hiding the salt .
  • Passwords should be changed with the passwd command. The command generates a new random salt, hashes the new password, and writes the new hash to /etc/shadow .

Remember: Passwords are hashed, not encrypted. The hash is a one-way fingerprint. The salt is a random value that makes each hash unique. The algorithm is identified by the $id$ prefix. Modern systems use yescrypt. Older systems use SHA-512. The hash is stored in /etc/shadow. The file is readable only by root. The password is never stored, never transmitted, and never recoverable.


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!