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

kdf.mddocs/

Key Derivation Functions

Password-based key derivation functions including PBKDF1, PBKDF2, and PKCS#12 KDF. These functions derive cryptographic keys from passwords using salt and iteration counts for security against brute-force attacks.

Capabilities

PBKDF2

Password-Based Key Derivation Function 2 (PBKDF2) as defined in RFC 2898, the most commonly used key derivation function.

def pbkdf2(hash_algorithm: str, password: bytes, salt: bytes, iterations: int, key_length: int) -> bytes:
    """
    Derive a key using PBKDF2.

    Parameters:
    - hash_algorithm: str - Hash algorithm ('sha1', 'sha224', 'sha256', 'sha384', 'sha512')
    - password: bytes - Password to derive key from
    - salt: bytes - Salt value (should be at least 8 bytes, preferably 16+)
    - iterations: int - Number of iterations (minimum 1000, recommended 10000+)
    - key_length: int - Length of derived key in bytes

    Returns:
    Derived key bytes
    """

def pbkdf2_iteration_calculator(hash_algorithm: str, key_length: int, target_ms: int = 100, quiet: bool = False) -> int:
    """
    Calculate PBKDF2 iterations for a target computation time.

    Parameters:
    - hash_algorithm: str - Hash algorithm to benchmark
    - key_length: int - Length of key to derive
    - target_ms: int - Target computation time in milliseconds
    - quiet: bool - Suppress progress output

    Returns:
    Number of iterations that achieves approximately target_ms computation time
    """

PBKDF1

Password-Based Key Derivation Function 1 (PBKDF1) as defined in RFC 2898. Less secure than PBKDF2, included for compatibility.

def pbkdf1(hash_algorithm: str, password: bytes, salt: bytes, iterations: int, key_length: int) -> bytes:
    """
    Derive a key using PBKDF1 (legacy, less secure than PBKDF2).

    Parameters:
    - hash_algorithm: str - Hash algorithm ('sha1', 'md5')
    - password: bytes - Password to derive key from
    - salt: bytes - Salt value (8 bytes)
    - iterations: int - Number of iterations
    - key_length: int - Length of derived key (limited by hash output size)

    Returns:
    Derived key bytes

    Note:
    PBKDF1 is deprecated. Use PBKDF2 for new applications.
    """

PKCS#12 KDF

PKCS#12 key derivation function used specifically for PKCS#12 files and some legacy applications.

def pkcs12_kdf(hash_algorithm: str, password: bytes, salt: bytes, iterations: int, key_length: int, id_: int) -> bytes:
    """
    Derive a key using PKCS#12 KDF.

    Parameters:
    - hash_algorithm: str - Hash algorithm ('sha1', 'sha224', 'sha256', 'sha384', 'sha512')
    - password: bytes - Password to derive key from
    - salt: bytes - Salt value
    - iterations: int - Number of iterations
    - key_length: int - Length of derived key in bytes
    - id_: int - Purpose ID (1=key material, 2=IV, 3=MAC key)

    Returns:
    Derived key bytes
    """

Usage Examples

PBKDF2 Key Derivation

from oscrypto.kdf import pbkdf2, pbkdf2_iteration_calculator
from oscrypto.util import rand_bytes
import os

# Generate secure random salt
salt = rand_bytes(16)
password = b"user_password_123"

# Calculate appropriate iteration count for ~100ms computation time
iterations = pbkdf2_iteration_calculator('sha256', 32, target_ms=100)
print(f"Using {iterations} iterations for ~100ms computation time")

# Derive AES-256 key (32 bytes)
key = pbkdf2('sha256', password, salt, iterations, 32)

print(f"Derived {len(key)} byte key")
print(f"Key: {key.hex()}")

Secure Password Storage

from oscrypto.kdf import pbkdf2
from oscrypto.util import rand_bytes, constant_compare
import hashlib

