CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-oscrypto

Cross-platform cryptographic library providing TLS sockets, asymmetric/symmetric encryption, and key operations using OS-native crypto libraries

Pending
Overview
Eval results
Files

keys.mddocs/

Key Management

Parsing and handling of cryptographic keys and certificates from various formats including DER, PEM, PKCS#8, and PKCS#12. These functions provide format detection and conversion capabilities for interoperability with different cryptographic systems.

Capabilities

Certificate Parsing

Parse X.509 certificates from DER or PEM format data.

def parse_certificate(data: bytes) -> Certificate:
    """
    Parse an X.509 certificate from DER or PEM data.

    Parameters:
    - data: bytes - Certificate data in DER or PEM format

    Returns:
    Certificate object with parsed certificate information

    Raises:
    ValueError if data is not a valid certificate
    """

Private Key Parsing

Parse private keys from various formats including PKCS#8, PKCS#1, and OpenSSL formats.

def parse_private(data: bytes) -> PrivateKey:
    """
    Parse a private key from DER or PEM encoded data.

    Parameters:
    - data: bytes - Private key data in supported formats:
                   - PKCS#8 (encrypted or unencrypted)
                   - PKCS#1 RSA private key
                   - OpenSSL traditional format
                   - SEC1 EC private key

    Returns:
    PrivateKey object for the parsed key

    Raises:
    ValueError if data is not a valid private key
    AsymmetricKeyError if key format is unsupported
    """

Public Key Parsing

Parse public keys from DER or PEM format data.

def parse_public(data: bytes) -> PublicKey:
    """
    Parse a public key from DER or PEM encoded data.

    Parameters:
    - data: bytes - Public key data in supported formats:
                   - X.509 SubjectPublicKeyInfo
                   - PKCS#1 RSA public key
                   - RFC 3279 formats

    Returns:
    PublicKey object for the parsed key

    Raises:
    ValueError if data is not a valid public key
    AsymmetricKeyError if key format is unsupported
    """

PKCS#12 Bundle Parsing

Parse PKCS#12 bundles containing certificates, private keys, and certificate chains.

def parse_pkcs12(data: bytes, password: bytes = None) -> Tuple[Certificate, PrivateKey, List[Certificate]]:
    """
    Parse a PKCS#12 bundle containing certificate and private key.

    Parameters:
    - data: bytes - PKCS#12 bundle data
    - password: bytes - Password for encrypted bundle (None for unencrypted)

    Returns:
    Tuple of (end_entity_certificate, private_key, intermediate_certificates)

    Raises:
    ValueError if data is not a valid PKCS#12 bundle
    AsymmetricKeyError if password is incorrect or bundle is corrupted
    """

Usage Examples

Certificate File Parsing

from oscrypto.keys import parse_certificate
import os

def load_certificate_file(file_path: str):
    """Load and parse a certificate file."""
    with open(file_path, 'rb') as f:
        cert_data = f.read()
    
    try:
        certificate = parse_certificate(cert_data)
        
        print(f"Certificate loaded from: {file_path}")
        print(f"Subject: {certificate.subject}")
        print(f"Issuer: {certificate.issuer}")
        print(f"Serial Number: {certificate.serial_number}")
        print(f"Valid From: {certificate.not_valid_before}")
        print(f"Valid Until: {certificate.not_valid_after}")
        print(f"Key Algorithm: {certificate.public_key.algorithm}")
        
        if hasattr(certificate.public_key, 'bit_size'):
            print(f"Key Size: {certificate.public_key.bit_size} bits")
        
        return certificate
        
    except ValueError as e:
        print(f"Error parsing certificate: {e}")
        return None

# Example usage
cert_files = [
    'server.crt',
    'ca-certificate.pem',
    'client.der'
]

for cert_file in cert_files:
    if os.path.exists(cert_file):
        load_certificate_file(cert_file)
        print("-" * 50)

Private Key File Parsing

from oscrypto.keys import parse_private
from oscrypto.errors import AsymmetricKeyError
import getpass

