or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

errors.mdindex.mdinterfaces.mdjwa.mdjwk.mdjws.mdutilities.md

jwk.mddocs/

0

# JSON Web Keys (JWK)

1

2

Key representation and management implementing the JSON Web Key specification (RFC 7517). Provides unified interfaces for RSA, Elliptic Curve, and symmetric keys with support for key loading, thumbprint generation, and public key extraction.

3

4

## Capabilities

5

6

### Base JWK Class

7

8

Abstract base class providing common functionality for all JSON Web Key types.

9

10

```python { .api }

11

class JWK:

12

"""Base class for JSON Web Keys"""

13

14

def thumbprint(self, hash_function=hashes.SHA256) -> bytes:

15

"""

16

Compute JWK Thumbprint according to RFC 7638.

17

18

Parameters:

19

- hash_function: Hash algorithm factory (default: SHA256)

20

21

Returns:

22

bytes: Key thumbprint hash

23

"""

24

25

def public_key(self) -> 'JWK':

26

"""

27

Generate JWK containing only the public key.

28

For symmetric keys, returns self.

29

30

Returns:

31

JWK: Public key JWK instance

32

"""

33

34

@classmethod

35

def from_json(cls, jobj: Any) -> 'JWK':

36

"""Deserialize JWK from JSON object"""

37

38

def to_partial_json(self) -> Any:

39

"""Serialize JWK to JSON-compatible dictionary"""

40

41

@classmethod

42

def load(cls, data: bytes, password: Optional[bytes] = None, backend: Optional[Any] = None) -> 'JWK':

43

"""

44

Load serialized key as JWK with automatic type detection.

45

46

Parameters:

47

- data: Public or private key serialized as PEM or DER

48

- password: Optional password for encrypted private keys

49

- backend: Cryptography backend (defaults to default_backend())

50

51

Returns:

52

JWK: JWK instance of appropriate type (JWKRSA, JWKEC, or JWKOct)

53

54

Raises:

55

josepy.errors.Error: If unable to deserialize or unsupported algorithm

56

"""

57

58

@classmethod

59

def _load_cryptography_key(cls, data: bytes, password: Optional[bytes] = None, backend: Optional[Any] = None) -> Any:

60

"""Load cryptography key from PEM/DER data"""

61

62

key: Any # Underlying cryptography key object

63

```

64

65

### RSA Keys (JWKRSA)

66

67

RSA key representation supporting both private and public keys with PKCS#1 and PSS algorithms.

68

69

```python { .api }

70

class JWKRSA(JWK):

71

"""RSA JSON Web Key"""

72

73

def __init__(self, key=None):

74

"""

75

Initialize RSA JWK.

76

77

Parameters:

78

- key: RSA private or public key from cryptography library,

79

or bytes/str containing PEM/DER encoded key data

80

"""

81

82

@classmethod

83

def load(cls, data: bytes, password: Optional[bytes] = None) -> 'JWKRSA':

84

"""

85

Load RSA key from PEM or DER encoded data.

86

87

Parameters:

88

- data: PEM or DER encoded key data

89

- password: Password for encrypted private keys

90

91

Returns:

92

JWKRSA: RSA JWK instance

93

"""

94

95

def public_key(self) -> 'JWKRSA':

96

"""Extract public key component"""

97

98

# JSON field mappings for RSA parameters

99

n: bytes # Modulus

100

e: bytes # Public exponent

101

d: bytes # Private exponent (private keys only)

102

p: bytes # First prime factor (private keys only)

103

q: bytes # Second prime factor (private keys only)

104

dp: bytes # First factor CRT exponent (private keys only)

105

dq: bytes # Second factor CRT exponent (private keys only)

106

qi: bytes # First CRT coefficient (private keys only)

107

```

108

109

#### Usage Examples

110

111

```python

112

from josepy import JWKRSA

113

from cryptography.hazmat.primitives.asymmetric import rsa

114

from cryptography.hazmat.backends import default_backend

115

from cryptography.hazmat.primitives import serialization

116

117

# Generate new RSA key

118

private_key = rsa.generate_private_key(

119

public_exponent=65537,

120

key_size=2048,

121

backend=default_backend()

122

)

123

124

# Create JWK from cryptography key

125

jwk = JWKRSA(key=private_key)

126

127

# Get public key JWK

128

public_jwk = jwk.public_key()

129

130

# Compute thumbprint

131

thumbprint = jwk.thumbprint()

132

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

133

134

# Serialize to JSON

135

jwk_json = jwk.json_dumps()

136

print(f"JWK JSON: {jwk_json}")

137

138

# Load from JSON

139

loaded_jwk = JWKRSA.json_loads(jwk_json)

140

141

# Load from PEM data

142

pem_data = private_key.private_bytes(

143

encoding=serialization.Encoding.PEM,

144

format=serialization.PrivateFormat.PKCS8,

145

encryption_algorithm=serialization.NoEncryption()

146

)

147

jwk_from_pem = JWKRSA.load(pem_data)

148

```

149

150

### Elliptic Curve Keys (JWKEC)

151

152

Elliptic Curve key representation supporting NIST P-curves for ECDSA operations.

153

154

```python { .api }

155

class JWKEC(JWK):

156

"""Elliptic Curve JSON Web Key"""

157

158

def __init__(self, key=None):

159

"""

160

Initialize EC JWK.

161

162

Parameters:

163

- key: EC private or public key from cryptography library,

164

or bytes/str containing PEM/DER encoded key data

165

"""

166

167

@classmethod

168

def load(cls, data: bytes, password: Optional[bytes] = None) -> 'JWKEC':

169

"""

170

Load EC key from PEM or DER encoded data.

171

172

Parameters:

173

- data: PEM or DER encoded key data

174

- password: Password for encrypted private keys

175

176

Returns:

177

JWKEC: EC JWK instance

178

"""

179

180

def public_key(self) -> 'JWKEC':

181

"""Extract public key component"""

182

183

# JSON field mappings for EC parameters

184

crv: str # Curve name ("P-256", "P-384", "P-521")

185

x: bytes # X coordinate

186

y: bytes # Y coordinate

187

d: bytes # Private key value (private keys only)

188

```

