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

jwe-operations.mddocs/

0

# JWE Operations

1

2

JSON Web Encryption functionality for encrypting and decrypting content using industry-standard encryption algorithms and key management methods. JWE provides confidentiality for sensitive data through authenticated encryption.

3

4

## Capabilities

5

6

### Content Encryption

7

8

Encrypts plaintext content and returns JWE compact serialization format with support for various encryption algorithms and key management methods.

9

10

```python { .api }

11

def encrypt(plaintext, key, encryption='A256GCM', algorithm='dir', zip=None, cty=None, kid=None):

12

"""

13

Encrypts plaintext and returns a JWE compact serialization string.

14

15

Args:

16

plaintext (bytes): The data to encrypt. Must be bytes object.

17

Use encode() to convert strings to bytes

18

key (str or bytes or dict): The encryption key. Supports:

19

- Bytes for direct encryption (dir algorithm)

20

- RSA public keys in PEM format for RSA key wrapping

21

- JWK dictionaries with appropriate key material

22

encryption (str): The content encryption algorithm. Defaults to 'A256GCM'.

23

Supported: A128GCM, A192GCM, A256GCM, A128CBC-HS256, A192CBC-HS384, A256CBC-HS512

24

algorithm (str): The key management algorithm. Defaults to 'dir'.

25

Supported: dir, RSA1_5, RSA-OAEP, RSA-OAEP-256, A128KW, A192KW, A256KW

26

zip (str, optional): The compression algorithm applied before encryption.

27

Supported: 'DEF' for DEFLATE compression, None for no compression

28

cty (str, optional): The content type of the secured content.

29

Examples: 'application/json', 'text/plain'

30

kid (str, optional): Key ID hint for the recipient to identify the key

31

32

Returns:

33

bytes: The JWE token in compact format (header.encryptedkey.iv.ciphertext.tag)

34

35

Raises:

36

JWEError: If encryption fails or parameters are invalid

37

JWEAlgorithmUnsupportedError: If the specified algorithm is not supported

38

"""

39

```

40

41

**Usage Examples:**

42

43

```python

44

from jose import jwe

45

from jose.constants import ALGORITHMS

46

47

# Basic AES-GCM encryption with direct key

48

key = b'This is a 32-byte key for AES256!!' # 32 bytes for A256GCM

49

plaintext = b'Secret message'

50

encrypted = jwe.encrypt(plaintext, key, ALGORITHMS.A256GCM, ALGORITHMS.DIR)

51

52

# String to bytes conversion

53

message = "Confidential data"

54

encrypted = jwe.encrypt(message.encode('utf-8'), key, ALGORITHMS.A256GCM, ALGORITHMS.DIR)

55

56

# RSA key wrapping with OAEP

57

rsa_public_key = """-----BEGIN PUBLIC KEY-----

58

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...

59

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

60

61

encrypted = jwe.encrypt(

62

b'Sensitive data',

63

rsa_public_key,

64

encryption=ALGORITHMS.A256GCM,

65

algorithm=ALGORITHMS.RSA_OAEP

66

)

67

68

# With compression

69

encrypted = jwe.encrypt(

70

b'Large repetitive data that compresses well...',

71

key,

72

encryption=ALGORITHMS.A256GCM,

73

algorithm=ALGORITHMS.DIR,

74

zip='DEF' # DEFLATE compression

75

)

76

77

# With content type and key ID

78

encrypted = jwe.encrypt(

79

b'{"user": "john", "role": "admin"}',

80

key,

81

encryption=ALGORITHMS.A256GCM,

82

algorithm=ALGORITHMS.DIR,

83

cty='application/json',

84

kid='encryption-key-1'

85

)

86

87

# AES key wrapping

88

aes_kek = b'Key Encryption Key 32 bytes!!!!!' # 32 bytes for A256KW

89

encrypted = jwe.encrypt(

90

b'Protected content',

91

aes_kek,

92

encryption=ALGORITHMS.A256GCM,

93

algorithm=ALGORITHMS.A256KW

94

)

95

96

# CBC with HMAC authentication

97

encrypted = jwe.encrypt(

98

b'Legacy compatibility data',

99

key,

100

encryption=ALGORITHMS.A256CBC_HS512,

101

algorithm=ALGORITHMS.DIR

102

)

103

```

