or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

constants-algorithms.mdindex.mdjwe-operations.mdjwk-management.mdjws-operations.mdjwt-operations.md

jwk-management.mddocs/

0

# JWK Management

1

2

JSON Web Key functionality for constructing, managing, and converting between different key formats and representations. JWK provides a standardized way to represent cryptographic keys in JSON format for use with JOSE operations.

3

4

## Capabilities

5

6

### Key Construction

7

8

Constructs JWK objects from various key formats and representations for use with JOSE operations.

9

10

```python { .api }

11

def construct(key_data, algorithm=None):

12

"""

13

Constructs a JWK from key data.

14

15

Args:

16

key_data (str or bytes or dict): The key material in various formats:

17

- String secrets for HMAC algorithms

18

- PEM-formatted RSA/EC keys (public or private)

19

- SSH-formatted keys

20

- JWK dictionaries (JSON Web Key format)

21

- Raw key bytes

22

algorithm (str, optional): Algorithm hint for key construction.

23

Helps determine the appropriate key type when ambiguous

24

25

Returns:

26

Key: A key object (HMACKey, RSAKey, ECKey, AESKey, or DIRKey)

27

that can be used with jwt, jws, and jwe operations

28

29

Raises:

30

JWKError: If the key cannot be constructed or format is invalid

31

"""

32

```

33

34

**Usage Examples:**

35

36

```python

37

from jose import jwk

38

from jose.constants import ALGORITHMS

39

40

# HMAC key from string secret

41

key = jwk.construct('my-secret-key', algorithm=ALGORITHMS.HS256)

42

43

# HMAC key from bytes

44

key = jwk.construct(b'binary-secret-key', algorithm=ALGORITHMS.HS256)

45

46

# RSA key from PEM format

47

rsa_pem = """-----BEGIN PRIVATE KEY-----

48

MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...

49

-----END PRIVATE KEY-----"""

50

51

rsa_key = jwk.construct(rsa_pem, algorithm=ALGORITHMS.RS256)

52

53

# RSA public key

54

rsa_public_pem = """-----BEGIN PUBLIC KEY-----

55

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...

56

-----END PUBLIC KEY-----"""

57

58

rsa_public_key = jwk.construct(rsa_public_pem)

59

60

# EC key from PEM format

61

ec_pem = """-----BEGIN PRIVATE KEY-----

62

MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg...

63

-----END PRIVATE KEY-----"""

64

65

ec_key = jwk.construct(ec_pem, algorithm=ALGORITHMS.ES256)

66

67

# JWK dictionary format

68

jwk_dict = {

69

'kty': 'oct', # Key type: octet sequence (symmetric)

70

'k': 'GawgguFyGrWKav7AX4VKUg', # base64url-encoded key value

71

'alg': 'HS256', # Algorithm

72

'use': 'sig' # Usage: signature

73

}

74

key = jwk.construct(jwk_dict)

75

76

# RSA JWK dictionary

77

rsa_jwk = {

78

'kty': 'RSA',

79

'n': 'public-modulus-base64url',

80

'd': 'private-exponent-base64url',

81

'e': 'AQAB', # public exponent (65537)

82

'alg': 'RS256'

83

}

84

rsa_key = jwk.construct(rsa_jwk)

85

86

# EC JWK dictionary

87

ec_jwk = {

88

'kty': 'EC',

89

'crv': 'P-256', # Curve

90

'x': 'x-coordinate-base64url',

91

'y': 'y-coordinate-base64url',

92

'd': 'private-key-base64url',

93

'alg': 'ES256'

94

}

95

ec_key = jwk.construct(ec_jwk)

96

97

# AES key for JWE

98

aes_key_bytes = b'This is a 32-byte key for AES256!!'

99

aes_key = jwk.construct(aes_key_bytes, algorithm=ALGORITHMS.A256GCM)

100

```

101

102

### Key Class Retrieval

103

104

Gets the appropriate key class for a given algorithm, useful for backend selection and key type determination.

105

106

```python { .api }

107

def get_key(algorithm):

108

"""

109

Get key class for algorithm.

110

111

Args:

112

algorithm (str): The algorithm name (e.g., 'HS256', 'RS256', 'ES256')

113

114

Returns:

115

type or None: The key class that handles the algorithm, or None if not found

116

"""

117

```

118

119

**Usage Examples:**

120

121

