1. SHA 算法简介
SHA(Secure Hash Algorithm)是一组密码学哈希函数,由美国国家安全局(NSA)设计,美国国家标准与技术研究院(NIST)发布。
2. 主要 SHA 算法对比
算法 | 输出长度 | 安全性 | 应用场景 |
---|---|---|---|
SHA-1 | 160位 | 已破解 | 不推荐使用 |
SHA-224 | 224位 | 安全 | 一般用途 |
SHA-256 | 256位 | 安全 | 最常用 |
SHA-384 | 384位 | 安全 | 高安全性 |
SHA-512 | 512位 | 安全 | 极高安全性 |
SHA3-256 | 256位 | 安全 | 新一代算法 |
3. Python 中使用 SHA 算法
基本用法
import hashlib
# 创建哈希对象
hash_object = hashlib.sha256()
# 更新数据(可以分多次)
hash_object.update(b"Hello")
hash_object.update(b" World")
# 获取哈希值
hex_digest = hash_object.hexdigest()
print(hex_digest)
所有 SHA 算法示例
import hashlib
def demo_all_sha_algorithms():
data = b"Hello World"
print("=== SHA 算法演示 ===")
print(f"原始数据: {data.decode()}")
print()
# SHA-1 (不推荐使用)
sha1 = hashlib.sha1(data).hexdigest()
print(f"SHA-1: {sha1}")
# SHA-2 系列
sha224 = hashlib.sha224(data).hexdigest()
print(f"SHA-224: {sha224}")
sha256 = hashlib.sha256(data).hexdigest()
print(f"SHA-256: {sha256}")
sha384 = hashlib.sha384(data).hexdigest()
print(f"SHA-384: {sha384}")
sha512 = hashlib.sha512(data).hexdigest()
print(f"SHA-512: {sha512}")
# SHA-3 系列 (需要Python 3.6+)
if hasattr(hashlib, 'sha3_256'):
sha3_256 = hashlib.sha3_256(data).hexdigest()
print(f"SHA3-256: {sha3_256}")
sha3_512 = hashlib.sha3_512(data).hexdigest()
print(f"SHA3-512: {sha3_512}")
demo_all_sha_algorithms()
4. 文件哈希计算
import hashlib
def calculate_file_hash(filename, algorithm='sha256'):
"""计算文件的哈希值"""
hash_func = getattr(hashlib, algorithm)()
try:
with open(filename, 'rb') as f:
# 分块读取大文件,避免内存不足
for chunk in iter(lambda: f.read(4096), b""):
hash_func.update(chunk)
return hash_func.hexdigest()
except FileNotFoundError:
return None
# 使用示例
file_hash = calculate_file_hash('example.txt', 'sha256')
print(f"文件哈希: {file_hash}")
5. 密码验证系统
import hashlib
import os
class PasswordManager:
def __init__(self):
self.salt_length = 16
def generate_salt(self):
"""生成随机盐值"""
return os.urandom(self.salt_length)
def hash_password(self, password, salt=None):
"""哈希密码(加盐)"""
if salt is None:
salt = self.generate_salt()
# 密码 + 盐值
salted_password = password.encode() + salt
# 多次哈希增加安全性
hashed = hashlib.sha256(salted_password).digest()
hashed = hashlib.sha256(hashed + salted_password).hexdigest()
return hashed, salt
def verify_password(self, password, stored_hash, salt):
"""验证密码"""
test_hash, _ = self.hash_password(password, salt)
return test_hash == stored_hash
# 使用示例
pm = PasswordManager()
# 注册用户
password = "mysecret123"
hashed_password, salt = pm.hash_password(password)
print(f"哈希密码: {hashed_password}")
print(f"盐值: {salt.hex()}")
# 验证密码
is_valid = pm.verify_password("mysecret123", hashed_password, salt)
print(f"密码验证: {is_valid}")
is_valid_wrong = pm.verify_password("wrongpass", hashed_password, salt)
print(f"错误密码验证: {is_valid_wrong}")
6. 批量文件完整性检查
import hashlib
import json
from pathlib import Path
class FileIntegrityChecker:
def __init__(self):
self.checksums = {}
def create_checksum_file(self, directory, output_file='checksums.json'):
"""创建文件的校验和记录"""
directory = Path(directory)
for file_path in directory.rglob('*'):
if file_path.is_file():
file_hash = self.calculate_file_hash(file_path)
relative_path = str(file_path.relative_to(directory))
self.checksums[relative_path] = file_hash
with open(output_file, 'w') as f:
json.dump(self.checksums, f, indent=2)
print(f"已生成 {len(self.checksums)} 个文件的校验和")
def verify_integrity(self, directory, checksum_file='checksums.json'):
"""验证文件完整性"""
with open(checksum_file, 'r') as f:
original_checksums = json.load(f)
changes = {'modified': [], 'added': [], 'deleted': []}
directory = Path(directory)
# 检查现有文件
for relative_path, original_hash in original_checksums.items():
file_path = directory / relative_path
if not file_path.exists():
changes['deleted'].append(relative_path)
else:
current_hash = self.calculate_file_hash(file_path)
if current_hash != original_hash:
changes['modified'].append(relative_path)
# 检查新增文件
current_files = {str(p.relative_to(directory)) for p in directory.rglob('*') if p.is_file()}
original_files = set(original_checksums.keys())
changes['added'] = list(current_files - original_files)
return changes
def calculate_file_hash(self, file_path, algorithm='sha256'):
"""计算文件哈希"""
hash_func = getattr(hashlib, algorithm)()
with open(file_path, 'rb') as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_func.update(chunk)
return hash_func.hexdigest()
# 使用示例
checker = FileIntegrityChecker()
# 创建校验和
checker.create_checksum_file('./my_folder')
# 验证完整性(稍后运行)
changes = checker.verify_integrity('./my_folder')
print("文件变化:", changes)
7. 性能测试比较
import hashlib
import time
import string
import random
def performance_test():
"""测试不同SHA算法的性能"""
# 生成测试数据
test_data = ''.join(random.choices(string.ascii_letters + string.digits, k=1024 * 1024)) # 1MB
test_data = test_data.encode()
algorithms = ['sha1', 'sha224', 'sha256', 'sha384', 'sha512']
if hasattr(hashlib, 'sha3_256'):
algorithms.extend(['sha3_256', 'sha3_512'])
results = {}
for algo in algorithms:
start_time = time.time()
# 运行100次取平均
for _ in range(100):
getattr(hashlib, algo)(test_data).hexdigest()
end_time = time.time()
avg_time = (end_time - start_time) / 100
results[algo] = avg_time
print(f"{algo.upper():<8}: {avg_time:.6f} 秒/次")
return results
# 运行性能测试
performance_test()
8.密码学基础案例 密码 "123456"
# 根据密码123456 推算出来哈希值(SHA-256是单向加密哈希函数)
import hashlib
# hashlib.sha256(b"123456").hexdigest()
hash_result = hashlib.sha256(b"123456").hexdigest()
print(hash_result)
# 输出 '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'
9.密码破解方法
# 方法1:已知常见密码尝试
import hashlib
def crack_hash(target_hash):
# 常见密码列表
common_passwords = [
"123456", "password", "123456789", "12345678", "12345",
"1234567", "1234567890", "qwerty", "abc123", "111111",
"123123", "admin", "letmein", "welcome", "monkey"
]
for password in common_passwords:
# 计算哈希值
hashed = hashlib.sha256(password.encode()).hexdigest()
if hashed == target_hash:
print(f"找到密码: {password}")
return password
print("未找到匹配的密码")
return None
# 要破解的哈希值
target_hash = "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92"
# 尝试破解
crack_hash(target_hash)
-----------------------------------------------------------------------------------------
# 方法2:数字组合暴力破解
import hashlib
import itertools
def brute_force_numeric(target_hash, max_length=6):
"""尝试所有数字组合"""
digits = "0123456789"
for length in range(1, max_length + 1):
print(f"正在尝试 {length} 位数字组合...")
for combination in itertools.product(digits, repeat=length):
password = ''.join(combination)
hashed = hashlib.sha256(password.encode()).hexdigest()
if hashed == target_hash:
print(f"找到密码: {password}")
return password
print("未找到匹配的密码")
return None
target_hash = "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92"
brute_force_numeric(target_hash)
-----------------------------------------------------------------------------------------
# 方法3:使用彩虹表(预先计算的哈希表)
import hashlib
# 简单的预计算彩虹表
rainbow_table = {
"123456": "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92",
"password": "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8",
"123456789": "15e2b0d3c33891ebb0f1ef609ec419420c20e320ce94c65fbc8c3312448eb225",
# 可以添加更多预计算的哈希值
}
def crack_with_rainbow_table(target_hash, table):
for password, hashed in table.items():
if hashed == target_hash:
print(f"从彩虹表中找到密码: {password}")
return password
print("彩虹表中未找到匹配的密码")
return None
target_hash = "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92"
crack_with_rainbow_table(target_hash, rainbow_table)
-----------------------------------------------------------------------------------------
# 方法4:完整的密码破解工具
import hashlib
import itertools
import string
import time
class PasswordCracker:
def __init__(self):
self.found = False
self.password = None
def crack(self, target_hash, charset=None, max_length=8):
"""主破解函数"""
if charset is None:
charset = string.digits # 默认只尝试数字
start_time = time.time()
for length in range(1, max_length + 1):
print(f"尝试长度: {length} 字符")
for combination in itertools.product(charset, repeat=length):
test_pass = ''.join(combination)
hashed = hashlib.sha256(test_pass.encode()).hexdigest()
if hashed == target_hash:
end_time = time.time()
print(f"成功! 密码: {test_pass}")
print(f"耗时: {end_time - start_time:.2f} 秒")
self.found = True
self.password = test_pass
return test_pass
print("破解失败")
return None
# 使用示例
cracker = PasswordCracker()
target_hash = "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92"
# 只尝试数字(因为知道密码是纯数字)
result = cracker.crack(target_hash, charset="0123456789", max_length=6)
10. 安全建议
-
不要使用 SHA-1:已被证明不安全
-
推荐使用 SHA-256:平衡安全性和性能
-
密码存储必须加盐:防止彩虹表攻击
-
考虑使用专门密码哈希函数:如 bcrypt、Argon2
-
定期更新算法:跟上密码学发展