or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cryptographic-hashing.mdcryptographic-protocols.mddigital-signatures.mdindex.mdinput-output-operations.mdmathematical-primitives.mdpublic-key-cryptography.mdsymmetric-encryption.mdutility-functions.md

input-output-operations.mddocs/

0

# Input/Output Operations

1

2

Utilities for encoding, decoding, and serializing cryptographic objects in standard formats. Provides support for PEM (Privacy-Enhanced Mail) and PKCS#8 formats commonly used for key storage and exchange.

3

4

## Capabilities

5

6

### PEM Encoding and Decoding

7

8

Privacy-Enhanced Mail (PEM) format provides ASCII-armored encoding of binary cryptographic data with clear text headers and optional encryption.

9

10

```python { .api }

11

def encode(data, marker, passphrase=None, randfunc=None):

12

"""

13

Encode binary data in PEM format.

14

15

Parameters:

16

- data (bytes): Binary data to encode

17

- marker (str): PEM marker string (e.g., 'RSA PRIVATE KEY', 'CERTIFICATE')

18

- passphrase (bytes/str): Optional password for encryption

19

- randfunc (callable): Random function for encryption (default: get_random_bytes)

20

21

Returns:

22

bytes: PEM-encoded data with -----BEGIN/END----- headers

23

"""

24

25

def decode(pem_data, passphrase=None):

26

"""

27

Decode PEM-formatted data.

28

29

Parameters:

30

- pem_data (bytes/str): PEM-encoded data with headers

31

- passphrase (bytes/str): Password for encrypted PEM data

32

33

Returns:

34

tuple: (decoded_data, marker, encrypted)

35

- decoded_data (bytes): Binary data

36

- marker (str): PEM marker string

37

- encrypted (bool): Whether data was encrypted

38

39

Raises:

40

ValueError: Invalid PEM format or incorrect passphrase

41

"""

42

```

43

44

### PKCS#8 Private Key Format

45

46

PKCS#8 (Private-Key Information Syntax Standard) provides a format for storing private key information with optional encryption and algorithm identification.

47

48

```python { .api }

49

def wrap(private_key, key_oid, passphrase=None, protection=None, prot_params=None, key_params=None, randfunc=None):

50

"""

51

Wrap private key in PKCS#8 format.

52

53

Parameters:

54

- private_key (bytes): Private key data to wrap

55

- key_oid (str): Object identifier for key algorithm

56

- passphrase (bytes/str): Optional password for encryption

57

- protection (str): Encryption algorithm ('PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC',

58

'PBKDF2WithHMAC-SHA1AndAES128-CBC', 'PBKDF2WithHMAC-SHA1AndAES256-CBC',

59

'scryptAndAES128-CBC', 'scryptAndAES256-CBC')

60

- prot_params (dict): Protection algorithm parameters

61

- key_params (bytes): Optional algorithm parameters

62

- randfunc (callable): Random function for encryption

63

64

Returns:

65

bytes: PKCS#8 wrapped private key (DER-encoded)

66

"""

67

68

def unwrap(p8_private_key, passphrase=None):

69

"""

70

Unwrap PKCS#8 private key.

71

72

Parameters:

73

- p8_private_key (bytes): PKCS#8 wrapped private key (DER or PEM)

74

- passphrase (bytes/str): Password for encrypted keys

75

76

Returns:

77

tuple: (key_data, key_oid, key_params)

78

- key_data (bytes): Private key data

79

- key_oid (str): Key algorithm OID

80

- key_params (bytes): Optional algorithm parameters

81

82

Raises:

83

ValueError: Invalid PKCS#8 format or incorrect passphrase

84

"""

85

```

86

87

## Usage Examples

88

89

### PEM Operations

90