```python

122

from jose import jwk

123

from jose.constants import ALGORITHMS

124

125

# Get key class for HMAC

126

hmac_key_class = jwk.get_key(ALGORITHMS.HS256)

127

print(hmac_key_class) # <class 'jose.backends.cryptography_backend.CryptographyHMACKey'>

128

129

# Get key class for RSA

130

rsa_key_class = jwk.get_key(ALGORITHMS.RS256)

131

print(rsa_key_class) # <class 'jose.backends.cryptography_backend.CryptographyRSAKey'>

132

133

# Get key class for EC

134

ec_key_class = jwk.get_key(ALGORITHMS.ES256)

135

print(ec_key_class) # <class 'jose.backends.cryptography_backend.CryptographyECKey'>

136

137

# Check if algorithm is supported

138

if jwk.get_key('UNSUPPORTED_ALG') is None:

139

print("Algorithm not supported")

140

141

# Dynamic key construction

142

algorithm = ALGORITHMS.HS256

143

key_class = jwk.get_key(algorithm)

144

if key_class:

145

key = key_class('secret-key', algorithm)

146

```

147

148

### Key Registration

149

150

Registers custom key classes for specific algorithms, enabling extensibility for custom cryptographic backends.

151

152

```python { .api }

153

def register_key(algorithm, key_class):

154

"""

155

Registers a key class for an algorithm.

156

157

Args:

158

algorithm (str): The algorithm name to register

159

key_class (type): The key class that must inherit from jose.backends.base.Key

160

161

Returns:

162

bool: True if registration was successful

163

164

Raises:

165

JWKError: If the key class is invalid or doesn't inherit from Key

166

"""

167

```

168

169

**Usage Examples:**

170

171

```python

172

from jose import jwk

173

from jose.backends.base import Key

174

175

# Custom key implementation

176

class CustomHMACKey(Key):

177

def __init__(self, key_data, algorithm):

178

super().__init__(key_data, algorithm)

179

# Custom initialization

180

181

def sign(self, msg):

182

# Custom signing implementation

183

pass

184

185

def verify(self, msg, sig):

186

# Custom verification implementation

187

pass

188

189

# Register custom key

190

success = jwk.register_key('CUSTOM_HMAC', CustomHMACKey)

191

if success:

192

print("Custom key registered successfully")

193

194

# Use registered key

195

key = jwk.construct('secret', algorithm='CUSTOM_HMAC')

196

```

197

198

## Key Classes

199

200

The JWK module provides access to various key implementation classes through different cryptographic backends.

201

202

### Base Key Class

203

204

```python { .api }

205

class Key:

206

"""

207

Base class for all key implementations.

208

209

Args:

210

prepared_key: The prepared key material

211

algorithm (str): The algorithm this key will be used with

212

"""

213

214

def __init__(self, prepared_key, algorithm):

215

"""Initialize the key with prepared key material and algorithm."""

216

217

def sign(self, msg):

218

"""

219

Sign a message (abstract method).

220

221

Args:

222

msg (bytes): The message to sign

223

224

Returns:

225

bytes: The signature

226

"""

227

228

def verify(self, msg, sig):

229

"""

230

Verify a signature (abstract method).

231

232

Args:

233

msg (bytes): The original message

234

sig (bytes): The signature to verify

235

236

Returns:

237

bool: True if signature is valid

238

"""

239

240

def encrypt(self, plaintext):

241

"""Encrypt plaintext (abstract method for JWE keys)."""

242

243

def decrypt(self, ciphertext, **kwargs):

244

"""Decrypt ciphertext (abstract method for JWE keys)."""

245

246

def wrap_key(self, key_data):

247

"""Wrap a key (abstract method for key wrapping algorithms)."""

248

249

def unwrap_key(self, wrapped_key):

250

"""Unwrap a key (abstract method for key wrapping algorithms)."""

251

```

252

253

### HMAC Key Class

254

255

```python { .api }

256

class HMACKey(Key):

257

"""

258

HMAC key implementation for symmetric signing algorithms.

259

260

Supports: HS256, HS384, HS512

261

"""

262

263

def __init__(self, key_data, algorithm):

264

"""Initialize HMAC key with secret and algorithm."""

265

266

def to_dict(self):

267

"""

268

Convert key to JWK dictionary format.

269

270

Returns:

271

dict: JWK representation of the key

272

"""

273

274

def sign(self, msg):

275

"""Sign message with HMAC."""

276

277

def verify(self, msg, sig):

278

"""Verify HMAC signature."""

279

```

280

281

### RSA Key Class

282

283

```python { .api }

284

class RSAKey(Key):

285

"""

286

RSA key implementation for asymmetric operations.

287

288

Supports: RS256, RS384, RS512, PS256, PS384, PS512 (backend dependent)

289

Key wrapping: RSA1_5, RSA-OAEP, RSA-OAEP-256

290

"""

291

292

def __init__(self, key_data, algorithm):

293

"""Initialize RSA key from PEM data or JWK dictionary."""

294

295

def to_dict(self):

296

"""Convert to JWK dictionary format."""

297

298

def sign(self, msg):

299

"""Sign message with RSA private key."""

300

301

def verify(self, msg, sig):

302

"""Verify signature with RSA public key."""

303

304

def encrypt(self, plaintext):

305

"""Encrypt with RSA public key (for JWE)."""

306

307

def decrypt(self, ciphertext):

308

"""Decrypt with RSA private key (for JWE)."""

309

```

