or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

asymmetric.mdbackend.mdindex.mdkdf.mdkeys.mdsymmetric.mdtls.mdtrust-store.mdutility.md

kdf.mddocs/

0

# Key Derivation Functions

1

2

Password-based key derivation functions including PBKDF1, PBKDF2, and PKCS#12 KDF. These functions derive cryptographic keys from passwords using salt and iteration counts for security against brute-force attacks.

3

4

## Capabilities

5

6

### PBKDF2

7

8

Password-Based Key Derivation Function 2 (PBKDF2) as defined in RFC 2898, the most commonly used key derivation function.

9

10

```python { .api }

11

def pbkdf2(hash_algorithm: str, password: bytes, salt: bytes, iterations: int, key_length: int) -> bytes:

12

"""

13

Derive a key using PBKDF2.

14

15

Parameters:

16

- hash_algorithm: str - Hash algorithm ('sha1', 'sha224', 'sha256', 'sha384', 'sha512')

17

- password: bytes - Password to derive key from

18

- salt: bytes - Salt value (should be at least 8 bytes, preferably 16+)

19

- iterations: int - Number of iterations (minimum 1000, recommended 10000+)

20

- key_length: int - Length of derived key in bytes

21

22

Returns:

23

Derived key bytes

24

"""

25

26

def pbkdf2_iteration_calculator(hash_algorithm: str, key_length: int, target_ms: int = 100, quiet: bool = False) -> int:

27

"""

28

Calculate PBKDF2 iterations for a target computation time.

29

30

Parameters:

31

- hash_algorithm: str - Hash algorithm to benchmark

32

- key_length: int - Length of key to derive

33

- target_ms: int - Target computation time in milliseconds

34

- quiet: bool - Suppress progress output

35

36

Returns:

37

Number of iterations that achieves approximately target_ms computation time

38

"""

39

```

40

41

### PBKDF1

42

43

Password-Based Key Derivation Function 1 (PBKDF1) as defined in RFC 2898. Less secure than PBKDF2, included for compatibility.

44

45

```python { .api }

46

def pbkdf1(hash_algorithm: str, password: bytes, salt: bytes, iterations: int, key_length: int) -> bytes:

47

"""

48

Derive a key using PBKDF1 (legacy, less secure than PBKDF2).

49

50

Parameters:

51

- hash_algorithm: str - Hash algorithm ('sha1', 'md5')

52

- password: bytes - Password to derive key from

53

- salt: bytes - Salt value (8 bytes)

54

- iterations: int - Number of iterations

55

- key_length: int - Length of derived key (limited by hash output size)

56

57

Returns:

58

Derived key bytes

59

60

Note:

61

PBKDF1 is deprecated. Use PBKDF2 for new applications.

62

"""

63

```

64

65

### PKCS#12 KDF

66

67

PKCS#12 key derivation function used specifically for PKCS#12 files and some legacy applications.

68

69

```python { .api }

70

def pkcs12_kdf(hash_algorithm: str, password: bytes, salt: bytes, iterations: int, key_length: int, id_: int) -> bytes:

71

"""

72

Derive a key using PKCS#12 KDF.

73

74

Parameters:

75

- hash_algorithm: str - Hash algorithm ('sha1', 'sha224', 'sha256', 'sha384', 'sha512')

76

- password: bytes - Password to derive key from

77

- salt: bytes - Salt value

78

- iterations: int - Number of iterations

79

- key_length: int - Length of derived key in bytes

80

- id_: int - Purpose ID (1=key material, 2=IV, 3=MAC key)

81

82

Returns:

83

Derived key bytes

84

"""

85

```

86

87

## Usage Examples

88

89

### PBKDF2 Key Derivation

90

91

```python

92

from oscrypto.kdf import pbkdf2, pbkdf2_iteration_calculator

93

from oscrypto.util import rand_bytes

94

import os

95

96

# Generate secure random salt

97

salt = rand_bytes(16)

98

password = b"user_password_123"

99

100

# Calculate appropriate iteration count for ~100ms computation time

101

iterations = pbkdf2_iteration_calculator('sha256', 32, target_ms=100)

102

print(f"Using {iterations} iterations for ~100ms computation time")

103

104

# Derive AES-256 key (32 bytes)

105

key = pbkdf2('sha256', password, salt, iterations, 32)

106

107

print(f"Derived {len(key)} byte key")

108

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

109

```

110

111

### Secure Password Storage

112

113

