or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

asymmetric.mdbackend.mdindex.mdkdf.mdkeys.mdsymmetric.mdtls.mdtrust-store.mdutility.md

utility.mddocs/

0

# Utility Functions

1

2

Cryptographic utilities including secure random number generation and constant-time comparison for security-critical operations. These functions provide essential building blocks for secure cryptographic implementations.

3

4

## Capabilities

5

6

### Secure Random Generation

7

8

Generate cryptographically secure random bytes using the operating system's entropy source.

9

10

```python { .api }

11

def rand_bytes(length: int) -> bytes:

12

"""

13

Generate cryptographically secure random bytes.

14

15

Parameters:

16

- length: int - Number of random bytes to generate

17

18

Returns:

19

Random bytes of specified length

20

21

Note:

22

Uses OS entropy sources (CryptGenRandom on Windows, /dev/urandom on Unix)

23

"""

24

```

25

26

### Constant-Time Comparison

27

28

Compare byte strings in constant time to prevent timing attacks in security-critical code.

29

30

```python { .api }

31

def constant_compare(a: bytes, b: bytes) -> bool:

32

"""

33

Compare two byte strings in constant time.

34

35

Parameters:

36

- a: bytes - First byte string

37

- b: bytes - Second byte string

38

39

Returns:

40

True if byte strings are equal, False otherwise

41

42

Raises:

43

TypeError if either parameter is not bytes

44

45

Note:

46

Comparison time is independent of where strings differ, preventing timing attacks

47

"""

48

```

49

50

## Usage Examples

51

52

### Secure Random Generation

53

54

```python

55

from oscrypto.util import rand_bytes

56

57

# Generate random keys of various sizes

58

aes_128_key = rand_bytes(16) # 128-bit AES key

59

aes_256_key = rand_bytes(32) # 256-bit AES key

60

random_salt = rand_bytes(16) # Salt for key derivation

61

session_id = rand_bytes(32) # Session identifier

62

63

print(f"AES-128 key: {aes_128_key.hex()}")

64

print(f"AES-256 key: {aes_256_key.hex()}")

65

print(f"Salt: {random_salt.hex()}")

66

print(f"Session ID: {session_id.hex()}")

67

68

# Generate random initialization vectors

69

aes_iv = rand_bytes(16) # AES block size

70

des_iv = rand_bytes(8) # DES block size

71

72

print(f"AES IV: {aes_iv.hex()}")

73

print(f"DES IV: {des_iv.hex()}")

74

```

75

76

### Constant-Time Comparison

77

78

```python

79

from oscrypto.util import constant_compare

80

import time

81

82

def timing_attack_demo():

83

"""Demonstrate why constant-time comparison is important."""

84

85

# Create two similar strings that differ at different positions

86

target = b"secret_authentication_token_12345678"

87

88

# Attack string differs at position 0

89

attack1 = b"xxxxxx_authentication_token_12345678"

90

91

# Attack string differs at position 30

92

attack2 = b"secret_authentication_token_1234xxxx"

93

94

# Measure time for regular comparison (vulnerable to timing attacks)

95

start = time.perf_counter()

96

for _ in range(100000):

97

result = target == attack1

98

time1 = time.perf_counter() - start

99

100

start = time.perf_counter()

101

for _ in range(100000):

102

result = target == attack2

103

time2 = time.perf_counter() - start

104

105

print("Regular comparison timing:")

106

print(f" Early difference: {time1:.6f} seconds")

107

print(f" Late difference: {time2:.6f} seconds")

108

print(f" Timing difference: {abs(time1 - time2):.6f} seconds")

109

110

# Measure time for constant-time comparison (secure)

111

start = time.perf_counter()

112

for _ in range(100000):

113

result = constant_compare(target, attack1)

114

time1 = time.perf_counter() - start

115

116

start = time.perf_counter()

117

for _ in range(100000):

118

result = constant_compare(target, attack2)

119

time2 = time.perf_counter() - start

120

121

print("\nConstant-time comparison:")

122

print(f" Early difference: {time1:.6f} seconds")

123

print(f" Late difference: {time2:.6f} seconds")

124

print(f" Timing difference: {abs(time1 - time2):.6f} seconds")

125

126

# Run timing demonstration

127

timing_attack_demo()

128

```

