or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

aead-ciphers.mdasymmetric-cryptography.mdhash-functions.mdindex.mdkey-derivation.mdkey-serialization.mdmessage-authentication.mdsymmetric-ciphers.mdsymmetric-encryption.mdtwo-factor-auth.mdutilities.mdx509-certificates.md

key-derivation.mddocs/

0

# Key Derivation Functions

1

2

Password-based and key-based derivation functions for generating cryptographic keys from passwords or other key material. Essential for secure password storage and key management.

3

4

## Core Imports

5

6

```python

7

from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

8

from cryptography.hazmat.primitives.kdf.hkdf import HKDF, HKDFExpand

9

from cryptography.hazmat.primitives.kdf.scrypt import Scrypt

10

from cryptography.hazmat.primitives.kdf.argon2 import Argon2

11

from cryptography.hazmat.primitives import hashes

12

```

13

14

## Capabilities

15

16

### PBKDF2 (Password-Based Key Derivation Function 2)

17

18

```python { .api }

19

class PBKDF2HMAC:

20

def __init__(self, algorithm, length: int, salt: bytes, iterations: int, backend=None):

21

"""

22

PBKDF2 with HMAC.

23

24

Args:

25

algorithm: Hash algorithm (hashes.SHA256(), etc.)

26

length (int): Output key length in bytes

27

salt (bytes): Random salt (16+ bytes recommended)

28

iterations (int): Number of iterations (100,000+ recommended)

29

"""

30

31

def derive(self, key_material: bytes) -> bytes:

32

"""

33

Derive key from password.

34

35

Args:

36

key_material (bytes): Password or key material

37

38

Returns:

39

bytes: Derived key

40

"""

41

42

def verify(self, key_material: bytes, expected_key: bytes) -> None:

43

"""

44

Verify password against expected key.

45

46

Raises:

47

InvalidKey: If verification fails

48

"""

49

```

50

51

### HKDF (HMAC-based Key Derivation Function)

52

53

```python { .api }

54

class HKDF:

55

def __init__(self, algorithm, length: int, salt: bytes = None, info: bytes = None, backend=None):

56

"""

57

HKDF extract-and-expand.

58

59

Args:

60

algorithm: Hash algorithm

61

length (int): Output length in bytes

62

salt (bytes, optional): Salt for extraction

63

info (bytes, optional): Context info for expansion

64

"""

65

66

def derive(self, key_material: bytes) -> bytes:

67

"""Derive key from input key material"""

68

69

class HKDFExpand:

70

def __init__(self, algorithm, length: int, info: bytes = None, backend=None):

71

"""HKDF expand-only (when you already have a PRK)"""

72

73

def derive(self, key_material: bytes) -> bytes:

74

"""Expand pseudorandom key"""

75

```

76

77

### Scrypt

78

79

```python { .api }

80

class Scrypt:

81

def __init__(self, algorithm, length: int, salt: bytes, n: int, r: int, p: int, backend=None):

82

"""

83

Scrypt key derivation function.

84

85

Args:

86

algorithm: Hash algorithm (usually SHA256)

87

length (int): Output length

88

salt (bytes): Random salt

89

n (int): CPU/memory cost (power of 2, e.g., 2**14)

90

r (int): Block size (e.g., 8)

91

p (int): Parallelization factor (e.g., 1)

92

"""

93

94

def derive(self, key_material: bytes) -> bytes:

95

"""Derive key using Scrypt"""

96

97

def verify(self, key_material: bytes, expected_key: bytes) -> None:

98

"""Verify password"""

99

```

100

101

### Argon2

102

103

```python { .api }

104

class Argon2:

105

def __init__(self, time_cost: int, memory_cost: int, parallelism: int,

106

hash_len: int, salt: bytes, type=Argon2.Type.I, backend=None):

107

"""

108

Argon2 password hashing.

109

110

Args:

111

time_cost (int): Number of iterations

112

memory_cost (int): Memory usage in KiB

113

parallelism (int): Number of parallel threads

114

hash_len (int): Output hash length

115

salt (bytes): Random salt

116

type: Argon2 variant (Type.I, Type.D, Type.ID)

117

"""

118

119

def derive(self, key_material: bytes) -> bytes:

120

"""Derive key using Argon2"""

121

122

def verify(self, key_material: bytes, expected_key: bytes) -> None:

123

"""Verify password"""

124

125

class Type:

126

I = "argon2i" # Side-channel resistant

127

D = "argon2d" # GPU-resistant

128

ID = "argon2id" # Hybrid (recommended)

129

```

