or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

aead.mdauth.mdbox.mded25519.mdhash.mdindex.mdkdf.mdkx.mdmemory.mdpwhash.mdrandom.mdsecretbox.mdsecretstream.mdshorthash.mdsign.mdstream.md

kdf.mddocs/

0

# Key Derivation Functions

1

2

Key derivation functions for generating multiple keys from a single master key with proper domain separation and context binding.

3

4

## Capabilities

5

6

### Master Key Generation

7

8

Generate a cryptographically secure master key for key derivation.

9

10

```javascript { .api }

11

/**

12

* Generate random master key for key derivation

13

* @param key - Output buffer for master key (must be KEYBYTES long)

14

*/

15

function crypto_kdf_keygen(key: Buffer): void;

16

```

17

18

**Usage Example:**

19

20

```javascript

21

const sodium = require('sodium-native');

22

23

// Generate master key

24

const masterKey = Buffer.alloc(sodium.crypto_kdf_KEYBYTES);

25

sodium.crypto_kdf_keygen(masterKey);

26

```

27

28

### Key Derivation

29

30

Derive subkeys from a master key with context and subkey ID for domain separation.

31

32

```javascript { .api }

33

/**

34

* Derive subkey from master key with context and ID

35

* @param subkey - Output buffer for derived subkey (size determines key length)

36

* @param subkeyId - Subkey identifier (numeric ID for key differentiation)

37

* @param ctx - Context buffer for domain separation (must be CONTEXTBYTES long)

38

* @param key - Master key buffer (must be KEYBYTES long)

39

* @throws Error if buffer sizes incorrect or derivation fails

40

*/

41

function crypto_kdf_derive_from_key(

42

subkey: Buffer,

43

subkeyId: number,

44

ctx: Buffer,

45

key: Buffer

46

): void;

47

```

48

49

**Usage Example:**

50

51

```javascript

52

const sodium = require('sodium-native');

53

54

// Generate master key

55

const masterKey = Buffer.alloc(sodium.crypto_kdf_KEYBYTES);

56

sodium.crypto_kdf_keygen(masterKey);

57

58

// Define context for domain separation

59

const context = Buffer.alloc(sodium.crypto_kdf_CONTEXTBYTES);

60

Buffer.from('MyApp v1').copy(context); // Pad to exact size

61

62

// Derive different types of keys

63

const encryptionKey = Buffer.alloc(32); // 256-bit encryption key

64

const authKey = Buffer.alloc(32); // 256-bit authentication key

65

const signingKey = Buffer.alloc(64); // 512-bit signing key

66

67

sodium.crypto_kdf_derive_from_key(encryptionKey, 1, context, masterKey);

68

sodium.crypto_kdf_derive_from_key(authKey, 2, context, masterKey);

69

sodium.crypto_kdf_derive_from_key(signingKey, 3, context, masterKey);

70

71

console.log('Derived encryption key length:', encryptionKey.length);

72

console.log('Derived auth key length:', authKey.length);

73

console.log('Derived signing key length:', signingKey.length);

74

```

75

76

## Constants

77

78

```javascript { .api }

79

// Minimum derived key size in bytes

80

const crypto_kdf_BYTES_MIN: number;

81

82

// Maximum derived key size in bytes

83

const crypto_kdf_BYTES_MAX: number;

84

85

// Context size in bytes (for domain separation)

86

const crypto_kdf_CONTEXTBYTES: number;

87

88

// Master key size in bytes

89

const crypto_kdf_KEYBYTES: number;

90

```

91

92

## Security Considerations

93

94

- **Master Key Security**: Protect the master key as it can derive all subkeys.

95

- **Context Uniqueness**: Use unique contexts for different applications or purposes.

96

- **Subkey ID Management**: Use systematic subkey ID assignment to avoid conflicts.

97

- **Key Rotation**: Consider rotating master keys periodically for long-term security.

98

99

## Common Patterns

