SHA-224 Python SDK
Our Python SDK provides an efficient and easy-to-use implementation of the SHA-224 cryptographic hash function for Python applications.
Pure Python Option
Optional pure Python implementation for environments without C extensions.
C-based Implementation
High-performance C extension for optimal speed in critical applications.
Stream Processing
Efficiently process large files and streams with incremental hashing.
Type Annotations
Full type hints support for modern Python development.
Async Support
Asynchronous APIs for non-blocking operation in async environments.
REST API Integration
Built-in client for the SHA224.com REST API.
Installation
Install the SHA-224 Python SDK using pip:
pip install sha224
The package supports Python 3.7+ and is tested on Windows, macOS, and Linux.
Requirements
- Python 3.7 or higher
- Optional: C compiler for building the C extension (falls back to pure Python if unavailable)
- Optional:
requests
for API client functionality - Optional:
aiohttp
for async API client functionality
Installing from Source
git clone https://github.com/sha224-org/sha224-python.git
cd sha224-python
pip install -e .
Quick Start
Generate SHA-224 hashes with just a few lines of code:
from sha224 import sha224, SHA224Hash
# Hash a string
hash_value = sha224("Hello, world!")
print(hash_value) # '8552d8b7a7dc5476cb9e25dee69a8091290764b7f2a64fe6e78e9568'
# Hash binary data
binary_data = b"Hello, world!"
binary_hash = sha224(binary_data)
print(binary_hash)
# Incremental hashing
hasher = SHA224Hash()
hasher.update("Hello, ")
hasher.update("world!")
incremental_hash = hasher.hexdigest()
print(incremental_hash) # Same as above
# Verify a hash
is_valid = sha224.verify("8552d8b7a7dc5476cb9e25dee69a8091290764b7f2a64fe6e78e9568", "Hello, world!")
print(is_valid) # True
Using the API Client
from sha224 import SHA224API
# Initialize the API client
api = SHA224API(api_key="YOUR_API_KEY")
# Hash using the API
api_hash = api.hash_text("Hello, world!")
print(api_hash)
# Verify a hash using the API
is_valid = api.verify("8552d8b7a7dc5476cb9e25dee69a8091290764b7f2a64fe6e78e9568", "Hello, world!")
print(is_valid) # True
API Reference
sha224(data, *, encoding='utf-8', output_format='hex')
Computes a SHA-224 hash of the input data.
Parameters
data
(str | bytes | bytearray | memoryview | io.BufferedReader) - The data to hashencoding
(str, optional) - Encoding to use for string input (ignored for binary input). Default: 'utf-8'output_format
(str, optional) - Output format: 'hex' (default), 'bytes', or 'base64'
Returns
str | bytes
- The SHA-224 hash of the input
Example
# Hash a string
hash_hex = sha224("Hello, world!") # Returns a hex string
# Hash bytes with base64 output
hash_base64 = sha224(b"Binary data", output_format="base64")
# Hash a file
with open("file.txt", "rb") as f:
file_hash = sha224(f)
sha224.verify(expected_hash, data, *, encoding='utf-8')
Verifies if the provided data matches the expected hash.
Parameters
expected_hash
(str) - The expected SHA-224 hashdata
(str | bytes | bytearray | memoryview | io.BufferedReader) - The data to verifyencoding
(str, optional) - Encoding to use for string input (ignored for binary input). Default: 'utf-8'
Returns
bool
- True if the hash matches, False otherwise
Example
expected = "8552d8b7a7dc5476cb9e25dee69a8091290764b7f2a64fe6e78e9568"
is_valid = sha224.verify(expected, "Hello, world!")
print(is_valid) # True
sha224.file(file_path, *, output_format='hex', buffer_size=65536)
Computes a SHA-224 hash of a file.
Parameters
file_path
(str | os.PathLike) - Path to the file to hashoutput_format
(str, optional) - Output format: 'hex' (default), 'bytes', or 'base64'buffer_size
(int, optional) - Size of chunks to read. Default: 65536 (64 KB)
Returns
str | bytes
- The SHA-224 hash of the file
Example
# Hash a file
file_hash = sha224.file("large_file.bin")
print(file_hash)
# Hash a file with custom buffer size
file_hash_large_buffer = sha224.file("large_file.bin", buffer_size=1048576) # 1 MB chunks
sha224.verify_file(expected_hash, file_path, *, buffer_size=65536)
Verifies if a file matches the expected hash.
Parameters
expected_hash
(str) - The expected SHA-224 hashfile_path
(str | os.PathLike) - Path to the file to verifybuffer_size
(int, optional) - Size of chunks to read. Default: 65536 (64 KB)
Returns
bool
- True if the hash matches, False otherwise
Example
# Verify a file
expected_hash = "8552d8b7a7dc5476cb9e25dee69a8091290764b7f2a64fe6e78e9568"
is_valid_file = sha224.verify_file(expected_hash, "file.txt")
print(is_valid_file)
class SHA224Hash
Class for incremental hashing of data chunks.
Methods
update(data, *, encoding='utf-8')
- Updates the hash with new datadigest()
- Returns the digest as byteshexdigest()
- Returns the digest as a hex stringbase64digest()
- Returns the digest as a base64 stringcopy()
- Returns a copy of the hasher object
Example
from sha224 import SHA224Hash
# Create a hash instance
hasher = SHA224Hash()
# Update with chunks of data
hasher.update("Hello, ")
hasher.update(b"world!")
# Get the final hash as a hex string
hex_hash = hasher.hexdigest()
print(hex_hash)
# Get the final hash as bytes
bytes_hash = hasher.digest()
# Get the final hash as base64
base64_hash = hasher.base64digest()
# Create a copy midway
hasher_copy = hasher.copy()
hasher.update("Additional data")
print(hasher.hexdigest()) # Different from hex_hash
print(hasher_copy.hexdigest()) # Same as hex_hash
class SHA224API
Client for the SHA224.com REST API.
Constructor
SHA224API(
api_key=None,
endpoint="https://api.sha224.com/v1",
timeout=10,
retry_attempts=3,
verify_ssl=True
)
Methods
hash_text(text, *, encoding='utf-8')
- Hashes text using the APIhash_file(file_path, *, buffer_size=None)
- Hashes a file using the APIverify(expected_hash, data, *, encoding='utf-8')
- Verifies a hash using the APIbatch_hash(items, *, encoding='utf-8')
- Hashes multiple text items in one requestbatch_verify(items, *, encoding='utf-8')
- Verifies multiple hash-text pairs in one request
Example
from sha224 import SHA224API
# Initialize the API client
api = SHA224API(
api_key="YOUR_API_KEY",
endpoint="https://api.sha224.com/v1",
timeout=5 # 5 seconds
)
# Hash text using the API
api_hash = api.hash_text("Hello, world!")
print(api_hash)
# Verify a hash using the API
is_valid = api.verify(
"8552d8b7a7dc5476cb9e25dee69a8091290764b7f2a64fe6e78e9568",
"Hello, world!"
)
print(is_valid)
# Batch hash multiple items
batch_results = api.batch_hash([
{"id": "item1", "text": "First item"},
{"id": "item2", "text": "Second item"},
{"id": "item3", "text": "Third item"}
])
print(batch_results)
async_sha224 Module
Asynchronous API for SHA-224 operations.
Functions
async_sha224.hash(data, *, encoding='utf-8', output_format='hex')
- Asynchronously computes a SHA-224 hashasync_sha224.verify(expected_hash, data, *, encoding='utf-8')
- Asynchronously verifies a hashasync_sha224.file(file_path, *, output_format='hex', buffer_size=65536)
- Asynchronously hashes a fileasync_sha224.verify_file(expected_hash, file_path, *, buffer_size=65536)
- Asynchronously verifies a file hash
Classes
async_sha224.AsyncSHA224Hash
- Asynchronous incremental hasherasync_sha224.AsyncSHA224API
- Asynchronous API client
Example
import asyncio
from sha224 import async_sha224
async def main():
# Hash a string asynchronously
hash_value = await async_sha224.hash("Hello, world!")
print(hash_value)
# Hash a file asynchronously
file_hash = await async_sha224.file("large_file.bin")
print(file_hash)
# Use the async API client
api = async_sha224.AsyncSHA224API(api_key="YOUR_API_KEY")
api_hash = await api.hash_text("Hello, world!")
print(api_hash)
# Batch operations
results = await api.batch_hash([
{"id": "item1", "text": "First item"},
{"id": "item2", "text": "Second item"}
])
print(results)
# Run the async function
asyncio.run(main())
Examples
Basic Usage Examples
Hashing Different Data Types
from sha224 import sha224
# Hash a string (default encoding is utf-8)
text_hash = sha224("Hello, world!")
print(f"String hash: {text_hash}")
# Hash with different string encoding
utf16_hash = sha224("Hello, world!", encoding="utf-16")
print(f"UTF-16 string hash: {utf16_hash}")
# Hash bytes
bytes_hash = sha224(b"Hello, world!")
print(f"Bytes hash: {bytes_hash}")
# Hash bytearray
bytearray_hash = sha224(bytearray(b"Hello, world!"))
print(f"Bytearray hash: {bytearray_hash}")
# Hash integers converted to bytes
integer_bytes = (12345).to_bytes(4, byteorder="big")
int_hash = sha224(integer_bytes)
print(f"Integer hash: {int_hash}")
# Different output formats
hex_output = sha224("test", output_format="hex")
bytes_output = sha224("test", output_format="bytes")
base64_output = sha224("test", output_format="base64")
print(f"Hex output: {hex_output}")
print(f"Bytes output: {bytes_output}")
print(f"Base64 output: {base64_output}")
Incremental Hashing
from sha224 import SHA224Hash
# Create a hasher instance
hasher = SHA224Hash()
# Update with different chunks of data
hasher.update("Part 1: ")
hasher.update("Part 2: ")
hasher.update(b"Binary part") # Can mix string and binary updates
# Get the final hash
final_hash = hasher.hexdigest()
print(f"Incremental hash: {final_hash}")
# Clone a hasher at a specific point
hasher_clone = hasher.copy()
hasher.update(" Additional data")
print(f"Original hasher: {hasher.hexdigest()}")
print(f"Cloned hasher: {hasher_clone.hexdigest()}")
Hash Verification
from sha224 import sha224
# Create a hash
data = "Important data to verify"
original_hash = sha224(data)
print(f"Original hash: {original_hash}")
# Later, verify the data hasn't been modified
is_valid = sha224.verify(original_hash, data)
print(f"Valid data: {is_valid}") # True
# Verify modified data
modified_data = "Important data to verify!"
is_modified_valid = sha224.verify(original_hash, modified_data)
print(f"Valid modified data: {is_modified_valid}") # False
# Comparing hashes correctly (constant-time comparison)
from sha224.utils import constant_time_compare
hash1 = sha224("data1")
hash2 = sha224("data2")
hash3 = sha224("data1")
print(constant_time_compare(hash1, hash2)) # False
print(constant_time_compare(hash1, hash3)) # True
File Hashing Examples
Hashing Files
from sha224 import sha224
# Hash a small file
small_file_hash = sha224.file("small_file.txt")
print(f"Small file hash: {small_file_hash}")
# Hash a large file with progress reporting
import os
from sha224 import SHA224Hash
def hash_large_file_with_progress(file_path, buffer_size=1048576): # 1 MB chunks
file_size = os.path.getsize(file_path)
bytes_read = 0
hasher = SHA224Hash()
with open(file_path, "rb") as file:
while True:
data = file.read(buffer_size)
if not data:
break
hasher.update(data)
bytes_read += len(data)
progress = bytes_read / file_size * 100
print(f"Progress: {progress:.2f}%")
return hasher.hexdigest()
large_file_hash = hash_large_file_with_progress("large_file.bin")
print(f"Large file hash: {large_file_hash}")
Directory Hashing
import os
from sha224 import sha224, SHA224Hash
def hash_directory(directory_path):
"""Compute a hash of all files in a directory (recursively)."""
if not os.path.isdir(directory_path):
raise ValueError(f"{directory_path} is not a directory")
# Get all files sorted by path for consistency
file_paths = []
for root, _, files in os.walk(directory_path):
for file in files:
file_paths.append(os.path.join(root, file))
file_paths.sort()
# Create a master hasher
master_hasher = SHA224Hash()
# Hash each file and add its path and hash to the master hasher
for file_path in file_paths:
rel_path = os.path.relpath(file_path, directory_path)
file_hash = sha224.file(file_path)
# Add the relative path and hash to the master hash
master_hasher.update(rel_path.encode('utf-8'))
master_hasher.update(file_hash.encode('utf-8'))
print(f"Hashed: {rel_path} - {file_hash}")
return master_hasher.hexdigest()
# Hash a project directory
project_hash = hash_directory("./my_project")
print(f"Project hash: {project_hash}")
File Verification
from sha224 import sha224
# Create a hash of a file
original_file_hash = sha224.file("important_document.pdf")
# Save the hash somewhere
with open("important_document.pdf.sha224", "w") as f:
f.write(original_file_hash)
# Later, verify the file hasn't been modified
def verify_file_integrity(file_path, hash_file_path):
with open(hash_file_path, "r") as f:
expected_hash = f.read().strip()
is_valid = sha224.verify_file(expected_hash, file_path)
return is_valid
# Check if the file is still valid
is_valid = verify_file_integrity(
"important_document.pdf",
"important_document.pdf.sha224"
)
print(f"File integrity valid: {is_valid}")
API Client Examples
Basic API Usage
from sha224 import SHA224API
# Initialize the API client
api = SHA224API(api_key="YOUR_API_KEY")
# Hash text using the API
api_hash = api.hash_text("Hello, world!")
print(f"API hash: {api_hash}")
# Hash with custom encoding
api_hash_latin1 = api.hash_text("Café", encoding="latin-1")
print(f"API hash (latin-1): {api_hash_latin1}")
# Verify a hash
is_valid = api.verify(
"8552d8b7a7dc5476cb9e25dee69a8091290764b7f2a64fe6e78e9568",
"Hello, world!"
)
print(f"Hash verification: {is_valid}") # True
Batch Operations
from sha224 import SHA224API
# Initialize the API client
api = SHA224API(api_key="YOUR_API_KEY")
# Batch hash multiple strings
items_to_hash = [
{"id": "user1", "text": "Password123"},
{"id": "user2", "text": "SecurePass456"},
{"id": "user3", "text": "StrongPassword789"}
]
batch_results = api.batch_hash(items_to_hash)
print("Batch hash results:")
for item in batch_results["results"]:
print(f"ID: {item['id']}, Hash: {item['hash']}")
# Later, verify multiple hashes at once
items_to_verify = [
{
"id": "user1",
"hash": batch_results["results"][0]["hash"],
"text": "Password123"
},
{
"id": "user2",
"hash": batch_results["results"][1]["hash"],
"text": "WrongPassword" # This one should fail
},
{
"id": "user3",
"hash": batch_results["results"][2]["hash"],
"text": "StrongPassword789"
}
]
verify_results = api.batch_verify(items_to_verify)
print("\nBatch verify results:")
for item in verify_results["results"]:
print(f"ID: {item['id']}, Valid: {item['valid']}")
Advanced API Configuration
from sha224 import SHA224API
import logging
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("sha224.api")
# Create an API client with custom settings
api = SHA224API(
api_key="YOUR_API_KEY",
endpoint="https://api.sha224.com/v1",
timeout=5, # 5 seconds timeout
retry_attempts=3, # Retry up to 3 times
verify_ssl=True # Verify SSL certificates
)
# Hash with error handling
try:
result = api.hash_text("Test text")
print(f"Hash result: {result}")
except Exception as e:
logger.error(f"API error: {e}")
# Using a proxy
import requests
session = requests.Session()
session.proxies = {
"http": "http://proxy.example.com:8080",
"https": "https://proxy.example.com:8080"
}
api_with_proxy = SHA224API(
api_key="YOUR_API_KEY",
session=session # Pass custom session
)
proxy_result = api_with_proxy.hash_text("Proxied request")
print(f"Proxy result: {proxy_result}")
Async API Examples
Basic Async Usage
import asyncio
from sha224 import async_sha224
async def basic_async_example():
# Hash a string asynchronously
hash_value = await async_sha224.hash("Hello, world!")
print(f"Async hash: {hash_value}")
# Hash a file asynchronously
file_hash = await async_sha224.file("document.pdf")
print(f"Async file hash: {file_hash}")
# Verify a hash asynchronously
is_valid = await async_sha224.verify(
"8552d8b7a7dc5476cb9e25dee69a8091290764b7f2a64fe6e78e9568",
"Hello, world!"
)
print(f"Async verification: {is_valid}")
# Run the async function
asyncio.run(basic_async_example())
Async Incremental Hashing
import asyncio
from sha224 import async_sha224
async def incremental_async_example():
# Create an async hasher
hasher = async_sha224.AsyncSHA224Hash()
# Update with data
await hasher.update("First part")
await hasher.update(" and second part")
# Get the digest
hash_value = await hasher.hexdigest()
print(f"Async incremental hash: {hash_value}")
# Clone and continue
hasher_clone = await hasher.copy()
await hasher.update(" and more data")
hash_value = await hasher.hexdigest()
clone_hash = await hasher_clone.hexdigest()
print(f"Final hash: {hash_value}")
print(f"Clone hash: {clone_hash}")
asyncio.run(incremental_async_example())
Async API Client
import asyncio
from sha224 import async_sha224
async def async_api_example():
# Initialize the async API client
api = async_sha224.AsyncSHA224API(api_key="YOUR_API_KEY")
# Hash using the API
hash_value = await api.hash_text("Hello, world!")
print(f"Async API hash: {hash_value}")
# Batch operations
items_to_hash = [
{"id": "item1", "text": "First item"},
{"id": "item2", "text": "Second item"},
{"id": "item3", "text": "Third item"}
]
batch_results = await api.batch_hash(items_to_hash)
print("Batch hash results:")
for item in batch_results["results"]:
print(f"ID: {item['id']}, Hash: {item['hash']}")
asyncio.run(async_api_example())
Parallel Async Processing
import asyncio
import os
from sha224 import async_sha224
async def hash_file_task(file_path):
file_hash = await async_sha224.file(file_path)
return {"path": file_path, "hash": file_hash}
async def parallel_file_hashing(directory):
"""Hash all files in a directory in parallel."""
file_paths = []
for root, _, files in os.walk(directory):
for file in files:
file_paths.append(os.path.join(root, file))
# Process all files in parallel
tasks = [hash_file_task(file_path) for file_path in file_paths]
results = await asyncio.gather(*tasks)
# Sort by file path for consistent output
results.sort(key=lambda x: x["path"])
return results
async def main():
print("Starting parallel file hashing...")
results = await parallel_file_hashing("./project_directory")
print(f"Processed {len(results)} files:")
for result in results:
print(f"{result['path']}: {result['hash']}")
asyncio.run(main())
Testing
The SHA-224 Python SDK comes with a comprehensive test suite that verifies its functionality against known test vectors.
Running Tests
# Install test dependencies
pip install -e ".[test]"
# Run tests
pytest
# Run with coverage
pytest --cov=sha224
Test Vectors
The SDK includes standard test vectors to verify the correctness of the SHA-224 implementation:
from sha224 import sha224
# NIST test vectors
test_vectors = [
{
"input": "",
"expected": "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"
},
{
"input": "abc",
"expected": "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"
},
{
"input": "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"expected": "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525"
}
]
# Verify test vectors
for vector in test_vectors:
result = sha224(vector["input"])
assert result == vector["expected"], f"Failed test vector: {vector['input']}"
print(f"Passed: {vector['input']} => {result}")
Performance Testing
You can benchmark the performance of the SHA-224 implementation:
import time
import random
from sha224 import sha224, SHA224Hash
def benchmark_sha224(data_size, iterations=100):
"""Benchmark SHA-224 performance."""
# Generate random data of specified size
data = bytes(random.getrandbits(8) for _ in range(data_size))
# Benchmark single-call hashing
start_time = time.time()
for _ in range(iterations):
sha224(data)
single_call_time = time.time() - start_time
# Benchmark incremental hashing
start_time = time.time()
for _ in range(iterations):
hasher = SHA224Hash()
hasher.update(data)
hasher.hexdigest()
incremental_time = time.time() - start_time
print(f"Data size: {data_size} bytes")
print(f"Single-call time: {single_call_time:.4f}s for {iterations} iterations")
print(f"Incremental time: {incremental_time:.4f}s for {iterations} iterations")
print(f"Single-call speed: {data_size * iterations / single_call_time / 1024 / 1024:.2f} MB/s")
print(f"Incremental speed: {data_size * iterations / incremental_time / 1024 / 1024:.2f} MB/s")
# Run benchmarks for different data sizes
data_sizes = [10, 100, 1000, 10000, 100000, 1000000]
for size in data_sizes:
benchmark_sha224(size)
print()
Frequently Asked Questions
SHA-224, a truncated version of SHA-256, provides a good balance between security and efficiency. It generates smaller hash values (224 bits vs. 256 bits) while maintaining strong security properties. This makes it ideal for applications with space constraints or when you need to balance security with performance.
However, if maximum security is your priority and space isn't a constraint, SHA-256 might be more appropriate. For a detailed comparison, see our SHA-224 vs SHA-256 comparison.
The SDK includes both implementations and automatically selects the most efficient one available:
- C implementation: Used by default when compiled successfully. Provides optimal performance.
- Pure Python implementation: Used as a fallback when the C extension cannot be compiled or when explicitly requested.
You can check which implementation is being used:
from sha224 import is_using_c_extension
print(f"Using C extension: {is_using_c_extension()}")
You can also force the use of the pure Python implementation:
import sha224
sha224.force_pure_python()
The asynchronous API provides non-blocking versions of all core functions. This is particularly useful in async applications (like web servers) where you don't want to block the event loop during CPU-intensive operations like hashing.
The async API works by:
- Using
asyncio.to_thread()
to run CPU-bound operations in a separate thread pool - Using
aiohttp
for non-blocking HTTP requests to the SHA224.com API - Providing async versions of all core methods that can be awaited
This allows you to hash data or files without blocking your application's main event loop.
For large files, you should use the streaming/incremental approach:
from sha224 import SHA224Hash
def hash_large_file(file_path, buffer_size=1048576): # 1 MB chunks
hasher = SHA224Hash()
with open(file_path, "rb") as file:
while True:
data = file.read(buffer_size)
if not data:
break
hasher.update(data)
return hasher.hexdigest()
For even larger files or better performance in async environments, consider using the async file hashing with a suitable buffer size:
import asyncio
from sha224 import async_sha224
async def hash_very_large_file(file_path):
# 8 MB chunks for better throughput with large files
return await async_sha224.file(file_path, buffer_size=8388608)
You can also use the SHA224.com API for very large files, which processes them server-side:
from sha224 import SHA224API
api = SHA224API(api_key="YOUR_API_KEY")
hash_value = api.hash_file("very_large_file.bin")
Yes, the SDK is thread-safe with some considerations:
- The
sha224()
function and all top-level functions are fully thread-safe and can be called from multiple threads concurrently. - Each
SHA224Hash
instance maintains its own state and should not be shared between threads without proper synchronization. For thread safety, create separate hasher instances for each thread or use appropriate locking mechanisms if sharing is necessary. - The
SHA224API
client is thread-safe for making concurrent requests, as it uses a thread-safe session object internally.
For multi-threaded applications, it's recommended to use a thread pool for parallel hashing operations:
from concurrent.futures import ThreadPoolExecutor
from sha224 import sha224
files_to_hash = ["file1.txt", "file2.bin", "file3.pdf"]
with ThreadPoolExecutor() as executor:
results = list(executor.map(sha224.file, files_to_hash))
for file, hash_value in zip(files_to_hash, results):
print(f"{file}: {hash_value}")