SHA-256 Security-Focused API Documentation
Version: 1.0
Last Updated: 2025-07-05
**Security Classification: PUBLIC
Author: Phantom (phantom@metamui.id)
Overview
SHA-256 is a cryptographic hash function that produces a 256-bit (32-byte) hash value. Part of the SHA-2 family designed by the NSA, it’s widely used for data integrity, digital signatures, and proof-of-work systems. This documentation provides security-focused guidance for using SHA-256 in the MetaMUI cryptographic library.
Security Level: 128-bit collision resistance
Output Size: 32 bytes (256 bits)
Block Size: 64 bytes (512 bits)
Security Warnings ⚠️
- Not for Passwords: NEVER use SHA-256 directly for password hashing - use Argon2
- Not a MAC: SHA-256 alone doesn’t provide authentication - use HMAC-SHA256
- Length Extension: Vulnerable to length extension attacks in certain constructions
- Not Encryption: Hash functions are one-way, they cannot encrypt data
- Quantum Vulnerable: Grover’s algorithm reduces security to 128 bits
API Functions
hash(data: bytes) -> bytes[32]
Security Contract:
- Preconditions:
datacan be any length up to 2^64 - 1 bits- Input data should be complete (no streaming state exposed)
- Postconditions:
- Returns deterministic 32-byte hash
- Same input always produces same output
- Input data not retained in memory
Attack Resistance: | Attack Type | Protected | Notes | |————-|———–|——-| | Collision | ✅ | 2^128 operations required | | Preimage | ✅ | 2^256 operations required | | Second Preimage | ✅ | 2^256 operations required | | Length Extension | ❌ | Vulnerable in naive constructions | | Timing Attack | ✅ | Constant time for same length |
Security Requirements:
- Do NOT use for password storage
- Do NOT use as a MAC without HMAC construction
- Do NOT assume hiding input length
- Consider SHA-512/256 for length extension resistance
Secure Usage Example:
# SECURE: File integrity verification
def verify_file_integrity(filepath: str, expected_hash: str) -> bool:
sha256 = SHA256()
with open(filepath, 'rb') as f:
# Process in chunks to handle large files
while chunk := f.read(8192):
sha256.update(chunk)
computed_hash = sha256.finalize()
# Constant-time comparison
return hmac.compare_digest(
computed_hash.hex(),
expected_hash.lower()
)
# SECURE: Content addressing
def content_address(data: bytes) -> str:
"""Generate content-based identifier"""
return f"sha256:{sha256(data).hex()}"
Common Mistakes:
# INSECURE: Password hashing
def store_password(password: str):
# NEVER DO THIS - easily cracked!
password_hash = sha256(password.encode())
database.save(password_hash)
# INSECURE: Simple MAC construction
def create_mac(key: bytes, message: bytes) -> bytes:
# Vulnerable to length extension!
return sha256(key + message)
# INSECURE: Using as encryption
def "encrypt"(data: bytes, key: bytes) -> bytes:
# This is NOT encryption!
return sha256(key + data)
create() -> SHA256Context
Security Contract:
- Preconditions:
- System has sufficient memory for context
- Postconditions:
- Returns fresh hash context
- Context initialized to SHA-256 initial values
- No data from previous operations
Security Notes:
- Context contains partial hash state
- Should not be serialized/stored
- Must be finalized to get hash
Secure Usage Example:
// SECURE: Streaming large file
fn hash_large_file(path: &Path) -> Result<[u8; 32], Error> {
let mut file = File::open(path)?;
let mut hasher = Sha256::create();
let mut buffer = [0u8; 16384];
loop {
let count = file.read(&mut buffer)?;
if count == 0 {
break;
}
hasher.update(&buffer[..count]);
}
Ok(hasher.finalize())
}
// SECURE: Multiple data sources
fn hash_request(headers: &[Header], body: &[u8]) -> [u8; 32] {
let mut hasher = Sha256::create();
// Hash headers
for header in headers {
hasher.update(header.name.as_bytes());
hasher.update(b": ");
hasher.update(header.value.as_bytes());
hasher.update(b"\r\n");
}
hasher.update(b"\r\n");
// Hash body
hasher.update(body);
hasher.finalize()
}
update(data: bytes) -> void
Security Contract:
- Preconditions:
- Context must be initialized via
create() - Context must not be finalized
- Context must be initialized via
- Postconditions:
- Internal state updated with new data
- Can be called multiple times
- Order matters - hash depends on sequence
Security Requirements:
- Total data must not exceed 2^64 - 1 bits
- Order of updates affects final hash
- Cannot “undo” an update operation
Secure Usage Example:
// SECURE: Hashing structured data
class SecureDataHasher {
private hasher: SHA256Context;
constructor() {
this.hasher = sha256.create();
}
addField(name: string, value: string): void {
// Include field boundaries to prevent ambiguity
const encoded = `${name.length}:${name}${value.length}:${value}`;
this.hasher.update(Buffer.from(encoded, 'utf-8'));
}
finalize(): Buffer {
return this.hasher.finalize();
}
}
// Prevents collision between different structures
const h1 = new SecureDataHasher();
h1.addField("name", "value");
h1.addField("", "namevalue");
const h2 = new SecureDataHasher();
h2.addField("", "namevalue");
h2.addField("name", "value");
// h1.finalize() !== h2.finalize()
finalize() -> bytes[32]
Security Contract:
- Preconditions:
- Context must be initialized
- Can be called only once per context
- Postconditions:
- Returns final 32-byte hash
- Context is consumed/invalidated
- Includes proper padding
Security Notes:
- Automatically applies SHA-256 padding
- Context cannot be reused after finalize
- Result is safe to share publicly
Security Best Practices
Data Integrity
class SecureFileManager:
def __init__(self):
self.hash_algorithm = "sha256"
def store_file(self, data: bytes, metadata: dict) -> str:
# Calculate hash for integrity
file_hash = sha256(data)
# Include metadata in integrity check
meta_bytes = json.dumps(metadata, sort_keys=True).encode()
combined_hash = sha256(file_hash + sha256(meta_bytes))
# Store with hash
file_id = combined_hash.hex()
self.storage.put(file_id, {
'data': data,
'metadata': metadata,
'hash': file_hash.hex(),
'meta_hash': sha256(meta_bytes).hex()
})
return file_id
def retrieve_file(self, file_id: str) -> tuple[bytes, dict]:
stored = self.storage.get(file_id)
# Verify data integrity
if sha256(stored['data']).hex() != stored['hash']:
raise IntegrityError("File data corrupted")
# Verify metadata integrity
meta_bytes = json.dumps(stored['metadata'], sort_keys=True).encode()
if sha256(meta_bytes).hex() != stored['meta_hash']:
raise IntegrityError("File metadata corrupted")
return stored['data'], stored['metadata']
Commitment Schemes
/// Secure commitment using SHA-256
pub struct Commitment {
commitment: [u8; 32],
}
impl Commitment {
pub fn create(value: &[u8], nonce: &[u8; 32]) -> Self {
let mut hasher = Sha256::create();
hasher.update(nonce);
hasher.update(value);
Self {
commitment: hasher.finalize(),
}
}
pub fn verify(&self, value: &[u8], nonce: &[u8; 32]) -> bool {
let check = Self::create(value, nonce);
constant_time_eq(&self.commitment, &check.commitment)
}
}
// Usage
let secret = b"my bid is $1000";
let nonce = random_bytes::<32>();
let commitment = Commitment::create(secret, &nonce);
// Later: reveal
assert!(commitment.verify(secret, &nonce));
Merkle Trees
class MerkleTree:
"""Secure Merkle tree implementation"""
def __init__(self, leaves: List[bytes]):
self.leaves = [sha256(leaf) for leaf in leaves]
self.tree = self._build_tree(self.leaves)
def _build_tree(self, nodes: List[bytes]) -> List[List[bytes]]:
tree = [nodes]
while len(nodes) > 1:
next_level = []
for i in range(0, len(nodes), 2):
if i + 1 < len(nodes):
# Hash pair with ordering
left, right = nodes[i], nodes[i + 1]
combined = sha256(b'\x00' + left + right)
else:
# Odd node - promote as-is
combined = nodes[i]
next_level.append(combined)
tree.append(next_level)
nodes = next_level
return tree
def get_root(self) -> bytes:
return self.tree[-1][0] if self.tree else sha256(b'')
def get_proof(self, index: int) -> List[Tuple[bytes, bool]]:
"""Generate inclusion proof for leaf at index"""
proof = []
for level in range(len(self.tree) - 1):
level_nodes = self.tree[level]
is_right_node = index % 2 == 1
sibling_index = index - 1 if is_right_node else index + 1
if sibling_index < len(level_nodes):
proof.append((level_nodes[sibling_index], is_right_node))
index //= 2
return proof
Common Integration Patterns
Blockchain/Proof-of-Work
def mine_block(block_data: dict, difficulty: int) -> dict:
"""Mine block with proof-of-work using SHA-256"""
target = 2 ** (256 - difficulty)
nonce = 0
block_bytes = json.dumps(block_data, sort_keys=True).encode()
while True:
candidate = block_bytes + nonce.to_bytes(8, 'little')
hash_value = sha256(sha256(candidate)) # Double SHA-256
if int.from_bytes(hash_value, 'big') < target:
return {
**block_data,
'nonce': nonce,
'hash': hash_value.hex()
}
nonce += 1
Git-style Content Addressing
pub fn create_git_hash(object_type: &str, content: &[u8]) -> String {
let header = format!("{} {}\0", object_type, content.len());
let mut hasher = Sha256::create();
hasher.update(header.as_bytes());
hasher.update(content);
format!("sha256:{}", hex::encode(hasher.finalize()))
}
Performance Considerations
| Input Size | Time | Throughput | Notes |
|---|---|---|---|
| 64 bytes | ~500 ns | 128 MB/s | One block |
| 1 KB | ~2 μs | 500 MB/s | Optimal size |
| 1 MB | ~2 ms | 500 MB/s | Large file |
| 1 GB | ~2 s | 500 MB/s | Memory mapped |
Hardware Acceleration:
- Intel SHA extensions: 5-10x speedup
- ARM crypto extensions: 3-5x speedup
- GPU implementations: For parallel hashing
Platform-Specific Security Notes
Python
- Use
hashlib.sha256()- C implementation - Avoid pure Python implementations
update()doesn’t copy data
Rust
- Use
sha2crate withasmfeature - Zero-copy with slices
- Compile-time optimization available
TypeScript/JavaScript
- WebCrypto API preferred for browsers
- Node.js
cryptomodule is native - Avoid pure JS implementations
Swift
- Use CryptoKit framework (iOS 13+)
- CommonCrypto for older versions
- Hardware acceleration automatic
Kotlin
- Java MessageDigest for JVM
- Native implementations for multiplatform
- Android hardware acceleration varies
Compliance and Standards
- FIPS 180-4: SHA-256 specification
- NIST SP 800-107: Hash function recommendations
- Common Criteria: EAL4+ validated implementations
- RFC 6234: SHA-256 test vectors
Security Auditing
Verification Checklist
- Never using for password storage
- Not constructing naive MACs
- Handling large files in chunks
- Using constant-time comparison for hashes
- Not relying on secrecy of hash function
- Considering quantum resistance needs
Anti-Patterns to Detect
# AUDIT: Search for these dangerous patterns
# ❌ Password hashing
sha256(password)
# ❌ Keyed hash without HMAC
sha256(key + data)
# ❌ Assuming encryption
encrypted = sha256(plaintext + key)
# ❌ Weak randomness
nonce = sha256(str(time.time()))
Migration Guidelines
From MD5/SHA-1
# Step 1: Parallel hashing during transition
def migrate_hash(data: bytes) -> dict:
return {
'legacy_md5': md5(data).hex(), # For compatibility
'legacy_sha1': sha1(data).hex(), # For compatibility
'sha256': sha256(data).hex(), # New standard
'algorithm': 'sha256' # Current algorithm
}
# Step 2: Verification supporting both
def verify_hash(data: bytes, hash_dict: dict) -> bool:
algorithm = hash_dict.get('algorithm', 'legacy_md5')
if algorithm == 'sha256':
return sha256(data).hex() == hash_dict['sha256']
elif algorithm == 'legacy_sha1':
return sha1(data).hex() == hash_dict['legacy_sha1']
else:
return md5(data).hex() == hash_dict['legacy_md5']
Security Analysis
Threat Model: SHA-256 Threat Model
The comprehensive threat analysis covers:
- Algorithm-specific attack vectors
- Implementation vulnerabilities
- Side-channel considerations
- Quantum resistance analysis (where applicable)
- Deployment recommendations
For complete security analysis and risk assessment, see the dedicated threat model documentation.
References
Support
Security Issues: security@metamui.id
Documentation Updates: phantom@metamui.id
Vulnerability Disclosure: See SECURITY.md
Document Version: 1.0
Review Cycle: Quarterly
Next Review: 2025-04-05
Classification: PUBLIC