def load_private_key_file(file_path: str, password: str = None):
    """Load and parse a private key file with optional password."""
    with open(file_path, 'rb') as f:
        key_data = f.read()
    
    # Convert password to bytes if provided
    password_bytes = password.encode('utf-8') if password else None
    
    try:
        # First try without password
        private_key = parse_private(key_data)
        print(f"Private key loaded from: {file_path} (unencrypted)")
        
    except (ValueError, AsymmetricKeyError) as e:
        if "password" in str(e).lower() or "encrypted" in str(e).lower():
            # Key is encrypted, prompt for password if not provided
            if not password_bytes:
                password = getpass.getpass("Enter private key password: ")
                password_bytes = password.encode('utf-8')
            
            try:
                from oscrypto.asymmetric import load_private_key
                private_key = load_private_key(key_data, password_bytes)
                print(f"Private key loaded from: {file_path} (encrypted)")
            except Exception as e2:
                print(f"Error loading encrypted private key: {e2}")
                return None
        else:
            print(f"Error parsing private key: {e}")
            return None
    
    # Display key information
    print(f"Algorithm: {private_key.algorithm}")
    if hasattr(private_key, 'bit_size'):
        print(f"Key Size: {private_key.bit_size} bits")
    if hasattr(private_key, 'curve'):
        print(f"Curve: {private_key.curve}")
    
    return private_key

# Example usage
key_files = [
    'private_key.pem',
    'encrypted_key.p8',
    'rsa_key.der'
]

for key_file in key_files:
    if os.path.exists(key_file):
        load_private_key_file(key_file)
        print("-" * 50)

PKCS#12 Bundle Processing

from oscrypto.keys import parse_pkcs12
from oscrypto.errors import AsymmetricKeyError
import getpass

def process_pkcs12_bundle(file_path: str, password: str = None):
    """Process a PKCS#12 bundle file."""
    with open(file_path, 'rb') as f:
        p12_data = f.read()
    
    # Prompt for password if not provided
    if not password:
        password = getpass.getpass(f"Enter password for {file_path}: ")
    
    password_bytes = password.encode('utf-8') if password else None
    
    try:
        certificate, private_key, intermediates = parse_pkcs12(p12_data, password_bytes)
        
        print(f"PKCS#12 bundle processed: {file_path}")
        print(f"End-entity certificate: {certificate.subject}")
        print(f"Private key algorithm: {private_key.algorithm}")
        print(f"Intermediate certificates: {len(intermediates)}")
        
        # Display certificate chain
        print("\nCertificate Chain:")
        print(f"1. {certificate.subject} (end-entity)")
        
        for i, intermediate in enumerate(intermediates, 2):
            print(f"{i}. {intermediate.subject} (intermediate)")
        
        # Verify private key matches certificate
        cert_public_key = certificate.public_key
        private_public_key = private_key.public_key
        
        # Simple check - compare key algorithms and sizes
        keys_match = (cert_public_key.algorithm == private_public_key.algorithm)
        if hasattr(cert_public_key, 'bit_size') and hasattr(private_public_key, 'bit_size'):
            keys_match = keys_match and (cert_public_key.bit_size == private_public_key.bit_size)
        
        print(f"\nPrivate key matches certificate: {keys_match}")
        
        return certificate, private_key, intermediates
        
    except AsymmetricKeyError as e:
        print(f"Error processing PKCS#12 bundle: {e}")
        return None, None, []

# Example usage
p12_files = [
    'client.p12',
    'server.pfx',
    'identity.p12'
]

for p12_file in p12_files:
    if os.path.exists(p12_file):
        process_pkcs12_bundle(p12_file)
        print("=" * 60)

Multi-Format Key Detection

from oscrypto.keys import parse_certificate, parse_private, parse_public, parse_pkcs12
from oscrypto.errors import AsymmetricKeyError