104

105

### Content Decryption

106

107

Decrypts JWE tokens and returns the original plaintext after verifying authentication.

108

109

```python { .api }

110

def decrypt(jwe_str, key):

111

"""

112

Decrypts a JWE token and returns the original plaintext.

113

114

Args:

115

jwe_str (str or bytes): The JWE token to decrypt in compact format

116

key (str or bytes or dict): The decryption key. Must match the key

117

used for encryption and be appropriate for the key management algorithm:

118

- Bytes for direct encryption (dir algorithm)

119

- RSA private keys in PEM format for RSA key wrapping

120

- AES keys for AES key wrapping

121

- JWK dictionaries with appropriate key material

122

123

Returns:

124

bytes: The decrypted plaintext as bytes. Use decode() to convert to string

125

126

Raises:

127

JWEError: If decryption fails or token format is invalid

128

JWEParseError: If the JWE token cannot be parsed

129

JWEInvalidAuth: If authentication verification fails

130

"""

131

```

132

133

**Usage Examples:**

134

135

```python

136

from jose import jwe

137

from jose.exceptions import JWEError, JWEParseError, JWEInvalidAuth

138

139

try:

140

# Basic decryption

141

plaintext = jwe.decrypt(encrypted_token, key)

142

message = plaintext.decode('utf-8')

143

print(f"Decrypted: {message}")

144

145

except JWEInvalidAuth:

146

print("Authentication verification failed - data may be tampered")

147

except JWEParseError:

148

print("Invalid JWE token format")

149

except JWEError as e:

150

print(f"Decryption failed: {e}")

151

152

# RSA key unwrapping

153

rsa_private_key = """-----BEGIN PRIVATE KEY-----

154

MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...

155

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

156

157

plaintext = jwe.decrypt(encrypted_token, rsa_private_key)

158

159

# AES key unwrapping

160

aes_kek = b'Key Encryption Key 32 bytes!!!!!'

161

plaintext = jwe.decrypt(encrypted_token, aes_kek)

162

163

# Direct key decryption

164

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

165

plaintext = jwe.decrypt(encrypted_token, direct_key)

166

167

# JWK dictionary key

168

jwk_key = {

169

'kty': 'oct',

170

'k': 'VGhpcyBpcyBhIDMyLWJ5dGUga2V5IGZvciBBRVMyNTYhIQ' # base64url encoded

171

}

172

plaintext = jwe.decrypt(encrypted_token, jwk_key)

173

```

174

175

### Header Inspection

176

177

Retrieve JWE header information without performing decryption.

178

179

```python { .api }

180

def get_unverified_header(jwe_str):

181

"""

182

Get JWE header without verification or decryption.

183

184

Args:

185

jwe_str (str or bytes): The JWE token

186

187

Returns:

188

dict: The JWE header dictionary

189

190

Raises:

191

JWEParseError: If the JWE token format is invalid

192

"""

193

```

194

195

**Usage Examples:**

196

197

```python

198

# Inspect JWE header

199

header = jwe.get_unverified_header(encrypted_token)

200

print(f"Key Management Algorithm: {header['alg']}")

201

print(f"Content Encryption Algorithm: {header['enc']}")

202

print(f"Key ID: {header.get('kid')}")

203

print(f"Content Type: {header.get('cty')}")

204

print(f"Compression: {header.get('zip')}")

205

206

# Key selection based on header

207

header = jwe.get_unverified_header(encrypted_token)

208

key_id = header.get('kid')

209

if key_id == 'rsa-key-1':

210

key = rsa_private_key_1

211

elif key_id == 'rsa-key-2':

212

key = rsa_private_key_2

213

else:

214

key = default_key

215

216

plaintext = jwe.decrypt(encrypted_token, key)

217

```

218

219

## JWE Header Structure

220

221

JWE headers contain metadata about encryption algorithms and key management:

222

223

