SHA 系列算法教程
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 hashlibdef 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 hashlibdef 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 osclass PasswordManager:def __init__(self):self.salt_length = 16def 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, saltdef 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 Pathclass 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_hashwith 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_pathif 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 changesdef 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 randomdef performance_test():"""测试不同SHA算法的性能"""# 生成测试数据test_data = ''.join(random.choices(string.ascii_letters + string.digits, k=1024 * 1024)) # 1MBtest_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) / 100results[algo] = avg_timeprint(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 hashlibdef 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 passwordprint("未找到匹配的密码")return None# 要破解的哈希值
target_hash = "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92"# 尝试破解
crack_hash(target_hash)
-----------------------------------------------------------------------------------------
# 方法2:数字组合暴力破解
import hashlib
import itertoolsdef 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 passwordprint("未找到匹配的密码")return Nonetarget_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 passwordprint("彩虹表中未找到匹配的密码")return Nonetarget_hash = "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92"
crack_with_rainbow_table(target_hash, rainbow_table)
-----------------------------------------------------------------------------------------
# 方法4:完整的密码破解工具
import hashlib
import itertools
import string
import timeclass PasswordCracker:def __init__(self):self.found = Falseself.password = Nonedef 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 = Trueself.password = test_passreturn test_passprint("破解失败")return None# 使用示例
cracker = PasswordCracker()
target_hash = "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92"# 只尝试数字(因为知道密码是纯数字)
result = cracker.crack(target_hash, charset="0123456789", max_length=6)
10. 安全建议
不要使用 SHA-1:已被证明不安全
推荐使用 SHA-256:平衡安全性和性能
密码存储必须加盐:防止彩虹表攻击
考虑使用专门密码哈希函数:如 bcrypt、Argon2
定期更新算法:跟上密码学发展