def hash_password(password: str) -> tuple:
    """Hash a password securely for storage."""
    # Convert password to bytes
    password_bytes = password.encode('utf-8')
    
    # Generate random salt
    salt = rand_bytes(16)
    
    # Use strong iteration count
    iterations = 100000
    
    # Derive key and hash it for storage
    key = pbkdf2('sha256', password_bytes, salt, iterations, 32)
    
    return salt, iterations, key

def verify_password(password: str, stored_salt: bytes, stored_iterations: int, stored_key: bytes) -> bool:
    """Verify a password against stored hash."""
    password_bytes = password.encode('utf-8')
    
    # Derive key with same parameters
    derived_key = pbkdf2('sha256', password_bytes, stored_salt, stored_iterations, 32)
    
    # Use constant-time comparison
    return constant_compare(derived_key, stored_key)

# Example usage
password = "my_secure_password"

# Store password
salt, iterations, key = hash_password(password)
print(f"Stored salt: {salt.hex()}")
print(f"Iterations: {iterations}")

# Verify password
is_valid = verify_password(password, salt, iterations, key)
print(f"Password valid: {is_valid}")

# Wrong password
is_valid = verify_password("wrong_password", salt, iterations, key)
print(f"Wrong password valid: {is_valid}")

Key Derivation for Encryption

from oscrypto.kdf import pbkdf2
from oscrypto.symmetric import aes_cbc_pkcs7_encrypt, aes_cbc_pkcs7_decrypt
from oscrypto.util import rand_bytes

def encrypt_with_password(data: bytes, password: str) -> tuple:
    """Encrypt data using password-derived key."""
    # Convert password to bytes
    password_bytes = password.encode('utf-8')
    
    # Generate random salt for key derivation
    salt = rand_bytes(16)
    
    # Derive AES-256 key
    key = pbkdf2('sha256', password_bytes, salt, 100000, 32)
    
    # Encrypt data
    ciphertext = aes_cbc_pkcs7_encrypt(key, data)
    
    return salt, ciphertext

def decrypt_with_password(salt: bytes, ciphertext: bytes, password: str) -> bytes:
    """Decrypt data using password-derived key."""
    password_bytes = password.encode('utf-8')
    
    # Derive the same key
    key = pbkdf2('sha256', password_bytes, salt, 100000, 32)
    
    # Decrypt data
    return aes_cbc_pkcs7_decrypt(key, ciphertext)

# Example usage
plaintext = b"Secret document contents"
password = "encryption_password_123"

# Encrypt
salt, ciphertext = encrypt_with_password(plaintext, password)
print(f"Encrypted {len(plaintext)} bytes to {len(ciphertext)} bytes")

# Decrypt
decrypted = decrypt_with_password(salt, ciphertext, password)
print(f"Decrypted: {decrypted}")
assert decrypted == plaintext

Multiple Hash Algorithms

from oscrypto.kdf import pbkdf2
from oscrypto.util import rand_bytes

password = b"test_password"
salt = rand_bytes(16)
iterations = 10000
key_length = 32

# Test different hash algorithms
algorithms = ['sha1', 'sha256', 'sha384', 'sha512']

for algorithm in algorithms:
    key = pbkdf2(algorithm, password, salt, iterations, key_length)
    print(f"{algorithm.upper()}: {key[:8].hex()}...")

Iteration Count Tuning

from oscrypto.kdf import pbkdf2_iteration_calculator
import time

# Test different target computation times
targets = [50, 100, 200, 500]  # milliseconds

for target_ms in targets:
    iterations = pbkdf2_iteration_calculator('sha256', 32, target_ms, quiet=True)
    
    # Verify actual timing
    start = time.time()
    pbkdf2('sha256', b'test', b'salt1234', iterations, 32)
    actual_ms = (time.time() - start) * 1000
    
    print(f"Target: {target_ms}ms, Iterations: {iterations}, Actual: {actual_ms:.1f}ms")

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