```python { .api }

224

# Standard JWE header fields

225

header = {

226

'alg': 'dir', # Key management algorithm (required)

227

'enc': 'A256GCM', # Content encryption algorithm (required)

228

'zip': 'DEF', # Compression algorithm (optional)

229

'kid': 'key-1', # Key ID for key identification (optional)

230

'cty': 'application/json', # Content type (optional)

231

'typ': 'JWE' # Type (optional)

232

}

233

```

234

235

## Encryption Algorithms

236

237

JWE supports multiple content encryption algorithms:

238

239

**AES-GCM (Authenticated Encryption):**

240

- `A128GCM`: AES-128-GCM (16-byte key)

241

- `A192GCM`: AES-192-GCM (24-byte key)

242

- `A256GCM`: AES-256-GCM (32-byte key) - **Recommended**

243

244

**AES-CBC with HMAC (Legacy Compatibility):**

245

- `A128CBC-HS256`: AES-128-CBC + HMAC-SHA-256

246

- `A192CBC-HS384`: AES-192-CBC + HMAC-SHA-384

247

- `A256CBC-HS512`: AES-256-CBC + HMAC-SHA-512

248

249

```python

250

from jose.constants import ALGORITHMS

251

252

# Modern authenticated encryption (recommended)

253

encrypted = jwe.encrypt(data, key, ALGORITHMS.A256GCM, ALGORITHMS.DIR)

254

255

# Legacy compatibility

256

encrypted = jwe.encrypt(data, key, ALGORITHMS.A256CBC_HS512, ALGORITHMS.DIR)

257

258

# Different key sizes

259

encrypted = jwe.encrypt(data, key_16, ALGORITHMS.A128GCM, ALGORITHMS.DIR) # 16-byte key

260

encrypted = jwe.encrypt(data, key_24, ALGORITHMS.A192GCM, ALGORITHMS.DIR) # 24-byte key

261

encrypted = jwe.encrypt(data, key_32, ALGORITHMS.A256GCM, ALGORITHMS.DIR) # 32-byte key

262

```

263

264

## Key Management Algorithms

265

266

JWE supports various key management methods:

267

268

**Direct Encryption:**

269

- `dir`: Direct use of Content Encryption Key (CEK)

270

271

**RSA Key Wrapping:**

272

- `RSA1_5`: RSA PKCS#1 v1.5 (legacy, not recommended)

273

- `RSA-OAEP`: RSA OAEP with SHA-1 and MGF1

274

- `RSA-OAEP-256`: RSA OAEP with SHA-256 and MGF1 - **Recommended**

275

276

**AES Key Wrapping:**

277

- `A128KW`: AES-128 Key Wrap

278

- `A192KW`: AES-192 Key Wrap

279

- `A256KW`: AES-256 Key Wrap

280

281

```python

282

# Direct encryption (CEK = key)

283

encrypted = jwe.encrypt(plaintext, direct_key, algorithm=ALGORITHMS.DIR)

284

285

# RSA key wrapping (recommended OAEP-256)

286

encrypted = jwe.encrypt(plaintext, rsa_public_key, algorithm=ALGORITHMS.RSA_OAEP_256)

287

288

# AES key wrapping

289

encrypted = jwe.encrypt(plaintext, aes_kek, algorithm=ALGORITHMS.A256KW)

290

```

291

292

## Key Requirements

293

294

Different algorithms require specific key formats and sizes:

295

296

```python

297

# Direct encryption key requirements

298

key_128 = b'16-byte key here' # For A128GCM

299

key_192 = b'24-byte key here!!!!!!!!' # For A192GCM

300

key_256 = b'This is a 32-byte key for AES256!!' # For A256GCM

301

302

# RSA keys (PEM format)

303

rsa_public_key = """-----BEGIN PUBLIC KEY-----

304

... (RSA public key in PEM format for encryption)

305

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

306

307

rsa_private_key = """-----BEGIN PRIVATE KEY-----

308

... (RSA private key in PEM format for decryption)

309

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

310

311

# AES Key Encryption Keys (KEK)

312

aes_kek_128 = b'16-byte KEK here' # For A128KW

313

aes_kek_192 = b'24-byte KEK here!!!!!!!' # For A192KW

314

aes_kek_256 = b'32-byte KEK for wrapping!!!!!!!!' # For A256KW

315

```

316

317

## Compression Support