189

190

#### Usage Examples

191

192

```python

193

from josepy import JWKEC

194

from cryptography.hazmat.primitives.asymmetric import ec

195

from cryptography.hazmat.backends import default_backend

196

197

# Generate new EC key (P-256)

198

private_key = ec.generate_private_key(ec.SECP256R1(), default_backend())

199

200

# Create JWK from cryptography key

201

jwk_ec = JWKEC(key=private_key)

202

203

# Get public key JWK

204

public_jwk_ec = jwk_ec.public_key()

205

206

# Compute thumbprint

207

thumbprint_ec = jwk_ec.thumbprint()

208

print(f"EC Key thumbprint: {thumbprint_ec.hex()}")

209

210

# Different curves

211

p384_key = ec.generate_private_key(ec.SECP384R1(), default_backend())

212

jwk_p384 = JWKEC(key=p384_key)

213

214

p521_key = ec.generate_private_key(ec.SECP521R1(), default_backend())

215

jwk_p521 = JWKEC(key=p521_key)

216

```

217

218

### Symmetric Keys (JWKOct)

219

220

Octet string key representation for symmetric cryptographic operations including HMAC.

221

222

```python { .api }

223

class JWKOct(JWK):

224

"""Symmetric (Octet String) JSON Web Key"""

225

226

def __init__(self, key=None):

227

"""

228

Initialize symmetric JWK.

229

230

Parameters:

231

- key: bytes containing the symmetric key material

232

"""

233

234

def public_key(self) -> 'JWKOct':

235

"""For symmetric keys, returns self"""

236

237

# JSON field mappings

238

k: bytes # Key value (base64url encoded in JSON)

239

```

240

241

#### Usage Examples

242

243

```python

244

from josepy import JWKOct

245

import os

246

247

# Generate random symmetric key

248

key_bytes = os.urandom(32) # 256-bit key

249

jwk_oct = JWKOct(key=key_bytes)

250

251

# Symmetric keys are their own "public key"

252

same_key = jwk_oct.public_key()

253

assert jwk_oct is same_key

254

255

# Compute thumbprint

256

thumbprint_oct = jwk_oct.thumbprint()

257

print(f"Symmetric key thumbprint: {thumbprint_oct.hex()}")

258

259

# Use with HMAC algorithms

260

from josepy import HS256

261

message = b"Hello, HMAC!"

262

signature = HS256.sign(jwk_oct.key, message)

263

is_valid = HS256.verify(jwk_oct.key, message, signature)

264

print(f"HMAC signature valid: {is_valid}")

265

```

266

267

## Key Loading and Generation

268

269

### Loading Keys from Various Formats

270

271

```python

272

from josepy import JWKRSA, JWKEC

273

274

# Load from PEM files

275

with open('private_key.pem', 'rb') as f:

276

pem_data = f.read()

277

jwk_rsa = JWKRSA.load(pem_data)

278

279

# Load password-protected keys

280

with open('encrypted_key.pem', 'rb') as f:

281

encrypted_pem = f.read()

282

jwk_rsa = JWKRSA.load(encrypted_pem, password=b'secret')

283

284

# Load from DER format

285

with open('key.der', 'rb') as f:

286

der_data = f.read()

287

jwk_rsa = JWKRSA.load(der_data)

288

289

# Load EC keys

290

with open('ec_key.pem', 'rb') as f:

291

ec_pem = f.read()

292

jwk_ec = JWKEC.load(ec_pem)

293

```

294

295

### JSON Serialization and Deserialization

296

297

```python

298

from josepy import JWKRSA, JWKEC, JWKOct

299

300

# Serialize any JWK to JSON

301

jwk_json = jwk.json_dumps(indent=2)

302

303

# Deserialize from JSON (automatic type detection)

304

from josepy import JWK

305

loaded_jwk = JWK.from_json(json.loads(jwk_json))

306

307

# Type-specific deserialization

308

rsa_jwk = JWKRSA.json_loads(jwk_json)

309

ec_jwk = JWKEC.json_loads(jwk_json)

310

oct_jwk = JWKOct.json_loads(jwk_json)

311

```

312

313

## Key Thumbprints

314

315

JWK thumbprints provide unique identifiers for keys according to RFC 7638:

316

317

```python

318

from josepy import JWKRSA

319

from cryptography.hazmat.primitives import hashes

320

321

# Default SHA-256 thumbprint

322

thumbprint = jwk.thumbprint()

323

324

# Custom hash function

325

thumbprint_sha1 = jwk.thumbprint(hashes.SHA1)

326

thumbprint_sha512 = jwk.thumbprint(hashes.SHA512)

327

328

# Thumbprints are deterministic and unique per key

329

assert jwk.thumbprint() == jwk.thumbprint()

330

assert public_jwk.thumbprint() == jwk.thumbprint() # Same for public key

331

```

332

333

## Error Handling

334

335

```python

336

from josepy.errors import DeserializationError

337

338

try:

339

# Invalid JSON structure

340

jwk = JWKRSA.json_loads('{"invalid": "json"}')

341

except DeserializationError as e:

342

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

343

344

try:

345

# Invalid key data

346

jwk = JWKRSA.load(b"not a valid key")

347

except (ValueError, TypeError) as e:

348

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

349

```