CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-cryptography

Cryptographic recipes and primitives for Python developers

Pending
Overview
Eval results
Files

hash-functions.mddocs/

Hash Functions

Cryptographic hash functions providing both one-shot hashing and incremental hash contexts. Includes SHA family, SHA-3, BLAKE2, MD5, SM3, and extendable output functions (XOFs).

Core Imports

from cryptography.hazmat.primitives import hashes

Capabilities

Hash Context Interface

All hash functions provide a consistent context-based interface for incremental hashing.

class Hash:
    def __init__(self, algorithm, backend=None):
        """
        Create hash context.
        
        Args:
            algorithm: Hash algorithm instance (SHA256(), BLAKE2b(), etc.)
            backend: Cryptographic backend (usually None for default)
        """
    
    def update(self, data: bytes) -> None:
        """
        Update hash with additional data.
        
        Args:
            data (bytes): Data to add to hash
        """
    
    def finalize(self) -> bytes:
        """
        Finalize hash and return digest.
        
        Returns:
            bytes: Hash digest
            
        Note:
            Cannot call update() after finalize()
        """
    
    def copy(self) -> 'Hash':
        """
        Create copy of current hash state.
        
        Returns:
            Hash: Independent copy of hash context
        """

class HashAlgorithm:
    """Abstract base class for hash algorithms"""
    
    @property
    def name(self) -> str:
        """Algorithm name"""
    
    @property
    def digest_size(self) -> int:
        """Digest size in bytes"""

Extendable Output Functions (XOFs)

XOFs can produce variable-length output.

class XOFHash:
    def __init__(self, algorithm, backend=None):
        """
        Create XOF hash context.
        
        Args:
            algorithm: XOF algorithm (SHAKE128(), SHAKE256())
            backend: Cryptographic backend
        """
    
    def update(self, data: bytes) -> None:
        """Update XOF with data"""
    
    def finalize(self, length: int) -> bytes:
        """
        Finalize XOF and return digest of specified length.
        
        Args:
            length (int): Desired output length in bytes
            
        Returns:
            bytes: XOF digest of requested length
        """
    
    def copy(self) -> 'XOFHash':
        """Create copy of XOF state"""

class ExtendableOutputFunction:
    """Abstract base for XOF algorithms"""
    
    @property
    def name(self) -> str:
        """Algorithm name"""

SHA-2 Family

Standard SHA-2 hash functions with fixed output sizes.

class SHA1:
    """
    SHA-1 hash algorithm (160-bit digest).
    
    Note: SHA-1 is cryptographically broken, use SHA-256 or higher.
    """
    name = "sha1"
    digest_size = 20

class SHA224:
    """SHA-224 hash algorithm (224-bit digest)"""
    name = "sha224" 
    digest_size = 28

class SHA256:
    """SHA-256 hash algorithm (256-bit digest)"""
    name = "sha256"
    digest_size = 32

class SHA384:
    """SHA-384 hash algorithm (384-bit digest)"""
    name = "sha384"
    digest_size = 48

class SHA512:
    """SHA-512 hash algorithm (512-bit digest)"""
    name = "sha512"
    digest_size = 64

class SHA512_224:
    """SHA-512/224 hash algorithm (224-bit digest from SHA-512)"""
    name = "sha512-224"
    digest_size = 28

class SHA512_256:
    """SHA-512/256 hash algorithm (256-bit digest from SHA-512)"""  
    name = "sha512-256"
    digest_size = 32

SHA-3 Family

NIST SHA-3 standard hash functions.

class SHA3_224:
    """SHA3-224 hash algorithm (224-bit digest)"""
    name = "sha3-224"
    digest_size = 28

class SHA3_256:
    """SHA3-256 hash algorithm (256-bit digest)"""
    name = "sha3-256" 
    digest_size = 32

class SHA3_384:
    """SHA3-384 hash algorithm (384-bit digest)"""
    name = "sha3-384"
    digest_size = 48