130

131

## Usage Examples

132

133

### Password Hashing with PBKDF2

134

135

```python

136

from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

137

from cryptography.hazmat.primitives import hashes

138

from cryptography.exceptions import InvalidKey

139

import os

140

141

def hash_password(password: str) -> tuple[bytes, bytes]:

142

"""Hash password for storage"""

143

salt = os.urandom(16)

144

kdf = PBKDF2HMAC(

145

algorithm=hashes.SHA256(),

146

length=32,

147

salt=salt,

148

iterations=100000, # OWASP minimum

149

)

150

key = kdf.derive(password.encode())

151

return key, salt

152

153

def verify_password(password: str, stored_key: bytes, salt: bytes) -> bool:

154

"""Verify password against stored hash"""

155

kdf = PBKDF2HMAC(

156

algorithm=hashes.SHA256(),

157

length=32,

158

salt=salt,

159

iterations=100000,

160

)

161

try:

162

kdf.verify(password.encode(), stored_key)

163

return True

164

except InvalidKey:

165

return False

166

167

# Usage

168

password = "user_secure_password"

169

key, salt = hash_password(password)

170

print(f"Stored key: {key.hex()}")

171

print(f"Salt: {salt.hex()}")

172

173

# Verify password

174

is_valid = verify_password(password, key, salt)

175

print(f"Password valid: {is_valid}")

176

```

177

178

### Key Derivation with HKDF

179

180

```python

181

from cryptography.hazmat.primitives.kdf.hkdf import HKDF

182

from cryptography.hazmat.primitives import hashes

183

import os

184

185

# Derive multiple keys from shared secret

186

shared_secret = os.urandom(32) # From key exchange

187

salt = os.urandom(16)

188

189

# Derive encryption key

190

hkdf_enc = HKDF(

191

algorithm=hashes.SHA256(),

192

length=32,

193

salt=salt,

194

info=b'encryption key',

195

)

196

encryption_key = hkdf_enc.derive(shared_secret)

197

198

# Derive MAC key

199

hkdf_mac = HKDF(

200

algorithm=hashes.SHA256(),

201

length=32,

202

salt=salt,

203

info=b'authentication key',

204

)

205

mac_key = hkdf_mac.derive(shared_secret)

206

207

print(f"Encryption key: {encryption_key.hex()}")

208

print(f"MAC key: {mac_key.hex()}")

209

```

210

211

### Secure Password Storage with Argon2

212

213

```python

214

from cryptography.hazmat.primitives.kdf.argon2 import Argon2

215

from cryptography.exceptions import InvalidKey

216

import os

217

218

def argon2_hash_password(password: str) -> tuple[bytes, bytes]:

219

"""Hash password with Argon2id"""

220

salt = os.urandom(16)

221

argon2 = Argon2(

222

time_cost=3, # Number of iterations

223

memory_cost=65536, # 64 MB memory usage

224

parallelism=1, # Single thread

225

hash_len=32, # 32-byte output

226

salt=salt,

227

type=Argon2.Type.ID # Argon2id (recommended)

228

)

229

key = argon2.derive(password.encode())

230

return key, salt

231

232

# Hash password

233

password = "strong_user_password_123"

234

hashed_key, salt = argon2_hash_password(password)

235

print(f"Argon2 hash: {hashed_key.hex()}")

236

```

237

238

## Security Considerations

239

240

- **Salt Usage**: Always use random salts for password hashing

241

- **Iteration Count**: Use sufficient iterations (PBKDF2: 100k+, Scrypt/Argon2: adjust for ~100ms)

242

- **Algorithm Selection**: Prefer Argon2 > Scrypt > PBKDF2 for password hashing

243

- **Memory Hard**: Scrypt and Argon2 resist hardware attacks better than PBKDF2

244

- **Key Stretching**: Essential for converting low-entropy passwords to keys

245

- **Context Separation**: Use different info/context for different derived keys