CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pycryptodome

PyCryptodome is a self-contained Python package of low-level cryptographic primitives

Pending
Overview
Eval results
Files

input-output-operations.mddocs/

Input/Output Operations

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.

Capabilities

PEM Encoding and Decoding

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

def encode(data, marker, passphrase=None, randfunc=None):
    """
    Encode binary data in PEM format.
    
    Parameters:
    - data (bytes): Binary data to encode
    - marker (str): PEM marker string (e.g., 'RSA PRIVATE KEY', 'CERTIFICATE')
    - passphrase (bytes/str): Optional password for encryption
    - randfunc (callable): Random function for encryption (default: get_random_bytes)
    
    Returns:
    bytes: PEM-encoded data with -----BEGIN/END----- headers
    """

def decode(pem_data, passphrase=None):
    """
    Decode PEM-formatted data.
    
    Parameters:
    - pem_data (bytes/str): PEM-encoded data with headers
    - passphrase (bytes/str): Password for encrypted PEM data
    
    Returns:
    tuple: (decoded_data, marker, encrypted)
    - decoded_data (bytes): Binary data
    - marker (str): PEM marker string
    - encrypted (bool): Whether data was encrypted
    
    Raises:
    ValueError: Invalid PEM format or incorrect passphrase
    """

PKCS#8 Private Key Format

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

def wrap(private_key, key_oid, passphrase=None, protection=None, prot_params=None, key_params=None, randfunc=None):
    """
    Wrap private key in PKCS#8 format.
    
    Parameters:
    - private_key (bytes): Private key data to wrap
    - key_oid (str): Object identifier for key algorithm
    - passphrase (bytes/str): Optional password for encryption
    - protection (str): Encryption algorithm ('PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC', 
                       'PBKDF2WithHMAC-SHA1AndAES128-CBC', 'PBKDF2WithHMAC-SHA1AndAES256-CBC',
                       'scryptAndAES128-CBC', 'scryptAndAES256-CBC')
    - prot_params (dict): Protection algorithm parameters
    - key_params (bytes): Optional algorithm parameters
    - randfunc (callable): Random function for encryption
    
    Returns:
    bytes: PKCS#8 wrapped private key (DER-encoded)
    """

def unwrap(p8_private_key, passphrase=None):
    """
    Unwrap PKCS#8 private key.
    
    Parameters:
    - p8_private_key (bytes): PKCS#8 wrapped private key (DER or PEM)
    - passphrase (bytes/str): Password for encrypted keys
    
    Returns:
    tuple: (key_data, key_oid, key_params)
    - key_data (bytes): Private key data
    - key_oid (str): Key algorithm OID
    - key_params (bytes): Optional algorithm parameters
    
    Raises:
    ValueError: Invalid PKCS#8 format or incorrect passphrase
    """

Usage Examples

PEM Operations

from Crypto.IO import PEM
from Crypto.PublicKey import RSA

# Generate RSA key for examples
key = RSA.generate(2048)
private_der = key.export_key('DER')

# Encode private key in PEM format (unencrypted)
pem_data = PEM.encode(private_der, "RSA PRIVATE KEY")
print(pem_data.decode())
# Output:
# -----BEGIN RSA PRIVATE KEY-----
# MIIEpAIBAAKCAQEA...
# -----END RSA PRIVATE KEY-----

# Encode with password protection
encrypted_pem = PEM.encode(private_der, "RSA PRIVATE KEY", passphrase="secret123")

# Decode PEM data
decoded_data, marker, was_encrypted = PEM.decode(pem_data)
print(f"Marker: {marker}, Encrypted: {was_encrypted}")

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

Custom PEM Markers

from Crypto.IO import PEM

# Custom data with custom marker
custom_data = b"Custom binary data for application"
pem_encoded = PEM.encode(custom_data, "CUSTOM DATA")

# Decode custom PEM
decoded, marker, encrypted = PEM.decode(pem_encoded)
assert decoded == custom_data
assert marker == "CUSTOM DATA"

PKCS#8 Operations

from Crypto.IO import PKCS8
from Crypto.PublicKey import RSA, ECC

# RSA private key in PKCS#8 format
rsa_key = RSA.generate(2048)
rsa_der = rsa_key.export_key('DER')

# Wrap RSA key in PKCS#8 (unencrypted)
pkcs8_data = PKCS8.wrap(rsa_der, "1.2.840.113549.1.1.1")  # RSA OID

# Wrap with AES-256 encryption
encrypted_pkcs8 = PKCS8.wrap(
    rsa_der, 
    "1.2.840.113549.1.1.1",
    passphrase="strong_password",
    protection="PBKDF2WithHMAC-SHA1AndAES256-CBC"
)

# Unwrap PKCS#8 data
key_data, key_oid, key_params = PKCS8.unwrap(pkcs8_data)
print(f"Key algorithm OID: {key_oid}")

# Unwrap encrypted PKCS#8
decrypted_key, oid, params = PKCS8.unwrap(encrypted_pkcs8, passphrase="strong_password")

ECC Keys in PKCS#8

from Crypto.IO import PKCS8
from Crypto.PublicKey import ECC