class SHA3_512:
    """SHA3-512 hash algorithm (512-bit digest)"""
    name = "sha3-512"
    digest_size = 64

class SHAKE128:
    """SHAKE128 extendable output function"""
    name = "shake128"

class SHAKE256:
    """SHAKE256 extendable output function"""
    name = "shake256"

BLAKE2 Family

High-performance cryptographic hash functions.

class BLAKE2b:
    def __init__(self, digest_size: int):
        """
        BLAKE2b hash algorithm with configurable output size.
        
        Args:
            digest_size (int): Output size in bytes (1-64)
        """
        
    @property
    def name(self) -> str:
        return "blake2b"
    
    @property
    def digest_size(self) -> int:
        """Configured digest size"""

class BLAKE2s:
    def __init__(self, digest_size: int):
        """
        BLAKE2s hash algorithm with configurable output size.
        
        Args:
            digest_size (int): Output size in bytes (1-32)
        """
        
    @property
    def name(self) -> str:
        return "blake2s"
    
    @property
    def digest_size(self) -> int:
        """Configured digest size"""

Other Hash Functions

class MD5:
    """
    MD5 hash algorithm (128-bit digest).
    
    Note: MD5 is cryptographically broken, use SHA-256 or higher.
    """
    name = "md5"
    digest_size = 16

class SM3:
    """SM3 hash algorithm (256-bit digest) - Chinese national standard"""
    name = "sm3"
    digest_size = 32

Usage Examples

Basic Hashing

from cryptography.hazmat.primitives import hashes

# One-shot hashing
data = b"Hello, World!"

# SHA-256
digest = hashes.Hash(hashes.SHA256())
digest.update(data)
hash_value = digest.finalize()
print(f"SHA-256: {hash_value.hex()}")

# SHA-3
digest = hashes.Hash(hashes.SHA3_256())
digest.update(data)
hash_value = digest.finalize()
print(f"SHA3-256: {hash_value.hex()}")

Incremental Hashing

from cryptography.hazmat.primitives import hashes

# Hash large data incrementally
hasher = hashes.Hash(hashes.SHA256())

# Process data in chunks
with open('large_file.bin', 'rb') as f:
    while chunk := f.read(8192):
        hasher.update(chunk)

final_hash = hasher.finalize()
print(f"File hash: {final_hash.hex()}")

Hash State Copying

from cryptography.hazmat.primitives import hashes

# Create base hash state
base_hasher = hashes.Hash(hashes.SHA256())
base_hasher.update(b"Common prefix")

# Create multiple branches from same state
hasher1 = base_hasher.copy()
hasher1.update(b"Branch 1 data")
hash1 = hasher1.finalize()

hasher2 = base_hasher.copy()  
hasher2.update(b"Branch 2 data")
hash2 = hasher2.finalize()

print(f"Hash 1: {hash1.hex()}")
print(f"Hash 2: {hash2.hex()}")

Extendable Output Functions (XOFs)

from cryptography.hazmat.primitives import hashes

# SHAKE128 - variable length output
data = b"Input data for XOF"
xof = hashes.XOFHash(hashes.SHAKE128())
xof.update(data)

# Generate different length outputs
short_output = xof.copy().finalize(16)  # 16 bytes
long_output = xof.copy().finalize(64)   # 64 bytes

print(f"Short SHAKE128: {short_output.hex()}")
print(f"Long SHAKE128: {long_output.hex()}")

# SHAKE256
xof256 = hashes.XOFHash(hashes.SHAKE256())
xof256.update(data)
output256 = xof256.finalize(32)
print(f"SHAKE256: {output256.hex()}")

BLAKE2 with Custom Output Size

from cryptography.hazmat.primitives import hashes

data = b"Data to hash with BLAKE2"

# BLAKE2b with 32-byte output
blake2b_32 = hashes.Hash(hashes.BLAKE2b(32))
blake2b_32.update(data)
hash_32 = blake2b_32.finalize()

# BLAKE2b with 64-byte output (maximum)
blake2b_64 = hashes.Hash(hashes.BLAKE2b(64))
blake2b_64.update(data)
hash_64 = blake2b_64.finalize()

