SHA-512 Security-Focused API Documentation
Version: 1.0
Last Updated: 2025-07-05
**Security Classification: PUBLIC
Author: Phantom (phantom@metamui.id)
Overview
SHA-512 is a cryptographic hash function that produces a 512-bit (64-byte) hash value. Part of the SHA-2 family, it offers higher security margins than SHA-256 and is often preferred for applications requiring long-term security or higher collision resistance. SHA-512 is particularly efficient on 64-bit platforms.
Security Level: 256-bit collision resistance
Output Size: 64 bytes (512 bits)
Block Size: 128 bytes (1024 bits)
Security Warnings ⚠️
- Not for Passwords: NEVER use SHA-512 directly for passwords - use Argon2
- Not a MAC: SHA-512 alone doesn’t authenticate - use HMAC-SHA512
- Length Extension: Vulnerable like SHA-256 - use SHA-512/256 to prevent
- Truncation Weakens: Don’t truncate output without careful analysis
- Quantum Security: Grover’s algorithm reduces to 256-bit security
API Functions
hash(data: bytes) -> bytes[64]
Security Contract:
- Preconditions:
datacan be any length up to 2^128 - 1 bits- Input should be complete (for simple API)
- Postconditions:
- Returns deterministic 64-byte hash
- Same input always produces same output
- One-way: cannot recover input from hash
Attack Resistance: | Attack Type | Protected | Notes | |————-|———–|——-| | Collision | ✅ | 2^256 operations required | | Preimage | ✅ | 2^512 operations required | | Second Preimage | ✅ | 2^512 operations required | | Length Extension | ❌ | Vulnerable - use HMAC or SHA-512/256 | | Timing Attack | ✅ | Constant time for same length |
Security Requirements:
- Never use for password storage
- Add authentication with HMAC for MACs
- Consider SHA-512/256 for length extension resistance
- Use SHA3-512 for quantum resistance needs
Secure Usage Example:
import hashlib
import hmac
from typing import List, Tuple
import json
class SecureHashingService:
"""Secure SHA-512 usage patterns"""
@staticmethod
def hash_file_content(filepath: str, chunk_size: int = 8192) -> str:
"""Hash large file efficiently"""
sha512 = hashlib.sha512()
with open(filepath, 'rb') as f:
while chunk := f.read(chunk_size):
sha512.update(chunk)
return sha512.hexdigest()
@staticmethod
def create_merkle_root(leaves: List[bytes]) -> bytes:
"""Build Merkle tree with SHA-512"""
if not leaves:
return hashlib.sha512(b"empty-tree").digest()
# Hash all leaves
current_level = [hashlib.sha512(leaf).digest() for leaf in leaves]
while len(current_level) > 1:
next_level = []
for i in range(0, len(current_level), 2):
if i + 1 < len(current_level):
# Hash pair with separator
combined = b"\x00" + current_level[i] + b"\x01" + current_level[i + 1]
else:
# Odd node - promote
combined = b"\x02" + current_level[i]
next_level.append(hashlib.sha512(combined).digest())
current_level = next_level
return current_level[0]
@staticmethod
def hash_structured_data(data: dict) -> bytes:
"""Hash structured data canonically"""
# Canonical JSON encoding
canonical = json.dumps(data, sort_keys=True, separators=(',', ':'))
# Include type identifier
typed_data = b"JSON:" + canonical.encode('utf-8')
return hashlib.sha512(typed_data).digest()
@staticmethod
def create_commitment(value: bytes, nonce: bytes) -> Tuple[bytes, bytes]:
"""Create hash-based commitment"""
# Commitment = H(nonce || value)
commitment = hashlib.sha512(nonce + value).digest()
return commitment, nonce
@staticmethod
def verify_commitment(value: bytes, nonce: bytes, commitment: bytes) -> bool:
"""Verify hash commitment"""
expected = hashlib.sha512(nonce + value).digest()
return hmac.compare_digest(expected, commitment)
# SECURE: Content addressing with verification
class ContentAddressableStorage:
def __init__(self):
self.storage = {}
def store(self, content: bytes, metadata: dict = None) -> str:
"""Store content with SHA-512 address"""
# Hash content
content_hash = hashlib.sha512(content).digest()
# Include metadata in verification
if metadata:
meta_bytes = json.dumps(metadata, sort_keys=True).encode()
meta_hash = hashlib.sha512(meta_bytes).digest()
# Combined verification hash
combined = hashlib.sha512(
b"CONTENT:" + content_hash +
b"META:" + meta_hash
).digest()
address = combined.hex()
else:
address = content_hash.hex()
# Store with integrity data
self.storage[address] = {
'content': content,
'content_hash': content_hash,
'metadata': metadata,
'stored_at': time.time()
}
return address
def retrieve(self, address: str) -> Tuple[bytes, dict]:
"""Retrieve and verify content"""
if address not in self.storage:
raise KeyError("Content not found")
stored = self.storage[address]
# Verify content integrity
actual_hash = hashlib.sha512(stored['content']).digest()
if not hmac.compare_digest(actual_hash, stored['content_hash']):
raise IntegrityError("Content corrupted")
return stored['content'], stored['metadata']
# SECURE: Using SHA-512/256 to prevent length extension
def sha512_256(data: bytes) -> bytes:
"""SHA-512/256 - truncated SHA-512 for length extension resistance"""
# Full SHA-512 hash
full_hash = hashlib.sha512(data).digest()
# Return first 256 bits (32 bytes)
# This prevents length extension attacks
return full_hash[:32]
def create_secure_mac(key: bytes, message: bytes) -> bytes:
"""Create MAC using HMAC-SHA512"""
# HMAC prevents length extension attacks
return hmac.new(key, message, hashlib.sha512).digest()
Common Mistakes:
# INSECURE: Password hashing
password_hash = hashlib.sha512(password.encode()).hexdigest() # NO!
# INSECURE: Simple MAC construction
def bad_mac(key: bytes, message: bytes) -> bytes:
return hashlib.sha512(key + message).digest() # Length extension!
# INSECURE: Using as encryption
def bad_encrypt(data: bytes, key: bytes) -> bytes:
return hashlib.sha512(key + data).digest() # Not encryption!
# INSECURE: Truncating without analysis
short_hash = hashlib.sha512(data).digest()[:8] # Only 64 bits!
create() -> SHA512Context
Security Contract:
- Preconditions:
- System has sufficient memory
- Postconditions:
- Returns fresh SHA-512 context
- Context initialized to standard initial values
- Ready for update() calls
Security Notes:
- Context contains partial state
- Should not be serialized with secrets
- Thread-safe per instance
Secure Usage Example:
use sha2::{Sha512, Digest};
use std::io::{self, Read};
/// Secure streaming hash implementation
pub struct StreamingHasher {
hasher: Sha512,
bytes_processed: u64,
}
impl StreamingHasher {
pub fn new() -> Self {
Self {
hasher: Sha512::new(),
bytes_processed: 0,
}
}
pub fn update(&mut self, data: &[u8]) -> Result<(), Error> {
// Check for overflow (2^128 bit limit)
let new_total = self.bytes_processed
.saturating_add(data.len() as u64);
if new_total > (1u128 << 125) as u64 {
return Err(Error::InputTooLarge);
}
self.hasher.update(data);
self.bytes_processed = new_total;
Ok(())
}
pub fn finalize(self) -> [u8; 64] {
self.hasher.finalize().into()
}
pub fn finalize_reset(&mut self) -> [u8; 64] {
let result = self.hasher.clone().finalize();
self.hasher.reset();
self.bytes_processed = 0;
result.into()
}
}
/// Hash with progress callback
pub fn hash_with_progress<R: Read, F: Fn(u64)>(
mut input: R,
mut progress_callback: F,
) -> io::Result<[u8; 64]> {
let mut hasher = Sha512::new();
let mut buffer = [0u8; 16384]; // 16KB buffer
let mut total_bytes = 0u64;
loop {
let count = input.read(&mut buffer)?;
if count == 0 {
break;
}
hasher.update(&buffer[..count]);
total_bytes += count as u64;
// Report progress
progress_callback(total_bytes);
}
Ok(hasher.finalize().into())
}
/// Parallel hashing for multiple inputs
pub fn hash_parallel(inputs: &[&[u8]]) -> Vec<[u8; 64]> {
use rayon::prelude::*;
inputs.par_iter()
.map(|input| {
let mut hasher = Sha512::new();
hasher.update(input);
hasher.finalize().into()
})
.collect()
}
update(data: bytes) -> void
Security Contract:
- Preconditions:
- Context created and not finalized
- Total input ≤ 2^128 - 1 bits
- Postconditions:
- Internal state updated
- Can be called multiple times
- Order affects final hash
Security Requirements:
- Total data must stay within limits
- Order of updates matters
- Cannot undo updates
Secure Usage Example:
import { createHash } from 'crypto';
class SecureDocumentHasher {
private hasher = createHash('sha512');
private sections: string[] = [];
addSection(name: string, content: Buffer): void {
// Include section boundaries to prevent collision
this.hasher.update(`[SECTION:${name}:${content.length}]`);
this.hasher.update(content);
this.hasher.update('[/SECTION]');
this.sections.push(name);
}
addMetadata(metadata: Record<string, any>): void {
// Canonical encoding for metadata
const canonical = JSON.stringify(metadata, Object.keys(metadata).sort());
this.hasher.update('[METADATA]');
this.hasher.update(canonical);
this.hasher.update('[/METADATA]');
}
finalize(): { hash: string; manifest: any } {
const hash = this.hasher.digest('hex');
return {
hash,
manifest: {
algorithm: 'SHA-512',
sections: this.sections,
timestamp: new Date().toISOString()
}
};
}
}
// Secure multi-source hashing
class MultiSourceHasher {
private hasher = createHash('sha512');
private sourceCount = 0;
addSource(sourceId: string, data: Buffer): void {
// Unambiguous encoding
const header = Buffer.alloc(4 + 32 + 8);
header.writeUInt32BE(this.sourceCount, 0);
header.write(sourceId.padEnd(32, '\0'), 4);
header.writeBigUInt64BE(BigInt(data.length), 36);
this.hasher.update(header);
this.hasher.update(data);
this.sourceCount++;
}
getHash(): Buffer {
// Include source count in final hash
const countBuffer = Buffer.alloc(4);
countBuffer.writeUInt32BE(this.sourceCount, 0);
this.hasher.update(countBuffer);
return this.hasher.digest();
}
}
finalize() -> bytes[64]
Security Contract:
- Preconditions:
- Context has been created
- Can be called only once per context
- Postconditions:
- Returns final 64-byte hash
- Includes proper padding
- Context is consumed
Security Notes:
- Automatically applies SHA-512 padding
- Result is safe to share publicly
- Context cannot be reused
Security Best Practices
Digital Signatures with SHA-512
class Ed25519WithSHA512:
"""Ed25519 signatures with explicit SHA-512 usage"""
@staticmethod
def sign_large_message(private_key: bytes, message: bytes) -> bytes:
"""Sign message with pre-hashing for large messages"""
# For messages > 1MB, pre-hash with SHA-512
if len(message) > 1024 * 1024:
# Create pre-hash
message_hash = hashlib.sha512(message).digest()
# Sign the hash with domain separation
to_sign = b"SHA512-PREHASH:" + message_hash
signature = ed25519_sign(private_key, to_sign)
return signature
else:
# Sign directly for small messages
return ed25519_sign(private_key, message)
@staticmethod
def verify_large_message(
public_key: bytes,
message: bytes,
signature: bytes
) -> bool:
"""Verify signature with pre-hashing"""
if len(message) > 1024 * 1024:
message_hash = hashlib.sha512(message).digest()
to_verify = b"SHA512-PREHASH:" + message_hash
return ed25519_verify(public_key, to_verify, signature)
else:
return ed25519_verify(public_key, message, signature)
HMAC-SHA512 Patterns
use hmac::{Hmac, Mac};
use sha2::Sha512;
type HmacSha512 = Hmac<Sha512>;
/// Secure API authentication with HMAC-SHA512
pub struct ApiAuthenticator {
signing_key: Vec<u8>,
}
impl ApiAuthenticator {
pub fn new(master_key: &[u8]) -> Self {
// Derive signing key
let mut mac = HmacSha512::new_from_slice(master_key)
.expect("HMAC can take key of any size");
mac.update(b"API-Signing-Key-v1");
let signing_key = mac.finalize().into_bytes().to_vec();
Self { signing_key }
}
pub fn create_request_signature(
&self,
method: &str,
path: &str,
body: &[u8],
timestamp: u64,
) -> String {
// Create canonical request
let canonical = format!(
"{}\n{}\n{}\n{}",
method,
path,
hex::encode(Sha512::digest(body)),
timestamp
);
// Sign with HMAC-SHA512
let mut mac = HmacSha512::new_from_slice(&self.signing_key)
.expect("HMAC can take key of any size");
mac.update(canonical.as_bytes());
base64::encode(mac.finalize().into_bytes())
}
pub fn verify_request_signature(
&self,
method: &str,
path: &str,
body: &[u8],
timestamp: u64,
signature: &str,
) -> Result<(), Error> {
// Check timestamp freshness (5 minute window)
let current_time = SystemTime::now()
.duration_since(UNIX_EPOCH)?
.as_secs();
if (current_time as i64 - timestamp as i64).abs() > 300 {
return Err(Error::RequestExpired);
}
// Recreate signature
let expected = self.create_request_signature(
method, path, body, timestamp
);
// Constant-time comparison
if !constant_time_eq(expected.as_bytes(), signature.as_bytes()) {
return Err(Error::InvalidSignature);
}
Ok(())
}
}
Key Derivation with SHA-512
def derive_keys_sha512(master_secret: bytes, context: str) -> dict:
"""Derive multiple keys using SHA-512 based KDF"""
# Use HKDF with SHA-512 for higher security
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
hkdf = HKDF(
algorithm=hashes.SHA512(),
length=128, # 4 × 32-byte keys
salt=b"KeyDerivation-SHA512-v1",
info=context.encode()
)
key_material = hkdf.derive(master_secret)
return {
'encryption_key': key_material[0:32],
'signing_key': key_material[32:64],
'storage_key': key_material[64:96],
'backup_key': key_material[96:128]
}
class SHA512XOF:
"""Extended output using SHA-512 (like SHAKE)"""
def __init__(self, seed: bytes):
self.seed = seed
def extract(self, length: int, context: bytes = b"") -> bytes:
"""Extract arbitrary length output"""
output = b""
counter = 0
while len(output) < length:
# Hash seed || context || counter
h = hashlib.sha512()
h.update(self.seed)
h.update(context)
h.update(counter.to_bytes(8, 'big'))
output += h.digest()
counter += 1
return output[:length]
Common Integration Patterns
Blockchain Proof-of-Work
def mine_block_sha512(block_data: dict, difficulty: int) -> dict:
"""Mine block using SHA-512 (educational example)"""
block_bytes = json.dumps(block_data, sort_keys=True).encode()
target = 2 ** (512 - difficulty)
nonce = 0
while True:
candidate = block_bytes + nonce.to_bytes(8, 'big')
# Double SHA-512 (like Bitcoin but with SHA-512)
hash1 = hashlib.sha512(candidate).digest()
hash2 = hashlib.sha512(hash1).digest()
if int.from_bytes(hash2, 'big') < target:
return {
**block_data,
'nonce': nonce,
'hash': hash2.hex()
}
nonce += 1
Password-Based Key Derivation
/// PBKDF2-HMAC-SHA512 for cases where Argon2 isn't available
pub fn pbkdf2_sha512(
password: &[u8],
salt: &[u8],
iterations: u32,
key_length: usize,
) -> Vec<u8> {
use pbkdf2::pbkdf2_hmac;
let mut key = vec![0u8; key_length];
pbkdf2_hmac::<Sha512>(
password,
salt,
iterations,
&mut key
);
key
}
/// Secure password verification with SHA-512
pub struct PasswordVerifier {
iterations: u32,
}
impl PasswordVerifier {
pub fn new(iterations: u32) -> Self {
// NIST recommends minimum 10,000 iterations
assert!(iterations >= 10_000);
Self { iterations }
}
pub fn hash_password(&self, password: &str) -> String {
let salt = generate_random_bytes(32);
let key = pbkdf2_sha512(
password.as_bytes(),
&salt,
self.iterations,
64 // Full SHA-512 output
);
// Encode as storable string
format!(
"$pbkdf2-sha512${}${}${}",
self.iterations,
base64::encode(&salt),
base64::encode(&key)
)
}
}
Performance Considerations
| Operation | SHA-256 | SHA-512 | Notes |
|---|---|---|---|
| Small message (<64B) | ~500 ns | ~600 ns | SHA-256 slightly faster |
| 1 KB message | ~2 μs | ~1.5 μs | SHA-512 faster on 64-bit |
| 1 MB message | ~2 ms | ~1.5 ms | SHA-512 more efficient |
| 64-bit platform | Baseline | 1.3x faster | SHA-512 optimized for 64-bit |
| 32-bit platform | Baseline | 0.7x speed | SHA-256 better on 32-bit |
When to Use SHA-512
- 64-bit platforms (better performance)
- Need higher security margins
- Large data hashing
- Long-term security requirements
- When output size isn’t a concern
When to Use SHA-256
- 32-bit platforms
- Space-constrained environments
- Compatibility requirements
- Shorter hash outputs needed
Security Auditing
Verification Checklist
- Not used for password hashing
- HMAC used for authentication
- No direct secret hashing
- Length extension attacks considered
- Appropriate truncation if used
- Collision resistance requirements met
Code Review Patterns
# ✅ GOOD: HMAC for authentication
auth_tag = hmac.new(key, message, hashlib.sha512).digest()
# ❌ BAD: Direct concatenation
auth_tag = hashlib.sha512(key + message).digest()
# ✅ GOOD: KDF for key derivation
derived_key = hkdf(master_key, salt, info, hashlib.sha512)
# ❌ BAD: Direct hashing for keys
derived_key = hashlib.sha512(master_key + purpose).digest()
# ✅ GOOD: Proper password hashing
password_hash = argon2.hash(password)
# ❌ BAD: SHA-512 for passwords
password_hash = hashlib.sha512(password + salt).digest()
Security Analysis
Threat Model: SHA-512 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