or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

aead-ciphers.mdasymmetric-cryptography.mdhash-functions.mdindex.mdkey-derivation.mdkey-serialization.mdmessage-authentication.mdsymmetric-ciphers.mdsymmetric-encryption.mdtwo-factor-auth.mdutilities.mdx509-certificates.md

message-authentication.mddocs/

0

# Message Authentication

1

2

Message authentication codes (MACs) and digital signatures for ensuring data integrity and authenticity. Protects against tampering and verifies message origin.

3

4

## Core Imports

5

6

```python

7

from cryptography.hazmat.primitives import hmac, cmac, poly1305

8

from cryptography.hazmat.primitives import hashes

9

from cryptography.hazmat.primitives.ciphers import algorithms

10

```

11

12

## Capabilities

13

14

### HMAC (Hash-based Message Authentication Code)

15

16

```python { .api }

17

class HMAC:

18

def __init__(self, key: bytes, algorithm, backend=None):

19

"""

20

Initialize HMAC with key and hash algorithm.

21

22

Args:

23

key (bytes): Secret key for authentication

24

algorithm: Hash algorithm (hashes.SHA256(), etc.)

25

backend: Cryptographic backend

26

"""

27

28

def update(self, data: bytes) -> None:

29

"""

30

Add data to MAC computation.

31

32

Args:

33

data (bytes): Data to authenticate

34

"""

35

36

def finalize(self) -> bytes:

37

"""

38

Finalize MAC and return authentication tag.

39

40

Returns:

41

bytes: HMAC authentication tag

42

"""

43

44

def verify(self, signature: bytes) -> None:

45

"""

46

Verify HMAC signature.

47

48

Args:

49

signature (bytes): Expected HMAC tag

50

51

Raises:

52

InvalidSignature: If verification fails

53

"""

54

55

def copy(self) -> 'HMAC':

56

"""Create copy of current HMAC state"""

57

```

58

59

### CMAC (Cipher-based Message Authentication Code)

60

61

```python { .api }

62

class CMAC:

63

def __init__(self, key: bytes, algorithm, backend=None):

64

"""

65

Initialize CMAC with key and cipher algorithm.

66

67

Args:

68

key (bytes): Secret key for authentication

69

algorithm: Block cipher algorithm (algorithms.AES(), etc.)

70

backend: Cryptographic backend

71

"""

72

73

def update(self, data: bytes) -> None:

74

"""Add data to CMAC computation"""

75

76

def finalize(self) -> bytes:

77

"""Finalize and return CMAC tag"""

78

79

def verify(self, signature: bytes) -> None:

80

"""

81

Verify CMAC signature.

82

83

Raises:

84

InvalidSignature: If verification fails

85

"""

86

87

def copy(self) -> 'CMAC':

88

"""Create copy of CMAC state"""

89

```

90

91

### Poly1305

92

93

```python { .api }

94

class Poly1305:

95

def __init__(self, key: bytes):

96

"""

97

Initialize Poly1305 MAC.

98

99

Args:

100

key (bytes): 32-byte secret key

101

"""

102

103

def update(self, data: bytes) -> None:

104

"""Add data to Poly1305 computation"""

105

106

def finalize(self) -> bytes:

107

"""

108

Finalize Poly1305 MAC.

109

110

Returns:

111

bytes: 16-byte authentication tag

112

"""

113

114

def verify(self, tag: bytes) -> None:

115

"""

116

Verify Poly1305 tag.

117

118

Raises:

119

InvalidSignature: If verification fails

120

"""

121

122

@classmethod

123

def generate_key(cls) -> bytes:

124

"""Generate random 32-byte key for Poly1305"""

125

```

126

127

## Usage Examples

128

129

### HMAC with SHA-256

130

131

```python

132

from cryptography.hazmat.primitives import hmac, hashes

133

from cryptography.exceptions import InvalidSignature

134

import os

135

136

# Generate HMAC key

137

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

138

139

# Create message to authenticate

140

message = b"Important message that needs authentication"

141

142

# Compute HMAC

143

h = hmac.HMAC(key, hashes.SHA256())

144

h.update(message)

145

tag = h.finalize()

146

147

print(f"HMAC-SHA256: {tag.hex()}")

148

149

# Verify HMAC

150

h_verify = hmac.HMAC(key, hashes.SHA256())

151

h_verify.update(message)

152

153

try:

154

h_verify.verify(tag)

155

print("HMAC verification: SUCCESS")

156

except InvalidSignature:

157

print("HMAC verification: FAILED")

158

```

