Hashing vs. Encryption: A Beginner's Guide
Hashing and encryption are key to securing data, but they work differently. This guide uses ASCII visualizations and TypeScript code with the Web Crypto API to explain both clearly.
Hashing: One-Way Data Fingerprint
Hashing converts data into a fixed-length, irreversible hash for integrity checks (e.g., password storage).
- One-way: Cannot reverse to original data.
- Fixed length: Output size is constant.
- Use case: Passwords, file checksums.
Visual Explanation
[Input Data] "MySecret123" | v +-------------------+ | SHA-256 Algorithm | | (One-Way Process) | +-------------------+ | v [Hash Output] 4a7d1ed414474e40... (Fixed 64 chars)
Steps:
- Input data (e.g., "MySecret123").
- SHA-256 processes it.
- Outputs a 64-character hash.
- Same input = same hash; can't reverse.
Hashing Code (Web Crypto API)
async function hashData(data: string): Promise<string> { const encoder = new TextEncoder(); const dataBuffer = encoder.encode(data); const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer); return Array.from(new Uint8Array(hashBuffer)) .map(b => b.toString(16).padStart(2, '0')) .join(''); } // Usage const password = "MySecret123"; hashData(password).then(hash => console.log(`Hash: ${hash}`));
Output: Hash: 4a7d1ed414474e4033ac29ccb8653d9b...
Encryption: Reversible Data Protection
Encryption scrambles data into ciphertext, reversible with a key, for confidentiality (e.g., secure messages).
- Two-way: Decrypt with key.
- Key-based: Requires secret key.
- Use case: Messages, sensitive data.
Visual Explanation
[Plaintext] "Hello, World!" | v +-------------------+ | AES-GCM + Key | | (Encryption) | +-------------------+ | v [Ciphertext] x7b9pQz... | v +-------------------+ | AES-GCM + Key | | (Decryption) | +-------------------+ | v [Plaintext] "Hello, World!"
Steps:
- Plaintext (e.g., "Hello, World!").
- Encrypt with AES-GCM and key.
- Get ciphertext (unreadable).
- Decrypt with same key to recover plaintext.
Encryption Code (Web Crypto API)
async function encryptData(data: string, key: CryptoKey): Promise<string> { const encoder = new TextEncoder(); const dataBuffer = encoder.encode(data); const encrypted = await crypto.subtle.encrypt({ name: 'AES-GCM', iv: new Uint8Array(12) }, key, dataBuffer); return Array.from(new Uint8Array(encrypted)) .map(b => b.toString(16).padStart(2, '0')) .join(''); } async function decryptData(encrypted: string, key: CryptoKey): Promise<string> { const encryptedBuffer = new Uint8Array(encrypted.match(/.{1,2}/g)!.map(byte => parseInt(byte, 16))); const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: new Uint8Array(12) }, key, encryptedBuffer); return new TextDecoder().decode(decrypted); } async function main() { const key = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']); const message = "Hello, World!"; const encrypted = await encryptData(message, key); const decrypted = await decryptData(encrypted, key); console.log(`Original: ${message}`); console.log(`Encrypted: ${encrypted}`); console.log(`Decrypted: ${decrypted}`); } main();
Output:
Original: Hello, World! Encrypted: x7b9pQz... Decrypted: Hello, World!
Hashing vs. Encryption
[Hashing] Input ----> [One-Way: SHA-256] ----> Fixed Hash (No Key) (Irreversible) [Encryption] Plaintext <--> [Two-Way: AES-GCM + Key] <--> Ciphertext (Reversible with Key)
Feature | Hashing | Encryption |
---|---|---|
Purpose | Integrity | Confidentiality |
Reversible | No | Yes |
Key | No | Yes |
Use Case | Passwords | Secure messages |
When to Use
- Hashing: Password storage, file verification.
- Encryption: Messages, sensitive data.
Security Tips
- Hashing: Use SHA-256 or bcrypt; avoid MD5/SHA-1.
- Encryption: Secure keys; use AES-256.
I hope this post was helpful to you.
Leave a reaction if you liked this post!