# Generate ECC key
ecc_key = ECC.generate(curve='P-256')
ecc_der = ecc_key.export_key(format='DER', use_pkcs8=False)

# Wrap ECC key in PKCS#8 with scrypt protection
pkcs8_ecc = PKCS8.wrap(
    ecc_der,
    "1.2.840.10045.2.1",  # EC public key OID
    passphrase="ecc_password",
    protection="scryptAndAES256-CBC"
)

# Unwrap ECC key
ecc_data, oid, params = PKCS8.unwrap(pkcs8_ecc, passphrase="ecc_password")

Integration with Key Objects

from Crypto.PublicKey import RSA
from Crypto.IO import PEM, PKCS8

# Generate and export key in different formats
key = RSA.generate(2048)

# Method 1: Direct PEM export (built-in)
pem_direct = key.export_key('PEM', passphrase="pass123")

# Method 2: Manual PEM encoding
der_data = key.export_key('DER')
pem_manual = PEM.encode(der_data, "RSA PRIVATE KEY", passphrase="pass123")

# Method 3: PKCS#8 format
pkcs8_wrapped = PKCS8.wrap(
    der_data,
    key.oid,  # RSA OID from key object
    passphrase="pass123",
    protection="PBKDF2WithHMAC-SHA1AndAES128-CBC"
)

# Convert PKCS#8 to PEM
pkcs8_pem = PEM.encode(pkcs8_wrapped, "PRIVATE KEY", passphrase="pass123")

Supported Encryption Algorithms

PEM Encryption

PEM encoding supports the following encryption algorithms for password protection:

  • DES-EDE3-CBC: Triple DES in CBC mode (legacy)
  • AES-128-CBC: AES-128 in CBC mode
  • AES-192-CBC: AES-192 in CBC mode
  • AES-256-CBC: AES-256 in CBC mode (recommended)

PKCS#8 Protection Schemes

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

# PBKDF2-based schemes
"PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC"    # Legacy
"PBKDF2WithHMAC-SHA1AndAES128-CBC"      # Standard
"PBKDF2WithHMAC-SHA1AndAES192-CBC"      # High security
"PBKDF2WithHMAC-SHA1AndAES256-CBC"      # Highest security

# scrypt-based schemes (more secure against hardware attacks)
"scryptAndAES128-CBC"                   # Modern standard
"scryptAndAES256-CBC"                   # Modern high security

Format Identification

PEM Format Detection

from Crypto.IO import PEM

def is_pem_format(data):
    """Check if data is in PEM format."""
    if isinstance(data, bytes):
        data = data.decode('ascii', errors='ignore')
    return data.strip().startswith('-----BEGIN') and '-----END' in data

# Example usage
pem_data = b"-----BEGIN RSA PRIVATE KEY-----\n..."
if is_pem_format(pem_data):
    decoded, marker, encrypted = PEM.decode(pem_data)

PKCS#8 vs Traditional Format

from Crypto.IO import PKCS8

def detect_private_key_format(der_data):
    """Detect if DER data is PKCS#8 or traditional format."""
    try:
        # Try PKCS#8 unwrap
        key_data, oid, params = PKCS8.unwrap(der_data)
        return "PKCS#8"
    except ValueError:
        # Probably traditional format (PKCS#1 for RSA, SEC1 for ECC, etc.)
        return "Traditional"

# Example usage
key = RSA.generate(2048)
traditional_der = key.export_key('DER')
pkcs8_der = PKCS8.wrap(traditional_der, key.oid)

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

Security Considerations

Password Protection

  • Use strong passwords for encrypted PEM/PKCS#8 data
  • Prefer AES-256 over legacy DES-based encryption
  • Consider scrypt-based protection for PKCS#8 (more secure against hardware attacks)

Key Storage Best Practices

  • Store private keys in PKCS#8 format with encryption
  • Use appropriate file permissions (600) for private key files
  • Consider hardware security modules (HSMs) for high-value keys
  • Implement proper key lifecycle management

Format Selection Guidelines

  • PEM: Human-readable, widely supported, good for configuration files
  • DER: Binary format, smaller size, good for protocols and embedded systems
  • PKCS#8: Standard format, algorithm-agnostic, recommended for private keys

Common OIDs for Key Algorithms

# RSA
RSA_OID = "1.2.840.113549.1.1.1"

# Elliptic Curve
EC_PUBLIC_KEY_OID = "1.2.840.10045.2.1"

# DSA  
DSA_OID = "1.2.840.10040.4.1"

# Ed25519
ED25519_OID = "1.3.101.112"

# Ed448
ED448_OID = "1.3.101.113"

Error Handling

  • ValueError: Invalid format, incorrect passphrase, or malformed data
  • TypeError: Incorrect parameter types
  • UnicodeDecodeError: Invalid PEM text encoding
  • KeyError: Missing required ASN.1 fields in PKCS#8 structures

Install with Tessl CLI

npx tessl i tessl/pypi-pycryptodome

docs

cryptographic-hashing.md

cryptographic-protocols.md

digital-signatures.md

index.md

input-output-operations.md

mathematical-primitives.md

public-key-cryptography.md

symmetric-encryption.md

utility-functions.md

tile.json