129

130

### Secure Token Generation

131

132

```python

133

from oscrypto.util import rand_bytes, constant_compare

134

import base64

135

import hashlib

136

137

class SecureTokenManager:

138

"""Example secure token management using oscrypto utilities."""

139

140

def __init__(self):

141

# Generate master key for token signing

142

self.master_key = rand_bytes(32)

143

144

def generate_token(self, user_id: str, expires_at: int) -> str:

145

"""Generate a secure token for a user."""

146

# Create token payload

147

payload = f"{user_id}:{expires_at}".encode('utf-8')

148

149

# Generate random nonce

150

nonce = rand_bytes(16)

151

152

# Create HMAC signature

153

hmac_key = hashlib.pbkdf2_hmac('sha256', self.master_key, nonce, 10000)

154

signature = hashlib.hmac.new(hmac_key, payload, hashlib.sha256).digest()

155

156

# Combine nonce + payload + signature

157

token_data = nonce + payload + signature

158

159

# Encode as base64

160

return base64.urlsafe_b64encode(token_data).decode('ascii')

161

162

def verify_token(self, token: str, user_id: str, expires_at: int) -> bool:

163

"""Verify a token in constant time."""

164

try:

165

# Decode token

166

token_data = base64.urlsafe_b64decode(token.encode('ascii'))

167

168

# Extract components

169

nonce = token_data[:16]

170

payload = token_data[16:-32]

171

signature = token_data[-32:]

172

173

# Verify payload matches expected values

174

expected_payload = f"{user_id}:{expires_at}".encode('utf-8')

175

if not constant_compare(payload, expected_payload):

176

return False

177

178

# Recreate signature

179

hmac_key = hashlib.pbkdf2_hmac('sha256', self.master_key, nonce, 10000)

180

expected_signature = hashlib.hmac.new(hmac_key, payload, hashlib.sha256).digest()

181

182

# Constant-time signature verification

183

return constant_compare(signature, expected_signature)

184

185

except Exception:

186

return False

187

188

# Example usage

189

token_manager = SecureTokenManager()

190

191

# Generate token

192

user_id = "user123"

193

expires_at = 1735689600 # Timestamp

194

token = token_manager.generate_token(user_id, expires_at)

195

print(f"Generated token: {token}")

196

197

# Verify valid token

198

is_valid = token_manager.verify_token(token, user_id, expires_at)

199

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

200

201

# Verify invalid token

202

is_valid = token_manager.verify_token(token + "x", user_id, expires_at)

203

print(f"Modified token valid: {is_valid}")

204

```

205

206

### Cryptographic Key Generation

207

208