print(f"BLAKE2b-32: {hash_32.hex()}")
print(f"BLAKE2b-64: {hash_64.hex()}")

# BLAKE2s with 16-byte output
blake2s_16 = hashes.Hash(hashes.BLAKE2s(16))
blake2s_16.update(data)
hash_16 = blake2s_16.finalize()
print(f"BLAKE2s-16: {hash_16.hex()}")

File Integrity Verification

from cryptography.hazmat.primitives import hashes
import os

class FileHasher:
    def __init__(self, algorithm=hashes.SHA256()):
        self.algorithm = algorithm
    
    def hash_file(self, filepath):
        """Compute hash of file"""
        hasher = hashes.Hash(self.algorithm)
        
        with open(filepath, 'rb') as f:
            while chunk := f.read(65536):  # 64KB chunks
                hasher.update(chunk)
        
        return hasher.finalize()
    
    def verify_file(self, filepath, expected_hash):
        """Verify file matches expected hash"""
        actual_hash = self.hash_file(filepath)
        return actual_hash == expected_hash

# Usage
file_hasher = FileHasher(hashes.SHA256())

# Compute file hash
file_hash = file_hasher.hash_file('document.pdf')
print(f"File hash: {file_hash.hex()}")

# Later, verify file integrity
is_valid = file_hasher.verify_file('document.pdf', file_hash)
print(f"File integrity: {'OK' if is_valid else 'FAILED'}")

Hash-based Message Authentication Code (HMAC) Integration

from cryptography.hazmat.primitives import hashes, hmac

# HMAC typically uses hash functions
key = b"secret_key_32_bytes_long_for_hmac"
message = b"Message to authenticate"

# HMAC-SHA256
h = hmac.HMAC(key, hashes.SHA256())
h.update(message)
signature = h.finalize()

print(f"HMAC-SHA256: {signature.hex()}")

# Verify HMAC
h_verify = hmac.HMAC(key, hashes.SHA256())
h_verify.update(message)
try:
    h_verify.verify(signature)
    print("HMAC verification: SUCCESS")
except Exception:
    print("HMAC verification: FAILED")

Password Hashing (with Key Derivation)

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
import os

def hash_password(password: str, salt: bytes = None) -> tuple:
    """Hash password using PBKDF2-HMAC-SHA256"""
    if salt is None:
        salt = os.urandom(16)
    
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,
        salt=salt,
        iterations=100000,  # OWASP recommended minimum
    )
    
    key = kdf.derive(password.encode())
    return key, salt

def verify_password(password: str, stored_hash: bytes, salt: bytes) -> bool:
    """Verify password against stored hash"""
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,
        salt=salt,
        iterations=100000,
    )
    
    try:
        kdf.verify(password.encode(), stored_hash)
        return True
    except Exception:
        return False

# Usage
password = "user_password123"

# Hash password for storage
password_hash, salt = hash_password(password)
print(f"Password hash: {password_hash.hex()}")
print(f"Salt: {salt.hex()}")

# Verify password
is_valid = verify_password(password, password_hash, salt)
print(f"Password valid: {is_valid}")

Security Considerations

  • Algorithm Selection: Use SHA-256 or higher for new applications
  • Legacy Algorithms: MD5 and SHA-1 are cryptographically broken
  • Performance: BLAKE2 offers excellent performance with strong security
  • XOF Usage: SHAKE functions useful for custom output lengths
  • Salt Usage: Always use random salts for password hashing
  • Incremental Hashing: More efficient for large data than loading into memory
  • State Management: Hash contexts cannot be used after finalization

Install with Tessl CLI

npx tessl i tessl/pypi-cryptography

docs

aead-ciphers.md

asymmetric-cryptography.md

hash-functions.md

index.md

key-derivation.md

key-serialization.md

message-authentication.md

symmetric-ciphers.md

symmetric-encryption.md

two-factor-auth.md

utilities.md

x509-certificates.md

tile.json