def identify_crypto_file(file_path: str):
    """Identify the type and contents of a cryptographic file."""
    with open(file_path, 'rb') as f:
        data = f.read()
    
    print(f"Analyzing file: {file_path}")
    print(f"File size: {len(data)} bytes")
    
    # Check if it's text (PEM) or binary (DER/P12)
    is_text = all(byte < 128 for byte in data[:100])
    print(f"Format: {'PEM/Text' if is_text else 'Binary (DER/P12)'}")
    
    if is_text:
        # Look for PEM markers
        data_str = data.decode('utf-8', errors='ignore')
        pem_types = []
        
        if '-----BEGIN CERTIFICATE-----' in data_str:
            pem_types.append('Certificate')
        if '-----BEGIN PRIVATE KEY-----' in data_str:
            pem_types.append('PKCS#8 Private Key')
        if '-----BEGIN RSA PRIVATE KEY-----' in data_str:
            pem_types.append('PKCS#1 RSA Private Key')
        if '-----BEGIN EC PRIVATE KEY-----' in data_str:
            pem_types.append('SEC1 EC Private Key')
        if '-----BEGIN PUBLIC KEY-----' in data_str:
            pem_types.append('Public Key')
        
        if pem_types:
            print(f"PEM content types: {', '.join(pem_types)}")
    
    # Try parsing as different types
    results = {}
    
    # Try certificate
    try:
        cert = parse_certificate(data)
        results['certificate'] = f"X.509 Certificate - Subject: {cert.subject}"
    except:
        pass
    
    # Try private key
    try:
        key = parse_private(data)
        results['private_key'] = f"Private Key - Algorithm: {key.algorithm}"
        if hasattr(key, 'bit_size'):
            results['private_key'] += f", {key.bit_size} bits"
    except:
        pass
    
    # Try public key
    try:
        pub_key = parse_public(data)
        results['public_key'] = f"Public Key - Algorithm: {pub_key.algorithm}"
        if hasattr(pub_key, 'bit_size'):
            results['public_key'] += f", {pub_key.bit_size} bits"
    except:
        pass
    
    # Try PKCS#12 (typically requires password, so this might fail)
    try:
        cert, key, intermediates = parse_pkcs12(data, None)
        results['pkcs12'] = f"PKCS#12 Bundle - Cert: {cert.subject}, Key: {key.algorithm}, Intermediates: {len(intermediates)}"
    except:
        # Try with empty password
        try:
            cert, key, intermediates = parse_pkcs12(data, b'')
            results['pkcs12'] = f"PKCS#12 Bundle (empty password) - Cert: {cert.subject}, Key: {key.algorithm}, Intermediates: {len(intermediates)}"
        except:
            pass
    
    if results:
        print("Successful parses:")
        for parse_type, description in results.items():
            print(f"  {parse_type}: {description}")
    else:
        print("Could not parse as any recognized cryptographic format")
    
    print()

# Example usage - analyze all crypto files in directory
import glob

crypto_extensions = ['*.pem', '*.crt', '*.cer', '*.der', '*.key', '*.p8', '*.p12', '*.pfx']
crypto_files = []

for extension in crypto_extensions:
    crypto_files.extend(glob.glob(extension))

for crypto_file in crypto_files:
    identify_crypto_file(crypto_file)

Key Conversion Utility

from oscrypto.keys import parse_private, parse_certificate
from oscrypto.asymmetric import dump_private_key, dump_certificate, dump_public_key
import base64

def convert_key_format(input_file: str, output_file: str, output_format: str = 'pem'):
    """Convert cryptographic files between formats."""
    
    with open(input_file, 'rb') as f:
        input_data = f.read()
    
    try:
        # Try parsing as private key
        private_key = parse_private(input_data)
        
        # Export in requested format
        if output_format.lower() == 'der':
            output_data = dump_private_key(private_key)
        else:  # PEM
            der_data = dump_private_key(private_key)
            pem_data = base64.b64encode(der_data).decode('ascii')
            # Add PEM wrapper
            output_data = (
                "-----BEGIN PRIVATE KEY-----\n" +
                '\n'.join(pem_data[i:i+64] for i in range(0, len(pem_data), 64)) +
                "\n-----END PRIVATE KEY-----\n"
            ).encode('ascii')
        
        with open(output_file, 'wb') as f:
            f.write(output_data)
        
        print(f"Converted private key from {input_file} to {output_file} ({output_format.upper()})")
        return
        
    except:
        pass
    
    try:
        # Try parsing as certificate
        certificate = parse_certificate(input_data)
        
        # Export in requested format
        if output_format.lower() == 'der':
            output_data = dump_certificate(certificate)
        else:  # PEM
            der_data = dump_certificate(certificate)
            pem_data = base64.b64encode(der_data).decode('ascii')
            # Add PEM wrapper
            output_data = (
                "-----BEGIN CERTIFICATE-----\n" +
                '\n'.join(pem_data[i:i+64] for i in range(0, len(pem_data), 64)) +
                "\n-----END CERTIFICATE-----\n"
            ).encode('ascii')
        
        with open(output_file, 'wb') as f:
            f.write(output_data)
        
        print(f"Converted certificate from {input_file} to {output_file} ({output_format.upper()})")
        return
        
    except Exception as e:
        print(f"Error converting {input_file}: {e}")

# Example usage
conversions = [
    ('server.crt', 'server.der', 'der'),
    ('client.der', 'client.pem', 'pem'),
    ('private.p8', 'private.pem', 'pem')
]

for input_file, output_file, format_type in conversions:
    if os.path.exists(input_file):
        convert_key_format(input_file, output_file, format_type)

Install with Tessl CLI

npx tessl i tessl/pypi-oscrypto

docs

asymmetric.md

backend.md

index.md

kdf.md

keys.md

symmetric.md

tls.md

trust-store.md

utility.md

tile.json