初始提交,未完全测试
This commit is contained in:
107
kit/HashKit.py
Normal file
107
kit/HashKit.py
Normal file
@@ -0,0 +1,107 @@
|
||||
#!/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
|
||||
Reference in New Issue
Block a user