0
# Algorithm Management
1
2
Cryptographic algorithm registration and management system providing custom algorithm support, algorithm whitelisting for security, and flexible algorithm configuration for both global and instance-level operations.
3
4
## Capabilities
5
6
### Global Algorithm Functions
7
8
Global functions for managing algorithms across all PyJWT operations using a shared algorithm registry.
9
10
```python { .api }
11
def register_algorithm(alg_id: str, alg_obj) -> None:
12
"""
13
Register a custom algorithm globally for all JWT/JWS operations.
14
15
Args:
16
alg_id (str): Algorithm identifier (e.g., 'CUSTOM256')
17
alg_obj: Algorithm implementation object
18
19
Raises:
20
ValueError: Algorithm already registered
21
TypeError: Invalid algorithm object
22
"""
23
24
def unregister_algorithm(alg_id: str) -> None:
25
"""
26
Remove an algorithm from the global registry.
27
28
Args:
29
alg_id (str): Algorithm identifier to remove
30
31
Raises:
32
KeyError: Algorithm not registered
33
"""
34
35
def get_algorithm_by_name(alg_name: str):
36
"""
37
Retrieve algorithm implementation by name from global registry.
38
39
Args:
40
alg_name (str): Algorithm name
41
42
Returns:
43
Algorithm object implementation
44
45
Raises:
46
NotImplementedError: Algorithm not supported or cryptography missing
47
"""
48
49
def get_unverified_header(jwt: str | bytes) -> dict:
50
"""
51
Extract JWT header without signature verification.
52
53
Args:
54
jwt (str | bytes): JWT token
55
56
Returns:
57
dict: JWT header dictionary
58
59
Raises:
60
DecodeError: Invalid token format
61
InvalidTokenError: Invalid header structure
62
"""
63
```
64
65
Usage examples:
66
67
```python
68
import jwt
69
from jwt.algorithms import Algorithm
70
71
# Check algorithm availability
72
try:
73
alg = jwt.get_algorithm_by_name('RS256')
74
print(f"RS256 available: {alg}")
75
except NotImplementedError as e:
76
print(f"RS256 not available: {e}")
77
78
# Extract header for algorithm info
79
token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..."
80
header = jwt.get_unverified_header(token)
81
print(f"Token algorithm: {header['alg']}")
82
83
# Register custom algorithm globally
84
class CustomHMAC(Algorithm):
85
def sign(self, msg, key):
86
# Custom signing implementation
87
import hashlib
88
import hmac
89
return hmac.new(key, msg, hashlib.sha3_256).digest()
90
91
def verify(self, msg, key, sig):
92
# Custom verification implementation
93
expected = self.sign(msg, key)
94
return hmac.compare_digest(sig, expected)
95
96
jwt.register_algorithm('CUSTOM-HMAC', CustomHMAC())
97
98
# Use custom algorithm
99
payload = {'user_id': 123}
100
token = jwt.encode(payload, b'secret', algorithm='CUSTOM-HMAC')
101
decoded = jwt.decode(token, b'secret', algorithms=['CUSTOM-HMAC'])
102
103
# Remove algorithm when no longer needed
104
jwt.unregister_algorithm('CUSTOM-HMAC')
105
```
106
107
### Instance-Level Algorithm Management
108
109
Algorithm management for specific PyJWT and PyJWS instances with custom algorithm sets and whitelisting.
110
111
```python { .api }
112
# PyJWS instance methods
113
class PyJWS:
114
def register_algorithm(self, alg_id: str, alg_obj) -> None:
115
"""Register algorithm for this JWS instance only."""
116
117
def unregister_algorithm(self, alg_id: str) -> None:
118
"""Unregister algorithm from this JWS instance."""
119
120
def get_algorithm_by_name(self, alg_name: str):
121
"""Get algorithm from this JWS instance."""
122
123
def get_algorithms(self) -> list:
124
"""List algorithms available to this JWS instance."""
125
126
# PyJWT inherits algorithm management through its internal PyJWS instance
127
```
128
129
Usage examples:
130
131
```python
132
import jwt
133
134
# Create JWS instance with limited algorithms
135
jws = jwt.PyJWS(algorithms=['HS256', 'HS512']) # Only allow HMAC
136
print(f"Allowed algorithms: {jws.get_algorithms()}")
137
138
# Add algorithm to specific instance
139
custom_alg = CustomHMAC()
140
jws.register_algorithm('CUSTOM', custom_alg)
141
142
# This instance now supports CUSTOM, but global instance doesn't
143
token = jws.encode(b'payload', b'key', algorithm='CUSTOM')
144
145
# Different instance with different algorithms
146
secure_jws = jwt.PyJWS(algorithms=['RS256', 'ES256']) # Only asymmetric
147
secure_jws.register_algorithm('CUSTOM-RSA', CustomRSA())
148
```
149
150
### Algorithm Security and Whitelisting
151
152
Security-focused algorithm management with explicit whitelisting and algorithm restrictions.
153
154
```python
155
import jwt
156
157
# Secure algorithm whitelisting
158
ALLOWED_ALGORITHMS = ['RS256', 'ES256', 'EdDSA'] # Only strong asymmetric
159
160
def verify_secure_token(token, key):
161
"""Verify token with strict algorithm policy."""
162
return jwt.decode(token, key, algorithms=ALLOWED_ALGORITHMS)
163
164
# Instance with security policy
165
secure_jwt = jwt.PyJWT()
166
secure_jws = jwt.PyJWS(algorithms=ALLOWED_ALGORITHMS)
167
168
# Block weak algorithms
169
weak_algorithms = ['none', 'HS256'] # Example: block 'none' and symmetric
170
for alg in weak_algorithms:
171
try:
172
jwt.unregister_algorithm(alg)
173
except KeyError:
174
pass # Algorithm not registered
175
176
# Verify no weak algorithms remain
177
available = jwt.PyJWS().get_algorithms()
178
dangerous = set(available) & set(weak_algorithms)
179
if dangerous:
180
print(f"Warning: Dangerous algorithms still available: {dangerous}")
181
```
182
183
### Algorithm Implementation Interface
184
185
Base interface for implementing custom algorithms compatible with PyJWT.
186
187
```python { .api }
188
class Algorithm:
189
"""
190
Base class for all algorithm implementations.
191
192
Custom algorithms must inherit from this class and implement
193
required methods for signing and verification.
194
"""
195
196
def sign(self, msg: bytes, key) -> bytes:
197
"""
198
Sign message with the given key.
199
200
Args:
201
msg (bytes): Message to sign
202
key: Cryptographic key for signing
203
204
Returns:
205
bytes: Signature
206
"""
207
raise NotImplementedError()
208
209
def verify(self, msg: bytes, key, sig: bytes) -> bool:
210
"""
211
Verify signature against message and key.
212
213
Args:
214
msg (bytes): Original message
215
key: Cryptographic key for verification
216
sig (bytes): Signature to verify
217
218
Returns:
219
bool: True if signature is valid
220
"""
221
raise NotImplementedError()
222
223
def prepare_key(self, key):
224
"""
225
Prepare and validate key for use with this algorithm.
226
227
Args:
228
key: Raw key material
229
230
Returns:
231
Prepared key object
232
233
Raises:
234
InvalidKeyError: Key is invalid for this algorithm
235
"""
236
return key
237
```
238
239
### Custom Algorithm Examples
240
241
Examples of implementing custom algorithms for specific use cases:
242
243
#### Custom HMAC with Different Hash Function
244
245
```python
246
import hashlib
247
import hmac
248
from jwt.algorithms import Algorithm
249
250
class HMACSHA3_256(Algorithm):
251
"""HMAC using SHA3-256 hash function."""
252
253
def sign(self, msg: bytes, key: bytes) -> bytes:
254
return hmac.new(key, msg, hashlib.sha3_256).digest()
255
256
def verify(self, msg: bytes, key: bytes, sig: bytes) -> bool:
257
expected = self.sign(msg, key)
258
return hmac.compare_digest(sig, expected)
259
260
def prepare_key(self, key):
261
if not isinstance(key, (bytes, str)):
262
raise jwt.InvalidKeyError("HMAC key must be bytes or string")
263
if isinstance(key, str):
264
key = key.encode('utf-8')
265
return key
266
267
# Register and use
268
jwt.register_algorithm('HS3-256', HMACSHA3_256())
269
token = jwt.encode({'data': 'test'}, 'secret', algorithm='HS3-256')
270
```
271
272
#### Custom Algorithm with Key Validation
273
274
```python
275
from jwt.algorithms import Algorithm
276
from jwt.exceptions import InvalidKeyError
277
278
class SecureHMAC(Algorithm):
279
"""HMAC with minimum key length requirement."""
280
281
MIN_KEY_LENGTH = 32 # Require 256-bit keys minimum
282
283
def prepare_key(self, key):
284
if isinstance(key, str):
285
key = key.encode('utf-8')
286
287
if not isinstance(key, bytes):
288
raise InvalidKeyError("Key must be bytes or string")
289
290
if len(key) < self.MIN_KEY_LENGTH:
291
raise InvalidKeyError(f"Key must be at least {self.MIN_KEY_LENGTH} bytes")
292
293
return key
294
295
def sign(self, msg: bytes, key: bytes) -> bytes:
296
return hmac.new(key, msg, hashlib.sha256).digest()
297
298
def verify(self, msg: bytes, key: bytes, sig: bytes) -> bool:
299
expected = self.sign(msg, key)
300
return hmac.compare_digest(sig, expected)
301
302
# Usage with key validation
303
jwt.register_algorithm('SECURE-HMAC', SecureHMAC())
304
305
try:
306
# This will fail - key too short
307
jwt.encode({'data': 'test'}, 'short', algorithm='SECURE-HMAC')
308
except InvalidKeyError as e:
309
print(f"Key rejected: {e}")
310
311
# This will work - key meets minimum length
312
long_key = 'a' * 32
313
token = jwt.encode({'data': 'test'}, long_key, algorithm='SECURE-HMAC')
314
```
315
316
### Algorithm Discovery and Introspection
317
318
Tools for discovering available algorithms and their capabilities:
319
320
```python
321
import jwt
322
323
def list_available_algorithms():
324
"""List all globally available algorithms."""
325
jws = jwt.PyJWS()
326
algorithms = jws.get_algorithms()
327
328
for alg_name in sorted(algorithms):
329
try:
330
alg_obj = jwt.get_algorithm_by_name(alg_name)
331
print(f"{alg_name}: {type(alg_obj).__name__}")
332
except NotImplementedError as e:
333
print(f"{alg_name}: Not available ({e})")
334
335
def check_cryptography_algorithms():
336
"""Check which algorithms require cryptography library."""
337
from jwt.algorithms import requires_cryptography, has_crypto
338
339
print(f"Cryptography installed: {has_crypto}")
340
print(f"Algorithms requiring cryptography: {requires_cryptography}")
341
342
if not has_crypto:
343
print("Install cryptography for full algorithm support:")
344
print("pip install PyJWT[crypto]")
345
346
# Run diagnostics
347
list_available_algorithms()
348
check_cryptography_algorithms()
349
```
350
351
### Security Best Practices
352
353
Recommended patterns for secure algorithm management:
354
355
```python
356
import jwt
357
358
# 1. Use explicit algorithm whitelists
359
PRODUCTION_ALGORITHMS = ['RS256', 'ES256', 'EdDSA']
360
361
def secure_decode(token, key):
362
return jwt.decode(token, key, algorithms=PRODUCTION_ALGORITHMS)
363
364
# 2. Block dangerous algorithms
365
BLOCKED_ALGORITHMS = ['none', 'HS256'] # Example policy
366
367
for alg in BLOCKED_ALGORITHMS:
368
try:
369
jwt.unregister_algorithm(alg)
370
except KeyError:
371
pass
372
373
# 3. Use asymmetric algorithms in production
374
def create_production_jwt_instance():
375
return jwt.PyJWT(algorithms=['RS256', 'ES256'])
376
377
# 4. Validate algorithm in token matches expected
378
def verify_with_algorithm_check(token, key, expected_algorithm):
379
header = jwt.get_unverified_header(token)
380
if header.get('alg') != expected_algorithm:
381
raise ValueError(f"Unexpected algorithm: {header.get('alg')}")
382
383
return jwt.decode(token, key, algorithms=[expected_algorithm])
384
385
# 5. Regular algorithm audit
386
def audit_algorithms():
387
"""Audit currently available algorithms for security compliance."""
388
available = jwt.PyJWS().get_algorithms()
389
390
dangerous = {'none'} # Example dangerous algorithms
391
weak = {'HS256', 'HS384', 'HS512'} # Example: symmetric keys
392
393
found_dangerous = set(available) & dangerous
394
found_weak = set(available) & weak
395
396
if found_dangerous:
397
print(f"CRITICAL: Dangerous algorithms available: {found_dangerous}")
398
if found_weak:
399
print(f"WARNING: Weak algorithms available: {found_weak}")
400
401
return len(found_dangerous) == 0 and len(found_weak) == 0
402
403
# Run security audit
404
if not audit_algorithms():
405
print("Algorithm security policy violations detected!")
406
```