Hash Security and Data Integrity Guide
Hash functions are fundamental to modern cryptography and data security. This guide covers hash algorithms, security applications, and best practices for maintaining data integrity.
1. Hash Function Fundamentals
Understanding Hash Functions
Core Properties
const hashProperties = {
deterministic: 'Same input always produces same output',
uniformDistribution: 'Output appears random and evenly distributed',
avalancheEffect: 'Small input change causes large output change',
irreversible: 'Cannot derive input from hash output',
collisionResistant: 'Difficult to find two inputs with same hash'
};
Common Hash Algorithms
Algorithm Comparison
const hashAlgorithms = {
md5: {
length: 128,
security: 'Broken - do not use for security',
useCase: 'File integrity checks only',
speed: 'Very fast'
},
sha1: {
length: 160,
security: 'Deprecated - collision attacks exist',
useCase: 'Legacy systems only',
speed: 'Fast'
},
sha256: {
length: 256,
security: 'Currently secure',
useCase: 'General purpose cryptographic hashing',
speed: 'Moderate'
},
sha512: {
length: 512,
security: 'Very secure',
useCase: 'High-security applications',
speed: 'Slower but more secure'
}
};
2. Password Hashing
Secure Password Storage
Hashing Implementation
class PasswordHasher {
async hashPassword(password, salt = null) {
// Generate salt if not provided
if (!salt) {
const saltArray = new Uint8Array(16);
crypto.getRandomValues(saltArray);
salt = Array.from(saltArray, byte => byte.toString(16).padStart(2, '0')).join('');
}
// Combine password and salt
const encoder = new TextEncoder();
const data = encoder.encode(password + salt);
// Hash using SHA-256
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = new Uint8Array(hashBuffer);
const hashHex = Array.from(hashArray, byte => byte.toString(16).padStart(2, '0')).join('');
return {
hash: hashHex,
salt: salt,
algorithm: 'SHA-256'
};
}
async verifyPassword(password, storedHash, salt) {
const result = await this.hashPassword(password, salt);
return this.constantTimeEquals(result.hash, storedHash);
}
constantTimeEquals(a, b) {
if (a.length !== b.length) {
return false;
}
let result = 0;
for (let i = 0; i < a.length; i++) {
result |= a.charCodeAt(i) ^ b.charCodeAt(i);
}
return result === 0;
}
}
Advanced Password Hashing (PBKDF2)
Key Derivation Function
class PBKDF2Hasher {
async hashPassword(password, salt = null, iterations = 100000) {
if (!salt) {
const saltArray = new Uint8Array(16);
crypto.getRandomValues(saltArray);
salt = saltArray;
} else if (typeof salt === 'string') {
salt = new TextEncoder().encode(salt);
}
const encoder = new TextEncoder();
const keyMaterial = await crypto.subtle.importKey(
'raw',
encoder.encode(password),
'PBKDF2',
false,
['deriveBits']
);
const derivedBits = await crypto.subtle.deriveBits(
{
name: 'PBKDF2',
salt: salt,
iterations: iterations,
hash: 'SHA-256'
},
keyMaterial,
256
);
return {
hash: Array.from(new Uint8Array(derivedBits), byte =>
byte.toString(16).padStart(2, '0')
).join(''),
salt: Array.from(salt, byte =>
byte.toString(16).padStart(2, '0')
).join(''),
iterations: iterations
};
}
}
3. File Integrity Verification
File Hash Calculation
File Hashing Implementation
class FileHasher {
async calculateFileHash(file, algorithm = 'SHA-256') {
const arrayBuffer = await file.arrayBuffer();
const hashBuffer = await crypto.subtle.digest(algorithm, arrayBuffer);
return Array.from(new Uint8Array(hashBuffer), byte =>
byte.toString(16).padStart(2, '0')
).join('');
}
async calculateStreamHash(stream, algorithm = 'SHA-256') {
const reader = stream.getReader();
let hash = await crypto.subtle.digest(algorithm, new ArrayBuffer(0));
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
// For streaming, you'd need a more complex implementation
// This is a simplified version
const combined = new Uint8Array(hash.byteLength + value.length);
combined.set(new Uint8Array(hash));
combined.set(value, hash.byteLength);
hash = await crypto.subtle.digest(algorithm, combined);
}
} finally {
reader.releaseLock();
}
return Array.from(new Uint8Array(hash), byte =>
byte.toString(16).padStart(2, '0')
).join('');
}
verifyFileIntegrity(file, expectedHash, algorithm = 'SHA-256') {
return this.calculateFileHash(file, algorithm)
.then(actualHash => actualHash.toLowerCase() === expectedHash.toLowerCase());
}
}