100

101

### Application Key Management

102

103

```javascript

104

const sodium = require('sodium-native');

105

106

class ApplicationKeyManager {

107

constructor(appName, version) {

108

// Generate or load master key

109

this.masterKey = Buffer.alloc(sodium.crypto_kdf_KEYBYTES);

110

sodium.crypto_kdf_keygen(this.masterKey);

111

112

// Create context from app name and version

113

this.context = Buffer.alloc(sodium.crypto_kdf_CONTEXTBYTES);

114

const contextString = `${appName} ${version}`.padEnd(sodium.crypto_kdf_CONTEXTBYTES, '\0');

115

Buffer.from(contextString).copy(this.context, 0, 0, sodium.crypto_kdf_CONTEXTBYTES);

116

}

117

118

// Key types with assigned IDs

119

static KeyTypes = {

120

DATABASE_ENCRYPTION: 1,

121

SESSION_SIGNING: 2,

122

API_AUTHENTICATION: 3,

123

FILE_ENCRYPTION: 4,

124

LOG_INTEGRITY: 5,

125

BACKUP_ENCRYPTION: 6

126

};

127

128

deriveKey(keyType, keySize = 32) {

129

if (!ApplicationKeyManager.KeyTypes[keyType]) {

130

throw new Error(`Unknown key type: ${keyType}`);

131

}

132

133

if (keySize < sodium.crypto_kdf_BYTES_MIN || keySize > sodium.crypto_kdf_BYTES_MAX) {

134

throw new Error(`Key size must be between ${sodium.crypto_kdf_BYTES_MIN} and ${sodium.crypto_kdf_BYTES_MAX} bytes`);

135

}

136

137

const subkey = Buffer.alloc(keySize);

138

const keyId = ApplicationKeyManager.KeyTypes[keyType];

139

140

sodium.crypto_kdf_derive_from_key(subkey, keyId, this.context, this.masterKey);

141

return subkey;

142

}

143

144

// Derive keys for common cryptographic operations

145

getEncryptionKey() {

146

return this.deriveKey('DATABASE_ENCRYPTION', 32);

147

}

148

149

getSigningKey() {

150

return this.deriveKey('SESSION_SIGNING', 64);

151

}

152

153

getAuthKey() {

154

return this.deriveKey('API_AUTHENTICATION', 32);

155

}

156

157

// Export master key for backup (encrypt before storing)

158

exportMasterKey() {

159

return Buffer.from(this.masterKey);

160

}

161

162

// Import master key from backup

163

importMasterKey(masterKeyData) {

164

Buffer.from(masterKeyData).copy(this.masterKey);

165

}

166

}

167

168

// Usage

169

const keyManager = new ApplicationKeyManager('SecureApp', 'v2.1');

170

171

const dbKey = keyManager.getEncryptionKey();

172

const apiKey = keyManager.getAuthKey();

173

const sessionKey = keyManager.getSigningKey();

174

```

175

176

### User-specific Key Derivation

177

178

