0
# Cryptographic Utilities
1
2
Additional cryptographic utilities including constant-time operations and key wrapping functionality.
3
4
## Core Imports
5
6
```python
7
from cryptography.hazmat.primitives import constant_time, keywrap
8
```
9
10
## Capabilities
11
12
### Constant-Time Operations
13
14
Constant-time comparison functions that resist timing attacks by ensuring operations take the same amount of time regardless of input values.
15
16
```python { .api }
17
def bytes_eq(a: bytes, b: bytes) -> bool:
18
"""
19
Compare two byte strings in constant time.
20
21
Args:
22
a (bytes): First byte string to compare
23
b (bytes): Second byte string to compare
24
25
Returns:
26
bool: True if the byte strings are equal, False otherwise
27
28
Raises:
29
TypeError: If either argument is not bytes
30
31
Note:
32
This function prevents timing attacks by ensuring the comparison
33
takes the same amount of time regardless of where the first
34
difference occurs or if the strings are identical.
35
"""
36
```
37
38
#### Usage Example
39
40
```python
41
from cryptography.hazmat.primitives import constant_time
42
43
# Constant-time comparison for security-sensitive operations
44
expected_token = b"secret_authentication_token"
45
received_token = b"user_provided_token_value"
46
47
# Use constant_time.bytes_eq instead of == for security
48
if constant_time.bytes_eq(expected_token, received_token):
49
print("Authentication successful")
50
else:
51
print("Authentication failed")
52
53
# Don't use regular comparison for security-sensitive data:
54
# if expected_token == received_token: # ❌ Vulnerable to timing attacks
55
```
56
57
### AES Key Wrapping
58
59
AES key wrapping as defined in RFC 3394 and RFC 5649, providing secure encryption of cryptographic keys using other keys.
60
61
```python { .api }
62
def aes_key_wrap(wrapping_key: bytes, key_to_wrap: bytes, backend=None) -> bytes:
63
"""
64
Wrap a key using AES Key Wrap (RFC 3394).
65
66
Args:
67
wrapping_key (bytes): AES key (16, 24, or 32 bytes)
68
key_to_wrap (bytes): Key material to wrap (min 16 bytes, multiple of 8)
69
backend: Cryptographic backend (usually None)
70
71
Returns:
72
bytes: Wrapped key data
73
74
Raises:
75
ValueError: If key lengths are invalid
76
"""
77
78
def aes_key_unwrap(wrapping_key: bytes, wrapped_key: bytes, backend=None) -> bytes:
79
"""
80
Unwrap a key using AES Key Wrap (RFC 3394).
81
82
Args:
83
wrapping_key (bytes): AES key used for wrapping
84
wrapped_key (bytes): Wrapped key data (min 24 bytes, multiple of 8)
85
backend: Cryptographic backend (usually None)
86
87
Returns:
88
bytes: Original key material
89
90
Raises:
91
ValueError: If key lengths are invalid
92
InvalidUnwrap: If unwrapping fails (integrity check failure)
93
"""
94
95
def aes_key_wrap_with_padding(wrapping_key: bytes, key_to_wrap: bytes, backend=None) -> bytes:
96
"""
97
Wrap a key using AES Key Wrap with Padding (RFC 5649).
98
99
Args:
100
wrapping_key (bytes): AES key (16, 24, or 32 bytes)
101
key_to_wrap (bytes): Key material to wrap (any length)
102
backend: Cryptographic backend (usually None)
103
104
Returns:
105
bytes: Wrapped key data with padding
106
107
Raises:
108
ValueError: If wrapping key length is invalid
109
"""
110
111
def aes_key_unwrap_with_padding(wrapping_key: bytes, wrapped_key: bytes, backend=None) -> bytes:
112
"""
113
Unwrap a key using AES Key Wrap with Padding (RFC 5649).
114
115
Args:
116
wrapping_key (bytes): AES key used for wrapping
117
wrapped_key (bytes): Wrapped key data (min 16 bytes)
118
backend: Cryptographic backend (usually None)
119
120
Returns:
121
bytes: Original key material without padding
122
123
Raises:
124
ValueError: If wrapping key length is invalid
125
InvalidUnwrap: If unwrapping fails (integrity or padding check failure)
126
"""
127
128
class InvalidUnwrap(Exception):
129
"""Raised when key unwrapping fails due to integrity check failure."""
130
```
131
132
#### Usage Examples
133
134
```python
135
from cryptography.hazmat.primitives import keywrap
136
from cryptography.hazmat.primitives.ciphers import algorithms
137
import os
138
139
# Generate keys
140
wrapping_key = os.urandom(32) # 256-bit AES key
141
key_to_wrap = os.urandom(32) # Key material to protect
142
143
# AES Key Wrap (RFC 3394) - requires key to be multiple of 8 bytes
144
wrapped_key = keywrap.aes_key_wrap(wrapping_key, key_to_wrap)
145
unwrapped_key = keywrap.aes_key_unwrap(wrapping_key, wrapped_key)
146
147
assert unwrapped_key == key_to_wrap
148
149
# AES Key Wrap with Padding (RFC 5649) - works with any key length
150
arbitrary_key = os.urandom(17) # Not a multiple of 8
151
wrapped_padded = keywrap.aes_key_wrap_with_padding(wrapping_key, arbitrary_key)
152
unwrapped_padded = keywrap.aes_key_unwrap_with_padding(wrapping_key, wrapped_padded)
153
154
assert unwrapped_padded == arbitrary_key
155
```
156
157
#### Security Considerations
158
159
- **Key Wrapping**: Always use cryptographically random keys for wrapping
160
- **Constant-Time**: Use `bytes_eq()` for comparing authentication tokens, signatures, or other security-sensitive data
161
- **RFC Compliance**: Both RFC 3394 and RFC 5649 key wrapping are supported and interoperable with other implementations
162
- **Error Handling**: `InvalidUnwrap` exceptions indicate integrity failures and should be handled securely