159

160

### CMAC with AES

161

162

```python

163

from cryptography.hazmat.primitives import cmac

164

from cryptography.hazmat.primitives.ciphers import algorithms

165

from cryptography.exceptions import InvalidSignature

166

import os

167

168

# Generate AES key for CMAC

169

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

170

171

message = b"Data to authenticate with CMAC-AES"

172

173

# Compute CMAC

174

c = cmac.CMAC(key, algorithms.AES)

175

c.update(message)

176

tag = c.finalize()

177

178

print(f"CMAC-AES: {tag.hex()}")

179

180

# Verify CMAC

181

c_verify = cmac.CMAC(key, algorithms.AES)

182

c_verify.update(message)

183

184

try:

185

c_verify.verify(tag)

186

print("CMAC verification: SUCCESS")

187

except InvalidSignature:

188

print("CMAC verification: FAILED")

189

```

190

191

### Poly1305 Authentication

192

193

```python

194

from cryptography.hazmat.primitives import poly1305

195

from cryptography.exceptions import InvalidSignature

196

197

# Generate Poly1305 key

198

key = poly1305.Poly1305.generate_key()

199

200

message = b"Message authenticated with Poly1305"

201

202

# Compute Poly1305 tag

203

p = poly1305.Poly1305(key)

204

p.update(message)

205

tag = p.finalize()

206

207

print(f"Poly1305 tag: {tag.hex()}")

208

209

# Verify tag

210

p_verify = poly1305.Poly1305(key)

211

p_verify.update(message)

212

213

try:

214

p_verify.verify(tag)

215

print("Poly1305 verification: SUCCESS")

216

except InvalidSignature:

217

print("Poly1305 verification: FAILED")

218

```

219

220

### Message Authentication for API Requests

221

222

```python

223

from cryptography.hazmat.primitives import hmac, hashes

224

import time

225

import json

226

import hashlib

227

228

class APIAuthenticator:

229

def __init__(self, secret_key: bytes):

230

self.secret_key = secret_key

231

232

def sign_request(self, method: str, url: str, body: bytes = None, timestamp: int = None) -> str:

233

"""Sign API request with HMAC"""

234

if timestamp is None:

235

timestamp = int(time.time())

236

237

# Create string to sign

238

body_hash = hashlib.sha256(body or b"").hexdigest()

239

string_to_sign = f"{method}\n{url}\n{body_hash}\n{timestamp}"

240

241

# Compute HMAC

242

h = hmac.HMAC(self.secret_key, hashes.SHA256())

243

h.update(string_to_sign.encode())

244

signature = h.finalize()

245

246

return {

247

'signature': signature.hex(),

248

'timestamp': timestamp

249

}

250

251

def verify_request(self, method: str, url: str, body: bytes, signature: str, timestamp: int) -> bool:

252

"""Verify API request signature"""

253

# Check timestamp (prevent replay attacks)

254

current_time = int(time.time())

255

if abs(current_time - timestamp) > 300: # 5 minute window

256

return False

257

258

# Verify signature

259

expected_sig = self.sign_request(method, url, body, timestamp)

260

return expected_sig['signature'] == signature

261

262

# Usage

263

api_key = os.urandom(32)

264

authenticator = APIAuthenticator(api_key)

265

266

# Sign request

267

request_body = json.dumps({"user": "alice", "action": "transfer"}).encode()

268

auth_data = authenticator.sign_request("POST", "/api/transfer", request_body)

269

270

print(f"Request signature: {auth_data['signature']}")

271

print(f"Timestamp: {auth_data['timestamp']}")

272

273

# Verify request

274

is_valid = authenticator.verify_request(

275

"POST", "/api/transfer", request_body,

276

auth_data['signature'], auth_data['timestamp']

277

)

278

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

279

```

280

281

### File Integrity with HMAC

282

283