318

319

JWE supports DEFLATE compression to reduce ciphertext size:

320

321

```python

322

# With compression (useful for large or repetitive data)

323

large_data = b'{"users": [' + b'{"name": "user", "role": "admin"},' * 1000 + b']}'

324

encrypted = jwe.encrypt(

325

large_data,

326

key,

327

encryption=ALGORITHMS.A256GCM,

328

algorithm=ALGORITHMS.DIR,

329

zip='DEF' # DEFLATE compression

330

)

331

332

# Compression is transparent during decryption

333

decrypted = jwe.decrypt(encrypted, key) # Automatically decompressed

334

```

335

336

## Error Handling

337

338

JWE operations can raise several specific exceptions:

339

340

```python { .api }

341

class JWEError(JOSEError):

342

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

343

344

class JWEParseError(JWEError):

345

"""JWE token parsing failed."""

346

347

class JWEInvalidAuth(JWEError):

348

"""JWE authentication verification failed."""

349

350

class JWEAlgorithmUnsupportedError(JWEError):

351

"""JWE algorithm not supported."""

352

```

353

354

**Error Handling Examples:**

355

356

```python

357

from jose.exceptions import JWEError, JWEParseError, JWEInvalidAuth, JWEAlgorithmUnsupportedError

358

359

try:

360

plaintext = jwe.decrypt(encrypted_token, key)

361

except JWEInvalidAuth:

362

print("Authentication failed - data may be corrupted or tampered")

363

except JWEParseError:

364

print("Invalid JWE token format")

365

except JWEAlgorithmUnsupportedError:

366

print("Encryption algorithm not supported by current backend")

367

except JWEError as e:

368

print(f"JWE operation failed: {e}")

369

370

# Encryption errors

371

try:

372

encrypted = jwe.encrypt(plaintext, key, 'UNSUPPORTED_ALG', 'dir')

373

except JWEAlgorithmUnsupportedError:

374

print("Unsupported encryption algorithm")

375

except JWEError as e:

376

print(f"Encryption failed: {e}")

377

```

378

379

## Security Considerations

380

381

1. **Algorithm Selection**: Use A256GCM with RSA-OAEP-256 for new applications

382

2. **Key Management**: Generate cryptographically secure random keys

383

3. **Key Size**: Use appropriate key sizes (256-bit for AES, 2048+ bit for RSA)

384

4. **Authentication**: Always verify authentication (handled automatically)

385

5. **Key Storage**: Store encryption keys securely, separate from encrypted data

386

6. **Key Rotation**: Implement key rotation for long-term security

387

388

## Integration with Other Modules

389

390

JWE works with other jose modules for complete JOSE functionality:

391

392

```python

393

from jose import jwe, jwk

394

395

# Use JWK for key management

396

key = jwk.construct({'kty': 'oct', 'k': 'encoded-key'})

397

encrypted = jwe.encrypt(plaintext, key, ALGORITHMS.A256GCM, ALGORITHMS.DIR)

398

399

# Nested JWT (signed then encrypted)

400

from jose import jwt

401

# First sign with JWT

402

signed_token = jwt.encode(claims, signing_key, algorithm='HS256')

403

# Then encrypt the JWT

404

encrypted_jwt = jwe.encrypt(signed_token.encode(), encryption_key, ALGORITHMS.A256GCM, ALGORITHMS.DIR)

405

406

# Decrypt then verify

407

decrypted_jwt = jwe.decrypt(encrypted_jwt, encryption_key)

408

claims = jwt.decode(decrypted_jwt.decode(), signing_key, algorithms=['HS256'])

409

```

410

411

## Best Practices

412

413

1. **Use authenticated encryption**: Prefer A256GCM over CBC+HMAC modes

414

2. **Strong key management**: Use RSA-OAEP-256 or secure key distribution

415

3. **Key rotation**: Implement regular key rotation policies

416

4. **Secure random keys**: Generate keys using cryptographically secure random sources

417

5. **Validate inputs**: Always validate plaintext size (max 250KB) and key formats

418

6. **Handle errors gracefully**: Implement proper error handling for all failure modes

419

7. **Compression consideration**: Use compression only when beneficial for data size