```python

114

from oscrypto.kdf import pbkdf2

115

from oscrypto.util import rand_bytes, constant_compare

116

import hashlib

117

118

def hash_password(password: str) -> tuple:

119

"""Hash a password securely for storage."""

120

# Convert password to bytes

121

password_bytes = password.encode('utf-8')

122

123

# Generate random salt

124

salt = rand_bytes(16)

125

126

# Use strong iteration count

127

iterations = 100000

128

129

# Derive key and hash it for storage

130

key = pbkdf2('sha256', password_bytes, salt, iterations, 32)

131

132

return salt, iterations, key

133

134

def verify_password(password: str, stored_salt: bytes, stored_iterations: int, stored_key: bytes) -> bool:

135

"""Verify a password against stored hash."""

136

password_bytes = password.encode('utf-8')

137

138

# Derive key with same parameters

139

derived_key = pbkdf2('sha256', password_bytes, stored_salt, stored_iterations, 32)

140

141

# Use constant-time comparison

142

return constant_compare(derived_key, stored_key)

143

144

# Example usage

145

password = "my_secure_password"

146

147

# Store password

148

salt, iterations, key = hash_password(password)

149

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

150

print(f"Iterations: {iterations}")

151

152

# Verify password

153

is_valid = verify_password(password, salt, iterations, key)

154

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

155

156

# Wrong password

157

is_valid = verify_password("wrong_password", salt, iterations, key)

158

print(f"Wrong password valid: {is_valid}")

159

```

160

161

### Key Derivation for Encryption

162

163

```python

164

from oscrypto.kdf import pbkdf2

165

from oscrypto.symmetric import aes_cbc_pkcs7_encrypt, aes_cbc_pkcs7_decrypt

166

from oscrypto.util import rand_bytes

167

168

def encrypt_with_password(data: bytes, password: str) -> tuple:

169

"""Encrypt data using password-derived key."""

170

# Convert password to bytes

171

password_bytes = password.encode('utf-8')

172

173

# Generate random salt for key derivation

174

salt = rand_bytes(16)

175

176

# Derive AES-256 key

177

key = pbkdf2('sha256', password_bytes, salt, 100000, 32)

178

179

# Encrypt data

180

ciphertext = aes_cbc_pkcs7_encrypt(key, data)

181

182

return salt, ciphertext

183

184

def decrypt_with_password(salt: bytes, ciphertext: bytes, password: str) -> bytes:

185

"""Decrypt data using password-derived key."""

186

password_bytes = password.encode('utf-8')

187

188

# Derive the same key

189

key = pbkdf2('sha256', password_bytes, salt, 100000, 32)

190

191

# Decrypt data

192

return aes_cbc_pkcs7_decrypt(key, ciphertext)

193

194

# Example usage

195

plaintext = b"Secret document contents"

196

password = "encryption_password_123"

197

198

# Encrypt

199

salt, ciphertext = encrypt_with_password(plaintext, password)

200

print(f"Encrypted {len(plaintext)} bytes to {len(ciphertext)} bytes")

201

202

# Decrypt

203

decrypted = decrypt_with_password(salt, ciphertext, password)

204

print(f"Decrypted: {decrypted}")

205

assert decrypted == plaintext

206

```

207

208

### Multiple Hash Algorithms

209

210

```python

211

from oscrypto.kdf import pbkdf2

212

from oscrypto.util import rand_bytes

213

214

password = b"test_password"

215

salt = rand_bytes(16)

216

iterations = 10000

217

key_length = 32

218

219

# Test different hash algorithms

220

algorithms = ['sha1', 'sha256', 'sha384', 'sha512']

221

222

for algorithm in algorithms:

223

key = pbkdf2(algorithm, password, salt, iterations, key_length)

224

print(f"{algorithm.upper()}: {key[:8].hex()}...")

225

```

226

227

### Iteration Count Tuning

228

229

```python

230

from oscrypto.kdf import pbkdf2_iteration_calculator

231

import time

232

233

# Test different target computation times

234

targets = [50, 100, 200, 500] # milliseconds

235

236

for target_ms in targets:

237

iterations = pbkdf2_iteration_calculator('sha256', 32, target_ms, quiet=True)

238

239

# Verify actual timing

240

start = time.time()

241

pbkdf2('sha256', b'test', b'salt1234', iterations, 32)

242

actual_ms = (time.time() - start) * 1000

243

244

print(f"Target: {target_ms}ms, Iterations: {iterations}, Actual: {actual_ms:.1f}ms")

245

```