0
# Hash Functions
1
2
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).
3
4
## Core Imports
5
6
```python
7
from cryptography.hazmat.primitives import hashes
8
```
9
10
## Capabilities
11
12
### Hash Context Interface
13
14
All hash functions provide a consistent context-based interface for incremental hashing.
15
16
```python { .api }
17
class Hash:
18
def __init__(self, algorithm, backend=None):
19
"""
20
Create hash context.
21
22
Args:
23
algorithm: Hash algorithm instance (SHA256(), BLAKE2b(), etc.)
24
backend: Cryptographic backend (usually None for default)
25
"""
26
27
def update(self, data: bytes) -> None:
28
"""
29
Update hash with additional data.
30
31
Args:
32
data (bytes): Data to add to hash
33
"""
34
35
def finalize(self) -> bytes:
36
"""
37
Finalize hash and return digest.
38
39
Returns:
40
bytes: Hash digest
41
42
Note:
43
Cannot call update() after finalize()
44
"""
45
46
def copy(self) -> 'Hash':
47
"""
48
Create copy of current hash state.
49
50
Returns:
51
Hash: Independent copy of hash context
52
"""
53
54
class HashAlgorithm:
55
"""Abstract base class for hash algorithms"""
56
57
@property
58
def name(self) -> str:
59
"""Algorithm name"""
60
61
@property
62
def digest_size(self) -> int:
63
"""Digest size in bytes"""
64
```
65
66
### Extendable Output Functions (XOFs)
67
68
XOFs can produce variable-length output.
69
70
```python { .api }
71
class XOFHash:
72
def __init__(self, algorithm, backend=None):
73
"""
74
Create XOF hash context.
75
76
Args:
77
algorithm: XOF algorithm (SHAKE128(), SHAKE256())
78
backend: Cryptographic backend
79
"""
80
81
def update(self, data: bytes) -> None:
82
"""Update XOF with data"""
83
84
def finalize(self, length: int) -> bytes:
85
"""
86
Finalize XOF and return digest of specified length.
87
88
Args:
89
length (int): Desired output length in bytes
90
91
Returns:
92
bytes: XOF digest of requested length
93
"""
94
95
def copy(self) -> 'XOFHash':
96
"""Create copy of XOF state"""
97
98
class ExtendableOutputFunction:
99
"""Abstract base for XOF algorithms"""
100
101
@property
102
def name(self) -> str:
103
"""Algorithm name"""
104
```
105
106
### SHA-2 Family
107
108
Standard SHA-2 hash functions with fixed output sizes.
109
110
```python { .api }
111
class SHA1:
112
"""
113
SHA-1 hash algorithm (160-bit digest).
114
115
Note: SHA-1 is cryptographically broken, use SHA-256 or higher.
116
"""
117
name = "sha1"
118
digest_size = 20
119
120
class SHA224:
121
"""SHA-224 hash algorithm (224-bit digest)"""
122
name = "sha224"
123
digest_size = 28
124
125
class SHA256:
126
"""SHA-256 hash algorithm (256-bit digest)"""
127
name = "sha256"
128
digest_size = 32
129
130
class SHA384:
131
"""SHA-384 hash algorithm (384-bit digest)"""
132
name = "sha384"
133
digest_size = 48
134
135
class SHA512:
136
"""SHA-512 hash algorithm (512-bit digest)"""
137
name = "sha512"
138
digest_size = 64
139
140
class SHA512_224:
141
"""SHA-512/224 hash algorithm (224-bit digest from SHA-512)"""
142
name = "sha512-224"
143
digest_size = 28
144
145
class SHA512_256:
146
"""SHA-512/256 hash algorithm (256-bit digest from SHA-512)"""
147
name = "sha512-256"
148
digest_size = 32
149
```
150
151
### SHA-3 Family
152
153
NIST SHA-3 standard hash functions.
154
155
```python { .api }
156
class SHA3_224:
157
"""SHA3-224 hash algorithm (224-bit digest)"""
158
name = "sha3-224"
159
digest_size = 28
160
161
class SHA3_256:
162
"""SHA3-256 hash algorithm (256-bit digest)"""
163
name = "sha3-256"
164
digest_size = 32
165
166
class SHA3_384:
167
"""SHA3-384 hash algorithm (384-bit digest)"""
168
name = "sha3-384"
169
digest_size = 48
170
171
class SHA3_512:
172
"""SHA3-512 hash algorithm (512-bit digest)"""
173
name = "sha3-512"
174
digest_size = 64
175
176
class SHAKE128:
177
"""SHAKE128 extendable output function"""
178
name = "shake128"
179
180
class SHAKE256:
181
"""SHAKE256 extendable output function"""
182
name = "shake256"
183
```
184
185
### BLAKE2 Family
186
187
High-performance cryptographic hash functions.
188
189
```python { .api }
190
class BLAKE2b:
191
def __init__(self, digest_size: int):
192
"""
193
BLAKE2b hash algorithm with configurable output size.
194
195
Args:
196
digest_size (int): Output size in bytes (1-64)
197
"""
198
199
@property
200
def name(self) -> str:
201
return "blake2b"
202
203
@property
204
def digest_size(self) -> int:
205
"""Configured digest size"""
206
207
class BLAKE2s:
208
def __init__(self, digest_size: int):
209
"""
210
BLAKE2s hash algorithm with configurable output size.
211
212
Args:
213
digest_size (int): Output size in bytes (1-32)
214
"""
215
216
@property
217
def name(self) -> str:
218
return "blake2s"
219
220
@property
221
def digest_size(self) -> int:
222
"""Configured digest size"""
223
```
224
225
### Other Hash Functions
226
227
```python { .api }
228
class MD5:
229
"""
230
MD5 hash algorithm (128-bit digest).
231
232
Note: MD5 is cryptographically broken, use SHA-256 or higher.
233
"""
234
name = "md5"
235
digest_size = 16
236
237
class SM3:
238
"""SM3 hash algorithm (256-bit digest) - Chinese national standard"""
239
name = "sm3"
240
digest_size = 32
241
```
242
243
## Usage Examples
244
245
### Basic Hashing
246
247
```python
248
from cryptography.hazmat.primitives import hashes
249
250
# One-shot hashing
251
data = b"Hello, World!"
252
253
# SHA-256
254
digest = hashes.Hash(hashes.SHA256())
255
digest.update(data)
256
hash_value = digest.finalize()
257
print(f"SHA-256: {hash_value.hex()}")
258
259
# SHA-3
260
digest = hashes.Hash(hashes.SHA3_256())
261
digest.update(data)
262
hash_value = digest.finalize()
263
print(f"SHA3-256: {hash_value.hex()}")
264
```
265
266
### Incremental Hashing
267
268
```python
269
from cryptography.hazmat.primitives import hashes
270
271
# Hash large data incrementally
272
hasher = hashes.Hash(hashes.SHA256())
273
274
# Process data in chunks
275
with open('large_file.bin', 'rb') as f:
276
while chunk := f.read(8192):
277
hasher.update(chunk)
278
279
final_hash = hasher.finalize()
280
print(f"File hash: {final_hash.hex()}")
281
```
282
283
### Hash State Copying
284
285
```python
286
from cryptography.hazmat.primitives import hashes
287
288
# Create base hash state
289
base_hasher = hashes.Hash(hashes.SHA256())
290
base_hasher.update(b"Common prefix")
291
292
# Create multiple branches from same state
293
hasher1 = base_hasher.copy()
294
hasher1.update(b"Branch 1 data")
295
hash1 = hasher1.finalize()
296
297
hasher2 = base_hasher.copy()
298
hasher2.update(b"Branch 2 data")
299
hash2 = hasher2.finalize()
300
301
print(f"Hash 1: {hash1.hex()}")
302
print(f"Hash 2: {hash2.hex()}")
303
```
304
305
### Extendable Output Functions (XOFs)
306
307
```python
308
from cryptography.hazmat.primitives import hashes
309
310
# SHAKE128 - variable length output
311
data = b"Input data for XOF"
312
xof = hashes.XOFHash(hashes.SHAKE128())
313
xof.update(data)
314
315
# Generate different length outputs
316
short_output = xof.copy().finalize(16) # 16 bytes
317
long_output = xof.copy().finalize(64) # 64 bytes
318
319
print(f"Short SHAKE128: {short_output.hex()}")
320
print(f"Long SHAKE128: {long_output.hex()}")
321
322
# SHAKE256
323
xof256 = hashes.XOFHash(hashes.SHAKE256())
324
xof256.update(data)
325
output256 = xof256.finalize(32)
326
print(f"SHAKE256: {output256.hex()}")
327
```
328
329
### BLAKE2 with Custom Output Size
330
331
```python
332
from cryptography.hazmat.primitives import hashes
333
334
data = b"Data to hash with BLAKE2"
335
336
# BLAKE2b with 32-byte output
337
blake2b_32 = hashes.Hash(hashes.BLAKE2b(32))
338
blake2b_32.update(data)
339
hash_32 = blake2b_32.finalize()
340
341
# BLAKE2b with 64-byte output (maximum)
342
blake2b_64 = hashes.Hash(hashes.BLAKE2b(64))
343
blake2b_64.update(data)
344
hash_64 = blake2b_64.finalize()
345
346
print(f"BLAKE2b-32: {hash_32.hex()}")
347
print(f"BLAKE2b-64: {hash_64.hex()}")
348
349
# BLAKE2s with 16-byte output
350
blake2s_16 = hashes.Hash(hashes.BLAKE2s(16))
351
blake2s_16.update(data)
352
hash_16 = blake2s_16.finalize()
353
print(f"BLAKE2s-16: {hash_16.hex()}")
354
```
355
356
### File Integrity Verification
357
358
```python
359
from cryptography.hazmat.primitives import hashes
360
import os
361
362
class FileHasher:
363
def __init__(self, algorithm=hashes.SHA256()):
364
self.algorithm = algorithm
365
366
def hash_file(self, filepath):
367
"""Compute hash of file"""
368
hasher = hashes.Hash(self.algorithm)
369
370
with open(filepath, 'rb') as f:
371
while chunk := f.read(65536): # 64KB chunks
372
hasher.update(chunk)
373
374
return hasher.finalize()
375
376
def verify_file(self, filepath, expected_hash):
377
"""Verify file matches expected hash"""
378
actual_hash = self.hash_file(filepath)
379
return actual_hash == expected_hash
380
381
# Usage
382
file_hasher = FileHasher(hashes.SHA256())
383
384
# Compute file hash
385
file_hash = file_hasher.hash_file('document.pdf')
386
print(f"File hash: {file_hash.hex()}")
387
388
# Later, verify file integrity
389
is_valid = file_hasher.verify_file('document.pdf', file_hash)
390
print(f"File integrity: {'OK' if is_valid else 'FAILED'}")
391
```
392
393
### Hash-based Message Authentication Code (HMAC) Integration
394
395
```python
396
from cryptography.hazmat.primitives import hashes, hmac
397
398
# HMAC typically uses hash functions
399
key = b"secret_key_32_bytes_long_for_hmac"
400
message = b"Message to authenticate"
401
402
# HMAC-SHA256
403
h = hmac.HMAC(key, hashes.SHA256())
404
h.update(message)
405
signature = h.finalize()
406
407
print(f"HMAC-SHA256: {signature.hex()}")
408
409
# Verify HMAC
410
h_verify = hmac.HMAC(key, hashes.SHA256())
411
h_verify.update(message)
412
try:
413
h_verify.verify(signature)
414
print("HMAC verification: SUCCESS")
415
except Exception:
416
print("HMAC verification: FAILED")
417
```
418
419
### Password Hashing (with Key Derivation)
420
421
```python
422
from cryptography.hazmat.primitives import hashes
423
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
424
import os
425
426
def hash_password(password: str, salt: bytes = None) -> tuple:
427
"""Hash password using PBKDF2-HMAC-SHA256"""
428
if salt is None:
429
salt = os.urandom(16)
430
431
kdf = PBKDF2HMAC(
432
algorithm=hashes.SHA256(),
433
length=32,
434
salt=salt,
435
iterations=100000, # OWASP recommended minimum
436
)
437
438
key = kdf.derive(password.encode())
439
return key, salt
440
441
def verify_password(password: str, stored_hash: bytes, salt: bytes) -> bool:
442
"""Verify password against stored hash"""
443
kdf = PBKDF2HMAC(
444
algorithm=hashes.SHA256(),
445
length=32,
446
salt=salt,
447
iterations=100000,
448
)
449
450
try:
451
kdf.verify(password.encode(), stored_hash)
452
return True
453
except Exception:
454
return False
455
456
# Usage
457
password = "user_password123"
458
459
# Hash password for storage
460
password_hash, salt = hash_password(password)
461
print(f"Password hash: {password_hash.hex()}")
462
print(f"Salt: {salt.hex()}")
463
464
# Verify password
465
is_valid = verify_password(password, password_hash, salt)
466
print(f"Password valid: {is_valid}")
467
```
468
469
## Security Considerations
470
471
- **Algorithm Selection**: Use SHA-256 or higher for new applications
472
- **Legacy Algorithms**: MD5 and SHA-1 are cryptographically broken
473
- **Performance**: BLAKE2 offers excellent performance with strong security
474
- **XOF Usage**: SHAKE functions useful for custom output lengths
475
- **Salt Usage**: Always use random salts for password hashing
476
- **Incremental Hashing**: More efficient for large data than loading into memory
477
- **State Management**: Hash contexts cannot be used after finalization