83 lines
2.3 KiB
Python
83 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from hashlib import md5, sha1, sha256, blake2b, _Hash as Hash
|
|
from zlib import crc32
|
|
from typing import Self, Protocol
|
|
from AnP.Utils.Checks import Check
|
|
|
|
class HashAlgorithm(Protocol):
|
|
def update(self:Self, data:bytes) -> None: ...
|
|
def hexdigest(self:Self) -> str: ...
|
|
|
|
class CRC32HashAlgorithm(HashAlgorithm):
|
|
|
|
def __init__(self:Self) -> None:
|
|
self.__value:int = 0
|
|
|
|
def update(self:Self, data:bytes) -> None:
|
|
self.__value = crc32(data, self.__value)
|
|
|
|
def hexdigest(self:Self) -> str:
|
|
return f"{self.__value & 0xFFFFFFFF:08x}"
|
|
|
|
class HashModel():
|
|
|
|
@staticmethod
|
|
def algorithms() -> dict[str, type[HashAlgorithm|Hash]]:
|
|
return {
|
|
"md5" : md5,
|
|
"sha1" : sha1,
|
|
"sha256" : sha256,
|
|
"blake2b" : blake2b,
|
|
"crc32" : CRC32HashAlgorithm
|
|
}
|
|
|
|
def __init__(self:Self, data:bytes = b"", chunk_size:int = 4096) -> None:
|
|
|
|
self.__chunk_size:int = chunk_size
|
|
self.md5:str = ""
|
|
self.sha1:str = ""
|
|
self.sha256:str = ""
|
|
self.blake2b:str = ""
|
|
self.crc32:str = ""
|
|
self.__hashes:list[str] = list(self.algorithms().keys())
|
|
self.__algorithms:list[HashAlgorithm|Hash] = [
|
|
method() for method in list(self.algorithms().values())
|
|
]
|
|
|
|
len(data) and self.update(data)
|
|
|
|
def __update_chunk(self:Self, chunk:bytes) -> None:
|
|
for hash_algorithm in self.__algorithms:
|
|
hash_algorithm.update(chunk)
|
|
|
|
def update(self:Self, data:bytes|str, encode:str = "utf-8") -> None:
|
|
|
|
done:bool = False
|
|
|
|
if Check.is_string(data):
|
|
data = data.encode(encode)
|
|
|
|
if Check.is_binary(data):
|
|
|
|
while data:
|
|
|
|
chunk:bytes = data[:self.__chunk_size]
|
|
|
|
data = data[self.__chunk_size:]
|
|
self.__update_chunk(chunk)
|
|
|
|
done = True
|
|
|
|
if done:
|
|
|
|
name:str
|
|
|
|
for name in self.__hashes:
|
|
setattr(self, name, getattr(self.__algorithms[self.__hashes.index(name)], "hexdigest")())
|
|
|
|
return done
|
|
|
|
def compare(self:Self, other:Self) -> bool:
|
|
return all(getattr(self, name) == getattr(other, name) for name in self.__hashes) |