```python

209

from oscrypto.util import rand_bytes

210

from oscrypto.kdf import pbkdf2

211

import base64

212

213

def generate_keypair_seed() -> str:

214

"""Generate a high-entropy seed for deterministic key generation."""

215

# Generate 256 bits of entropy

216

seed = rand_bytes(32)

217

218

# Encode as base64 for storage/transmission

219

return base64.b64encode(seed).decode('ascii')

220

221

def derive_multiple_keys(master_secret: bytes, key_count: int = 3) -> dict:

222

"""Derive multiple keys from a master secret."""

223

keys = {}

224

225

for i in range(key_count):

226

# Use different salt for each key

227

salt = f"key_derivation_{i}".encode('utf-8') + rand_bytes(8)

228

229

# Derive 32-byte key

230

key = pbkdf2('sha256', master_secret, salt, 100000, 32)

231

keys[f"key_{i}"] = key

232

233

return keys

234

235

def secure_key_splitting(secret: bytes, threshold: int, shares: int) -> list:

236

"""Simple secret sharing using XOR (for demonstration)."""

237

if threshold != shares:

238

raise ValueError("This example only supports threshold == shares")

239

240

# Generate random shares

241

share_list = []

242

running_xor = secret

243

244

for i in range(shares - 1):

245

share = rand_bytes(len(secret))

246

share_list.append(share)

247

248

# XOR with running total

249

running_xor = bytes(a ^ b for a, b in zip(running_xor, share))

250

251

# Last share is the XOR of all previous shares with the secret

252

share_list.append(running_xor)

253

254

return share_list

255

256

def reconstruct_secret(shares: list) -> bytes:

257

"""Reconstruct secret from XOR shares."""

258

result = shares[0]

259

for share in shares[1:]:

260

result = bytes(a ^ b for a, b in zip(result, share))

261

return result

262

263

# Example usage

264

print("Generating master seed...")

265

seed_b64 = generate_keypair_seed()

266

print(f"Seed (base64): {seed_b64}")

267

268

# Convert back to bytes

269

master_secret = base64.b64decode(seed_b64)

270

271

print("\nDeriving multiple keys...")

272

keys = derive_multiple_keys(master_secret, 3)

273

for name, key in keys.items():

274

print(f"{name}: {key[:8].hex()}...")

275

276

print("\nSecret sharing example...")

277

secret = b"This is a very secret message!"

278

shares = secure_key_splitting(secret, 3, 3)

279

print(f"Split secret into {len(shares)} shares")

280

281

# Reconstruct

282

reconstructed = reconstruct_secret(shares)

283

print(f"Reconstructed: {reconstructed}")

284

print(f"Match: {secret == reconstructed}")

285

```

286

287

### Secure Random Testing

288

289

```python

290

from oscrypto.util import rand_bytes

291

import collections

292

293

def test_randomness_quality(samples: int = 10000, byte_length: int = 16):

294

"""Basic statistical tests for random number quality."""

295

296

print(f"Testing randomness with {samples} samples of {byte_length} bytes each")

297

298

# Collect random samples

299

byte_counts = collections.defaultdict(int)

300

bit_counts = [0, 0] # [0-bits, 1-bits]

301

302

for _ in range(samples):

303

random_bytes = rand_bytes(byte_length)

304

305

# Count byte values

306

for byte_val in random_bytes:

307

byte_counts[byte_val] += 1

308

309

# Count bits

310

for byte_val in random_bytes:

311

for bit_pos in range(8):

312

bit_counts[(byte_val >> bit_pos) & 1] += 1

313

314

# Analyze results

315

total_bytes = samples * byte_length

316

total_bits = total_bytes * 8

317

318

print(f"\nBit distribution:")

319

print(f" 0-bits: {bit_counts[0]} ({bit_counts[0]/total_bits*100:.2f}%)")

320

print(f" 1-bits: {bit_counts[1]} ({bit_counts[1]/total_bits*100:.2f}%)")

321

print(f" Balance: {abs(bit_counts[0] - bit_counts[1])} difference")

322

323

# Check for repeated sequences

324

sequences = set()

325

duplicates = 0

326

327

for _ in range(1000):

328

seq = rand_bytes(16)

329

if seq in sequences:

330

duplicates += 1

331

sequences.add(seq)

332

333

print(f"\nSequence uniqueness (1000 samples):")

334

print(f" Duplicates: {duplicates}")

335

print(f" Unique: {1000 - duplicates}")

336

337

# Byte value distribution

338

expected_per_value = total_bytes / 256

339

max_deviation = max(abs(count - expected_per_value) for count in byte_counts.values())

340

341

print(f"\nByte value distribution:")

342

print(f" Expected per value: {expected_per_value:.1f}")

343

print(f" Max deviation: {max_deviation:.1f}")

344

345

# Run randomness tests

346

test_randomness_quality()

347

```