Files
py_enjoy/kit/HashKit.py
2026-02-27 14:37:10 +08:00

108 lines
2.9 KiB
Python

#!/usr/bin/env python3.9
# -*- coding: utf-8 -*-
"""
JFinal HashKit - Hash and Encryption Utilities
"""
import hashlib
import secrets
import threading
class HashKit:
"""Hash utility class"""
FNV_OFFSET_BASIS_64 = 0xcbf29ce484222325
FNV_PRIME_64 = 0x100000001b3
_HEX_DIGITS = "0123456789abcdef"
_CHAR_ARRAY = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
@staticmethod
def fnv1a64(key: str) -> int:
"""FNV-1a 64-bit hash"""
hash_val = HashKit.FNV_OFFSET_BASIS_64
for i in range(len(key)):
hash_val ^= ord(key[i])
hash_val *= HashKit.FNV_PRIME_64
return hash_val
@staticmethod
def md5(src_str: str) -> str:
"""MD5 hash"""
return HashKit._hash("md5", src_str)
@staticmethod
def sha1(src_str: str) -> str:
"""SHA-1 hash"""
return HashKit._hash("sha1", src_str)
@staticmethod
def sha256(src_str: str) -> str:
"""SHA-256 hash"""
return HashKit._hash("sha256", src_str)
@staticmethod
def sha384(src_str: str) -> str:
"""SHA-384 hash"""
return HashKit._hash("sha384", src_str)
@staticmethod
def sha512(src_str: str) -> str:
"""SHA-512 hash"""
return HashKit._hash("sha512", src_str)
@staticmethod
def _hash(algorithm: str, src_str: str) -> str:
"""Generic hash function"""
try:
md = hashlib.new(algorithm)
md.update(src_str.encode('utf-8'))
return HashKit.to_hex(md.digest())
except Exception as e:
raise RuntimeError(e)
@staticmethod
def to_hex(bytes_data: bytes) -> str:
"""Convert bytes to hex string"""
ret = []
for b in bytes_data:
ret.append(HashKit._HEX_DIGITS[(b >> 4) & 0x0f])
ret.append(HashKit._HEX_DIGITS[b & 0x0f])
return ''.join(ret)
@staticmethod
def generate_salt(salt_length: int) -> str:
"""Generate random salt"""
salt = []
for i in range(salt_length):
salt.append(secrets.choice(HashKit._CHAR_ARRAY))
return ''.join(salt)
@staticmethod
def generate_salt_for_sha256() -> str:
"""Generate salt for SHA-256"""
return HashKit.generate_salt(32)
@staticmethod
def generate_salt_for_sha512() -> str:
"""Generate salt for SHA-512"""
return HashKit.generate_salt(64)
@staticmethod
def generate_random_str(str_length: int) -> str:
"""Generate random string"""
return HashKit.generate_salt(str_length)
@staticmethod
def slow_equals(a: bytes, b: bytes) -> bool:
"""Timing-safe byte comparison"""
if a is None or b is None:
return False
if len(a) != len(b):
return False
diff = 0
for i in range(len(a)):
diff |= a[i] ^ b[i]
return diff == 0