```javascript

179

const sodium = require('sodium-native');

180

181

class UserKeyDerivation {

182

constructor(systemMasterKey) {

183

this.systemMasterKey = Buffer.from(systemMasterKey);

184

}

185

186

// Derive user-specific master key

187

deriveUserMasterKey(userId) {

188

const userContext = Buffer.alloc(sodium.crypto_kdf_CONTEXTBYTES);

189

Buffer.from('UserKeys').copy(userContext);

190

191

const userMasterKey = Buffer.alloc(sodium.crypto_kdf_KEYBYTES);

192

sodium.crypto_kdf_derive_from_key(

193

userMasterKey,

194

userId,

195

userContext,

196

this.systemMasterKey

197

);

198

199

return userMasterKey;

200

}

201

202

// Derive specific keys for a user

203

deriveUserKeys(userId) {

204

const userMasterKey = this.deriveUserMasterKey(userId);

205

206

const userContext = Buffer.alloc(sodium.crypto_kdf_CONTEXTBYTES);

207

Buffer.from('UserData').copy(userContext);

208

209

// Derive different keys for user data

210

const fileKey = Buffer.alloc(32);

211

const profileKey = Buffer.alloc(32);

212

const settingsKey = Buffer.alloc(32);

213

214

sodium.crypto_kdf_derive_from_key(fileKey, 1, userContext, userMasterKey);

215

sodium.crypto_kdf_derive_from_key(profileKey, 2, userContext, userMasterKey);

216

sodium.crypto_kdf_derive_from_key(settingsKey, 3, userContext, userMasterKey);

217

218

// Clean up user master key from memory

219

sodium.sodium_memzero(userMasterKey);

220

221

return {

222

fileEncryption: fileKey,

223

profileEncryption: profileKey,

224

settingsEncryption: settingsKey

225

};

226

}

227

}

228

229

// Usage

230

const systemKey = 'system-master-key-32-bytes-long!!!';

231

const userKdf = new UserKeyDerivation(systemKey);

232

233

const user123Keys = userKdf.deriveUserKeys(123);

234

const user456Keys = userKdf.deriveUserKeys(456);

235

```

236

237

### Hierarchical Key Derivation

238

239

```javascript

240

const sodium = require('sodium-native');

241

242

class HierarchicalKeyDerivation {

243

constructor() {

244

// Root master key

245

this.rootKey = Buffer.alloc(sodium.crypto_kdf_KEYBYTES);

246

sodium.crypto_kdf_keygen(this.rootKey);

247

}

248

249

// Derive domain-specific master keys

250

deriveDomainKey(domain) {

251

const domainContext = Buffer.alloc(sodium.crypto_kdf_CONTEXTBYTES);

252

Buffer.from('Domains').copy(domainContext);

253

254

const domainKey = Buffer.alloc(sodium.crypto_kdf_KEYBYTES);

255

const domainId = this.hashStringToId(domain);

256

257

sodium.crypto_kdf_derive_from_key(

258

domainKey,

259

domainId,

260

domainContext,

261

this.rootKey

262

);

263

264

return domainKey;

265

}

266

267

// Derive service keys within a domain

268

deriveServiceKey(domain, service) {

269

const domainKey = this.deriveDomainKey(domain);

270

271

const serviceContext = Buffer.alloc(sodium.crypto_kdf_CONTEXTBYTES);

272

Buffer.from(`${domain}`).copy(serviceContext);

273

274

const serviceKey = Buffer.alloc(sodium.crypto_kdf_KEYBYTES);

275

const serviceId = this.hashStringToId(service);

276

277

sodium.crypto_kdf_derive_from_key(

278

serviceKey,

279

serviceId,

280

serviceContext,

281

domainKey

282

);

283

284

// Clean up domain key

285

sodium.sodium_memzero(domainKey);

286

287

return serviceKey;

288

}

289

290

// Derive operational keys for specific purposes

291

deriveOperationalKey(domain, service, operation, keySize = 32) {

292

const serviceKey = this.deriveServiceKey(domain, service);

293

294

const opContext = Buffer.alloc(sodium.crypto_kdf_CONTEXTBYTES);

295

Buffer.from(`${service}`).copy(opContext);

296

297

const operationalKey = Buffer.alloc(keySize);

298

const operationId = this.hashStringToId(operation);

299

300

sodium.crypto_kdf_derive_from_key(

301

operationalKey,

302

operationId,

303

opContext,

304

serviceKey

305

);

306

307

// Clean up service key

308

sodium.sodium_memzero(serviceKey);

309

310

return operationalKey;

311

}

312

313

// Helper to convert string to numeric ID

314

hashStringToId(str) {

315

const hash = Buffer.alloc(4);

316

sodium.crypto_generichash(hash, Buffer.from(str));

317

return hash.readUInt32LE(0);

318

}

319

}

320

321

// Usage

322

const hkdf = new HierarchicalKeyDerivation();

323

324

// Derive keys at different levels

325

const authServiceKey = hkdf.deriveServiceKey('production', 'auth-service');

326

const dbEncryptionKey = hkdf.deriveOperationalKey('production', 'database', 'encryption');

327

const logSigningKey = hkdf.deriveOperationalKey('production', 'logging', 'signing', 64);

328

329

// Same operations will always produce same keys

330

const dbEncryptionKey2 = hkdf.deriveOperationalKey('production', 'database', 'encryption');

331

console.log('Keys match:', dbEncryptionKey.equals(dbEncryptionKey2));

332

```