```python

91

from Crypto.IO import PEM

92

from Crypto.PublicKey import RSA

93

94

# Generate RSA key for examples

95

key = RSA.generate(2048)

96

private_der = key.export_key('DER')

97

98

# Encode private key in PEM format (unencrypted)

99

pem_data = PEM.encode(private_der, "RSA PRIVATE KEY")

100

print(pem_data.decode())

101

# Output:

102

# -----BEGIN RSA PRIVATE KEY-----

103

# MIIEpAIBAAKCAQEA...

104

# -----END RSA PRIVATE KEY-----

105

106

# Encode with password protection

107

encrypted_pem = PEM.encode(private_der, "RSA PRIVATE KEY", passphrase="secret123")

108

109

# Decode PEM data

110

decoded_data, marker, was_encrypted = PEM.decode(pem_data)

111

print(f"Marker: {marker}, Encrypted: {was_encrypted}")

112

113

# Decode encrypted PEM

114

decrypted_data, marker, was_encrypted = PEM.decode(encrypted_pem, passphrase="secret123")

115

```

116

117

### Custom PEM Markers

118

```python

119

from Crypto.IO import PEM

120

121

# Custom data with custom marker

122

custom_data = b"Custom binary data for application"

123

pem_encoded = PEM.encode(custom_data, "CUSTOM DATA")

124

125

# Decode custom PEM

126

decoded, marker, encrypted = PEM.decode(pem_encoded)

127

assert decoded == custom_data

128

assert marker == "CUSTOM DATA"

129

```

130

131

### PKCS#8 Operations

132

```python

133

from Crypto.IO import PKCS8

134

from Crypto.PublicKey import RSA, ECC

135

136

# RSA private key in PKCS#8 format

137

rsa_key = RSA.generate(2048)

138

rsa_der = rsa_key.export_key('DER')

139

140

# Wrap RSA key in PKCS#8 (unencrypted)

141

pkcs8_data = PKCS8.wrap(rsa_der, "1.2.840.113549.1.1.1") # RSA OID

142

143

# Wrap with AES-256 encryption

144

encrypted_pkcs8 = PKCS8.wrap(

145

rsa_der,

146

"1.2.840.113549.1.1.1",

147

passphrase="strong_password",

148

protection="PBKDF2WithHMAC-SHA1AndAES256-CBC"

149

)

150

151

# Unwrap PKCS#8 data

152

key_data, key_oid, key_params = PKCS8.unwrap(pkcs8_data)

153

print(f"Key algorithm OID: {key_oid}")

154

155

# Unwrap encrypted PKCS#8

156

decrypted_key, oid, params = PKCS8.unwrap(encrypted_pkcs8, passphrase="strong_password")

157

```

158

159

### ECC Keys in PKCS#8

160

```python

161

from Crypto.IO import PKCS8

162

from Crypto.PublicKey import ECC

163

164

# Generate ECC key

165

ecc_key = ECC.generate(curve='P-256')

166

ecc_der = ecc_key.export_key(format='DER', use_pkcs8=False)

167

168

# Wrap ECC key in PKCS#8 with scrypt protection

169

pkcs8_ecc = PKCS8.wrap(

170

ecc_der,

171

"1.2.840.10045.2.1", # EC public key OID

172

passphrase="ecc_password",

173

protection="scryptAndAES256-CBC"

174

)

175

176

# Unwrap ECC key

177

ecc_data, oid, params = PKCS8.unwrap(pkcs8_ecc, passphrase="ecc_password")

178

```

179

180

### Integration with Key Objects

181

```python

182

from Crypto.PublicKey import RSA

183

from Crypto.IO import PEM, PKCS8

184

185

# Generate and export key in different formats

186

key = RSA.generate(2048)

187

188

# Method 1: Direct PEM export (built-in)

189

pem_direct = key.export_key('PEM', passphrase="pass123")

190

191

# Method 2: Manual PEM encoding

192

der_data = key.export_key('DER')

193

pem_manual = PEM.encode(der_data, "RSA PRIVATE KEY", passphrase="pass123")

194

195

# Method 3: PKCS#8 format

196

pkcs8_wrapped = PKCS8.wrap(

197

der_data,

198

key.oid, # RSA OID from key object

199

passphrase="pass123",

200

protection="PBKDF2WithHMAC-SHA1AndAES128-CBC"

201

)

202

203

# Convert PKCS#8 to PEM

204

pkcs8_pem = PEM.encode(pkcs8_wrapped, "PRIVATE KEY", passphrase="pass123")

205

```

206

207

## Supported Encryption Algorithms

208

209