310

311

### EC Key Class

312

313

```python { .api }

314

class ECKey(Key):

315

"""

316

Elliptic Curve key implementation.

317

318

Supports: ES256, ES384, ES512

319

Curves: P-256, P-384, P-521

320

"""

321

322

def __init__(self, key_data, algorithm):

323

"""Initialize EC key from PEM data or JWK dictionary."""

324

325

def to_dict(self):

326

"""Convert to JWK dictionary format."""

327

328

def sign(self, msg):

329

"""Sign message with EC private key."""

330

331

def verify(self, msg, sig):

332

"""Verify signature with EC public key."""

333

```

334

335

### AES Key Class

336

337

```python { .api }

338

class AESKey(Key):

339

"""

340

AES key implementation for symmetric encryption.

341

342

Supports: A128KW, A192KW, A256KW (key wrapping)

343

A128GCM, A192GCM, A256GCM (content encryption)

344

"""

345

346

def __init__(self, key_data, algorithm):

347

"""Initialize AES key with key bytes."""

348

349

def encrypt(self, plaintext):

350

"""Encrypt with AES (algorithm-dependent mode)."""

351

352

def decrypt(self, ciphertext, **kwargs):

353

"""Decrypt with AES (algorithm-dependent mode)."""

354

355

def wrap_key(self, key_data):

356

"""Wrap key with AES key wrapping."""

357

358

def unwrap_key(self, wrapped_key):

359

"""Unwrap key with AES key wrapping."""

360

```

361

362

## JWK Dictionary Format

363

364

JWK (JSON Web Key) provides a standardized JSON representation for cryptographic keys:

365

366

### Symmetric Keys (HMAC)

367

368

```python { .api }

369

# HMAC key JWK format

370

hmac_jwk = {

371

'kty': 'oct', # Key type: octet sequence

372

'k': 'base64url-key', # Key value (base64url encoded)

373

'alg': 'HS256', # Algorithm (optional)

374

'use': 'sig', # Usage: sig (signature) or enc (encryption)

375

'kid': 'key-id' # Key ID (optional)

376

}

377

```

378

379

### RSA Keys

380

381

```python { .api }

382

# RSA private key JWK format

383

rsa_private_jwk = {

384

'kty': 'RSA', # Key type: RSA

385

'n': 'modulus-b64url', # Public modulus

386

'e': 'AQAB', # Public exponent (usually 65537)

387

'd': 'private-exp-b64url', # Private exponent

388

'p': 'prime1-b64url', # First prime factor

389

'q': 'prime2-b64url', # Second prime factor

390

'dp': 'exp1-b64url', # First factor exponent

391

'dq': 'exp2-b64url', # Second factor exponent

392

'qi': 'coefficient-b64url', # Coefficient

393

'alg': 'RS256', # Algorithm

394

'use': 'sig', # Usage

395

'kid': 'rsa-key-1' # Key ID

396

}

397

398

# RSA public key JWK format (subset of private)

399

rsa_public_jwk = {

400

'kty': 'RSA',

401

'n': 'modulus-b64url',

402

'e': 'AQAB',

403

'alg': 'RS256',

404

'use': 'sig',

405

'kid': 'rsa-key-1'

406

}

407

```

408

409

### Elliptic Curve Keys

410

411

```python { .api }

412

# EC private key JWK format

413

ec_private_jwk = {

414

'kty': 'EC', # Key type: Elliptic Curve

415

'crv': 'P-256', # Curve: P-256, P-384, or P-521

416

'x': 'x-coord-b64url', # X coordinate

417

'y': 'y-coord-b64url', # Y coordinate

418

'd': 'private-key-b64url', # Private key

419

'alg': 'ES256', # Algorithm

420

'use': 'sig', # Usage

421

'kid': 'ec-key-1' # Key ID

422

}

423

424

# EC public key JWK format (without 'd')

425

ec_public_jwk = {

426

'kty': 'EC',

427

'crv': 'P-256',

428

'x': 'x-coord-b64url',

429

'y': 'y-coord-b64url',

430

'alg': 'ES256',

431

'use': 'sig',

432

'kid': 'ec-key-1'

433

}

434

```

435

436

## Key Format Support

437

438

The JWK module supports various input key formats:

439

440

### PEM Format

441