333

334

### Key Versioning System

335

336

```javascript

337

const sodium = require('sodium-native');

338

339

class VersionedKeyManager {

340

constructor() {

341

this.masterKeys = new Map(); // version -> master key

342

this.currentVersion = 1;

343

344

// Initialize with first version

345

this.generateNewVersion();

346

}

347

348

generateNewVersion() {

349

const masterKey = Buffer.alloc(sodium.crypto_kdf_KEYBYTES);

350

sodium.crypto_kdf_keygen(masterKey);

351

352

this.masterKeys.set(this.currentVersion, masterKey);

353

return this.currentVersion;

354

}

355

356

rotateKeys() {

357

this.currentVersion++;

358

return this.generateNewVersion();

359

}

360

361

deriveKey(keyPurpose, version = null, keySize = 32) {

362

const useVersion = version || this.currentVersion;

363

const masterKey = this.masterKeys.get(useVersion);

364

365

if (!masterKey) {

366

throw new Error(`No master key for version ${useVersion}`);

367

}

368

369

const context = Buffer.alloc(sodium.crypto_kdf_CONTEXTBYTES);

370

Buffer.from(`v${useVersion}`).copy(context);

371

372

const purposeId = this.hashStringToId(keyPurpose);

373

const derivedKey = Buffer.alloc(keySize);

374

375

sodium.crypto_kdf_derive_from_key(

376

derivedKey,

377

purposeId,

378

context,

379

masterKey

380

);

381

382

return {

383

key: derivedKey,

384

version: useVersion,

385

purpose: keyPurpose

386

};

387

}

388

389

// Clean up old versions (keep only recent versions)

390

cleanupOldVersions(keepCount = 3) {

391

const versions = Array.from(this.masterKeys.keys()).sort((a, b) => b - a);

392

393

for (let i = keepCount; i < versions.length; i++) {

394

const oldVersion = versions[i];

395

const oldKey = this.masterKeys.get(oldVersion);

396

397

if (oldKey) {

398

sodium.sodium_memzero(oldKey);

399

this.masterKeys.delete(oldVersion);

400

}

401

}

402

}

403

404

hashStringToId(str) {

405

const hash = Buffer.alloc(4);

406

sodium.crypto_generichash(hash, Buffer.from(str));

407

return hash.readUInt32LE(0);

408

}

409

}

410

411

// Usage

412

const versionedKeys = new VersionedKeyManager();

413

414

// Get current keys

415

const currentDbKey = versionedKeys.deriveKey('database-encryption');

416

const currentApiKey = versionedKeys.deriveKey('api-signing');

417

418

console.log(`Database key version: ${currentDbKey.version}`);

419

420

// Rotate keys

421

const newVersion = versionedKeys.rotateKeys();

422

console.log(`Rotated to version: ${newVersion}`);

423

424

// Get new keys

425

const newDbKey = versionedKeys.deriveKey('database-encryption');

426

console.log(`New database key version: ${newDbKey.version}`);

427

428

// Still can access old keys for decryption

429

const oldDbKey = versionedKeys.deriveKey('database-encryption', currentDbKey.version);

430

console.log('Old key still accessible:', oldDbKey.key.equals(currentDbKey.key));

431

```