### PEM Encryption

210

PEM encoding supports the following encryption algorithms for password protection:

211

- **DES-EDE3-CBC**: Triple DES in CBC mode (legacy)

212

- **AES-128-CBC**: AES-128 in CBC mode

213

- **AES-192-CBC**: AES-192 in CBC mode

214

- **AES-256-CBC**: AES-256 in CBC mode (recommended)

215

216

### PKCS#8 Protection Schemes

217

PKCS#8 supports various protection schemes combining key derivation with encryption:

218

219

```python

220

# PBKDF2-based schemes

221

"PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC" # Legacy

222

"PBKDF2WithHMAC-SHA1AndAES128-CBC" # Standard

223

"PBKDF2WithHMAC-SHA1AndAES192-CBC" # High security

224

"PBKDF2WithHMAC-SHA1AndAES256-CBC" # Highest security

225

226

# scrypt-based schemes (more secure against hardware attacks)

227

"scryptAndAES128-CBC" # Modern standard

228

"scryptAndAES256-CBC" # Modern high security

229

```

230

231

## Format Identification

232

233

### PEM Format Detection

234

```python

235

from Crypto.IO import PEM

236

237

def is_pem_format(data):

238

"""Check if data is in PEM format."""

239

if isinstance(data, bytes):

240

data = data.decode('ascii', errors='ignore')

241

return data.strip().startswith('-----BEGIN') and '-----END' in data

242

243

# Example usage

244

pem_data = b"-----BEGIN RSA PRIVATE KEY-----\n..."

245

if is_pem_format(pem_data):

246

decoded, marker, encrypted = PEM.decode(pem_data)

247

```

248

249

### PKCS#8 vs Traditional Format

250

```python

251

from Crypto.IO import PKCS8

252

253

def detect_private_key_format(der_data):

254

"""Detect if DER data is PKCS#8 or traditional format."""

255

try:

256

# Try PKCS#8 unwrap

257

key_data, oid, params = PKCS8.unwrap(der_data)

258

return "PKCS#8"

259

except ValueError:

260

# Probably traditional format (PKCS#1 for RSA, SEC1 for ECC, etc.)

261

return "Traditional"

262

263

# Example usage

264

key = RSA.generate(2048)

265

traditional_der = key.export_key('DER')

266

pkcs8_der = PKCS8.wrap(traditional_der, key.oid)

267

268

print(detect_private_key_format(traditional_der)) # "Traditional"

269

print(detect_private_key_format(pkcs8_der)) # "PKCS#8"

270

```

271

272

## Security Considerations

273

274

### Password Protection

275

- Use strong passwords for encrypted PEM/PKCS#8 data

276

- Prefer AES-256 over legacy DES-based encryption

277

- Consider scrypt-based protection for PKCS#8 (more secure against hardware attacks)

278

279

### Key Storage Best Practices

280

- Store private keys in PKCS#8 format with encryption

281

- Use appropriate file permissions (600) for private key files

282

- Consider hardware security modules (HSMs) for high-value keys

283

- Implement proper key lifecycle management

284

285

### Format Selection Guidelines

286

- **PEM**: Human-readable, widely supported, good for configuration files

287

- **DER**: Binary format, smaller size, good for protocols and embedded systems

288

- **PKCS#8**: Standard format, algorithm-agnostic, recommended for private keys

289

290

## Common OIDs for Key Algorithms

291

292

```python

293

# RSA

294

RSA_OID = "1.2.840.113549.1.1.1"

295

296

# Elliptic Curve

297

EC_PUBLIC_KEY_OID = "1.2.840.10045.2.1"

298

299

# DSA

300

DSA_OID = "1.2.840.10040.4.1"

301

302

# Ed25519

303

ED25519_OID = "1.3.101.112"

304

305

# Ed448

306

ED448_OID = "1.3.101.113"

307

```

308

309

## Error Handling

310

311

- `ValueError`: Invalid format, incorrect passphrase, or malformed data

312

- `TypeError`: Incorrect parameter types

313

- `UnicodeDecodeError`: Invalid PEM text encoding

314

- `KeyError`: Missing required ASN.1 fields in PKCS#8 structures