442

```python

443

# RSA private key in PEM format

444

rsa_pem = """-----BEGIN PRIVATE KEY-----

445

MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...

446

-----END PRIVATE KEY-----"""

447

448

# RSA public key in PEM format

449

rsa_public_pem = """-----BEGIN PUBLIC KEY-----

450

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...

451

-----END PUBLIC KEY-----"""

452

453

# EC private key in PEM format

454

ec_pem = """-----BEGIN PRIVATE KEY-----

455

MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg...

456

-----END PRIVATE KEY-----"""

457

458

# Construct keys from PEM

459

rsa_key = jwk.construct(rsa_pem)

460

ec_key = jwk.construct(ec_pem)

461

```

462

463

### Raw Key Material

464

465

```python

466

# HMAC secret as string or bytes

467

hmac_secret = 'my-secret-key'

468

hmac_bytes = b'binary-secret-key'

469

470

# AES key as bytes (specific lengths)

471

aes_128_key = b'16-byte key here'

472

aes_256_key = b'This is a 32-byte key for AES256!!'

473

474

# Construct from raw material

475

hmac_key = jwk.construct(hmac_secret, algorithm='HS256')

476

aes_key = jwk.construct(aes_256_key, algorithm='A256GCM')

477

```

478

479

## Backend Integration

480

481

JWK automatically selects the best available cryptographic backend:

482

483

```python

484

# Backend priority (highest to lowest):

485

# 1. cryptography (pyca/cryptography) - Recommended

486

# 2. native-python (python-rsa, python-ecdsa)

487

# 3. pycryptodome (alternative backend)

488

489

# Check which backend is being used

490

key = jwk.construct('secret', algorithm='HS256')

491

print(type(key)) # Shows the backend class being used

492

493

# Examples of backend classes:

494

# - CryptographyHMACKey (cryptography backend)

495

# - CryptographyRSAKey (cryptography backend)

496

# - CryptographyECKey (cryptography backend)

497

# - RSAKey (native backend)

498

# - ECDSAECKey (native backend)

499

```

500

501

## Error Handling

502

503

JWK operations can raise specific exceptions:

504

505

```python { .api }

506

class JWKError(JOSEError):

507

"""Base exception for JWK-related errors."""

508

```

509

510

**Error Handling Examples:**

511

512

```python

513

from jose.exceptions import JWKError

514

515

try:

516

# Invalid key format

517

key = jwk.construct('invalid-key-format')

518

except JWKError as e:

519

print(f"Key construction failed: {e}")

520

521

try:

522

# Unsupported algorithm

523

key_class = jwk.get_key('UNKNOWN_ALGORITHM')

524

if key_class is None:

525

print("Algorithm not supported")

526

except JWKError as e:

527

print(f"Key retrieval failed: {e}")

528

529

try:

530

# Invalid JWK dictionary

531

invalid_jwk = {'kty': 'INVALID', 'k': 'key'}

532

key = jwk.construct(invalid_jwk)

533

except JWKError as e:

534

print(f"Invalid JWK: {e}")

535

```

536

537

## Usage with Other JOSE Operations

538

539

JWK objects integrate seamlessly with JWT, JWS, and JWE operations:

540

541

```python

542

from jose import jwt, jws, jwe, jwk

543

544

# Construct key once, use everywhere

545

key = jwk.construct('shared-secret', algorithm='HS256')

546

547

# Use with JWT

548

token = jwt.encode({'user': 'john'}, key)

549

claims = jwt.decode(token, key, algorithms=['HS256'])

550

551

# Use with JWS

552

signature = jws.sign('message', key)

553

payload = jws.verify(signature, key, algorithms=['HS256'])

554

555

# For JWE (with appropriate key type)

556

aes_key = jwk.construct(b'32-byte-key-for-aes-256-gcm!!!!', algorithm='A256GCM')

557

encrypted = jwe.encrypt(b'secret', aes_key, algorithm='dir')

558

plaintext = jwe.decrypt(encrypted, aes_key)

559

```

560

561

## Best Practices

562

563

1. **Key Generation**: Use cryptographically secure random sources for key generation

564

2. **Key Storage**: Store keys securely, separate from application code

565

3. **Key Rotation**: Implement regular key rotation with overlapping validity periods

566

4. **Algorithm Selection**: Use strong algorithms (HS256+, RS256+, ES256+)

567

5. **Key Size**: Use appropriate key sizes (256-bit HMAC, 2048+ bit RSA, P-256+ EC)

568

6. **JWK Format**: Use JWK format for key distribution and storage when possible

569

7. **Backend Selection**: Prefer cryptography backend for production environments

570

8. **Error Handling**: Always handle JWKError exceptions in key operations