```python

284

from cryptography.hazmat.primitives import hmac, hashes

285

import os

286

287

class FileIntegrityChecker:

288

def __init__(self, key: bytes):

289

self.key = key

290

291

def compute_file_hmac(self, filepath: str) -> bytes:

292

"""Compute HMAC for file contents"""

293

h = hmac.HMAC(self.key, hashes.SHA256())

294

295

with open(filepath, 'rb') as f:

296

while chunk := f.read(8192):

297

h.update(chunk)

298

299

return h.finalize()

300

301

def create_integrity_file(self, filepath: str):

302

"""Create .hmac file with integrity hash"""

303

file_hmac = self.compute_file_hmac(filepath)

304

305

with open(f"{filepath}.hmac", 'wb') as f:

306

f.write(file_hmac)

307

308

print(f"Integrity file created: {filepath}.hmac")

309

310

def verify_file_integrity(self, filepath: str) -> bool:

311

"""Verify file against .hmac file"""

312

try:

313

with open(f"{filepath}.hmac", 'rb') as f:

314

stored_hmac = f.read()

315

316

current_hmac = self.compute_file_hmac(filepath)

317

return stored_hmac == current_hmac

318

319

except FileNotFoundError:

320

print(f"Integrity file not found: {filepath}.hmac")

321

return False

322

323

# Usage

324

integrity_key = os.urandom(32)

325

checker = FileIntegrityChecker(integrity_key)

326

327

# Create test file

328

with open('important_document.txt', 'w') as f:

329

f.write("This is an important document that must not be tampered with.\n")

330

331

# Create integrity hash

332

checker.create_integrity_file('important_document.txt')

333

334

# Verify integrity

335

is_intact = checker.verify_file_integrity('important_document.txt')

336

print(f"File integrity: {'OK' if is_intact else 'COMPROMISED'}")

337

338

# Simulate tampering

339

with open('important_document.txt', 'a') as f:

340

f.write("Unauthorized modification\n")

341

342

# Check integrity again

343

is_intact = checker.verify_file_integrity('important_document.txt')

344

print(f"File integrity after modification: {'OK' if is_intact else 'COMPROMISED'}")

345

```

346

347

### Streaming Authentication

348

349

```python

350

from cryptography.hazmat.primitives import hmac, hashes

351

from cryptography.exceptions import InvalidSignature

352

353

class StreamingMAC:

354

def __init__(self, key: bytes):

355

self.key = key

356

self.hmac = hmac.HMAC(key, hashes.SHA256())

357

358

def update(self, data: bytes):

359

"""Add data to streaming MAC"""

360

self.hmac.update(data)

361

362

def finalize(self) -> bytes:

363

"""Get final MAC tag"""

364

return self.hmac.finalize()

365

366

def verify_stream(self, expected_tag: bytes) -> bool:

367

"""Verify streaming MAC"""

368

# Create new HMAC for verification (original is finalized)

369

verify_hmac = hmac.HMAC(self.key, hashes.SHA256())

370

371

# Re-process all data would require storing it

372

# In practice, you'd compute MAC during initial processing

373

try:

374

verify_hmac.verify(expected_tag)

375

return True

376

except InvalidSignature:

377

return False

378

379

# Usage for streaming data

380

key = os.urandom(32)

381

stream_mac = StreamingMAC(key)

382

383

# Process data in chunks

384

data_chunks = [b"chunk1", b"chunk2", b"chunk3", b"final_chunk"]

385

386

for chunk in data_chunks:

387

stream_mac.update(chunk)

388

print(f"Processed chunk: {chunk}")

389

390

# Get final authentication tag

391

final_tag = stream_mac.finalize()

392

print(f"Stream MAC: {final_tag.hex()}")

393

```

394

395

## Security Considerations

396

397

- **Key Management**: Use different keys for different purposes

398

- **Key Length**: Use appropriately sized keys (32+ bytes for HMAC)

399

- **Timing Attacks**: Use constant-time comparison for MAC verification

400

- **Replay Protection**: Include timestamps or nonces in authenticated data

401

- **Algorithm Selection**: HMAC-SHA256 for most applications, Poly1305 for performance

402

- **MAC-then-Encrypt**: Apply MAC to plaintext, then encrypt both message and MAC

403

- **Verification**: Always verify MAC before processing authenticated data