KeyLock Class

Overview

The KeyLock class encapsulates the ciphertext of a public-key encrypted symmetric block cipher key and its pertinent metadata, such as the public key used during encryption. Key locks are used in hybrid encryption schemes where a symmetric cipher encrypts the data and a public-key cipher encrypts the symmetric key.

Package: keychain.core.key_lock

from keychain.core.key_lock import KeyLock

Class Definition

class KeyLock(SerializableObject):
    """A key lock is the encapsulation of ciphertext of an encrypted symmetric key."""

Constructor

def __init__(
    self,
    serialized_string: Optional[bytes] = None,
    serialization_format: SerializationFormat = SerializationFormat.PROTOBUF,
    c_pointer: Optional[ctypes.c_void_p] = None,
) -> None

Initialize a KeyLock object.

Parameters:

  • serialized_string (bytes, optional) - Serialized key lock bytes to deserialize

  • serialization_format (SerializationFormat, optional) - Format of the serialized data (defaults to PROTOBUF)

  • c_pointer (ctypes.c_void_p, optional) - Existing C pointer to wrap

Example:

from keychain.core.key_lock import KeyLock
from keychain.constants import SerializationFormat

# Create from serialized data
key_lock_bytes = b"..."  # Previously serialized key lock
key_lock = KeyLock(
    serialized_string=key_lock_bytes,
    serialization_format=SerializationFormat.PROTOBUF
)

# Create from existing C pointer (typically from library functions)
key_lock = KeyLock(c_pointer=existing_pointer)

Class Methods

from_copy()

@classmethod
def from_copy(cls, other: "KeyLock") -> "KeyLock"

Create a copy of a key lock.

Parameters:

  • other (KeyLock) - The key lock to copy

Returns: A new KeyLock instance that is a deep copy

Example:

original_key_lock = get_key_lock()
copied_key_lock = KeyLock.from_copy(original_key_lock)

Instance Methods

copy()

def copy(self) -> "KeyLock"

Create a deep copy of this key lock.

Returns: A new KeyLock instance that is a deep copy

serialize()

def serialize(self) -> bytes

Serialize the key lock.

Returns: Bytes serialization of the key lock in protobuf format

Example:

key_lock = get_key_lock()
serialized_data = key_lock.serialize()
# Can be stored or transmitted and later reconstructed
restored_key_lock = KeyLock(serialized_data)

data_type()

def data_type(self) -> DataType

Get the data type of the key lock.

Returns: DataType.KEY_LOCK

Properties

Encrypted Key Properties

cipher_text

@property
def cipher_text(self) -> str

Get the encrypted symmetric key.

Returns: The raw binary ciphertext of the encrypted symmetric key (as string)

Example:

key_lock = get_key_lock()
encrypted_key = key_lock.cipher_text
print(f"Encrypted key length: {len(encrypted_key)} bytes")

Public Key Properties

public_key

@property
def public_key(self) -> str

Get the public key used for encryption.

Returns: The public key in hexadecimal format

Example:

key_lock = get_key_lock()
pub_key = key_lock.public_key
print(f"Public key: {pub_key[:32]}...")  # First 32 characters

public_key_hash

@property
def public_key_hash(self) -> str

Get a non-cryptographic hash of the public key.

Returns: A non-cryptographic hash of the public key in binary format

Example:

key_lock = get_key_lock()
key_hash = key_lock.public_key_hash
print(f"Public key hash: {key_hash}")

Integrity Properties

ciphertext_hash

@property
def ciphertext_hash(self) -> str

Get a cryptographic hash of the ciphertext.

Returns: A cryptographic hash of the ciphertext for integrity verification

Example:

key_lock = get_key_lock()
cipher_hash = key_lock.ciphertext_hash
print(f"Ciphertext hash: {cipher_hash}")

Algorithm Properties

algorithm

@property
def algorithm(self) -> EncryptionScheme

Get the public-key encryption algorithm used to encrypt the symmetric key.

Returns: The EncryptionScheme used for key encryption

Example:

key_lock = get_key_lock()
algorithm = key_lock.algorithm
print(f"Encryption algorithm: {algorithm.name}")

Version Properties

version

@property
def version(self) -> Version

Get the serialized-data format version.

Returns: The Version of the data format used

Example:

key_lock = get_key_lock()
version = key_lock.version
print(f"Data format version: {version.name}")

Comparison Methods

eq()

def __eq__(self, other: object) -> bool

Compare key locks for equality.

Parameters:

  • other (KeyLock) - The other key lock to compare

Returns: True if key locks are equal, False otherwise

Example:

key_lock1 = get_key_lock()
key_lock2 = key_lock1.copy()

if key_lock1 == key_lock2:
    print("Key locks are identical")

String Representation

str()

def __str__(self) -> str

Return string representation of the key lock.

Returns: Hex string of serialized data

repr()

def __repr__(self) -> str

Return detailed string representation.

Returns: Detailed representation showing class and serialized form

Example: Working with Key Locks

from keychain.core.key_lock import KeyLock
from keychain.constants import EncryptionScheme

def analyze_key_lock(key_lock: KeyLock):
    """Analyze a key lock and display its properties."""

    print("=== Key Lock Analysis ===")

    # Basic properties
    print(f"Data type: {key_lock.data_type().name}")
    print(f"Version: {key_lock.version.name}")

    # Encryption algorithm
    algorithm = key_lock.algorithm
    print(f"Encryption algorithm: {algorithm.name}")
    print(f"Algorithm value: {algorithm.value}")

    # Public key information
    public_key = key_lock.public_key
    print(f"Public key length: {len(public_key)} characters")
    print(f"Public key (first 32 chars): {public_key[:32]}...")

    # Hash values for verification
    pub_key_hash = key_lock.public_key_hash
    cipher_hash = key_lock.ciphertext_hash
    print(f"Public key hash: {pub_key_hash[:16]}...")
    print(f"Ciphertext hash: {cipher_hash[:16]}...")

    # Encrypted data
    cipher_text = key_lock.cipher_text
    print(f"Ciphertext length: {len(cipher_text)} bytes")

def compare_key_locks(key_locks: list[KeyLock]):
    """Compare multiple key locks for analysis."""

    if not key_locks:
        print("No key locks to compare")
        return

    print("=== Key Lock Comparison ===")

    # Algorithm distribution
    algorithms = {}
    for i, key_lock in enumerate(key_locks):
        alg = key_lock.algorithm.name
        if alg not in algorithms:
            algorithms[alg] = []
        algorithms[alg].append(i)

    print("Algorithm distribution:")
    for alg, indices in algorithms.items():
        print(f"  {alg}: {len(indices)} key locks (indices: {indices})")

    # Version distribution
    versions = {}
    for i, key_lock in enumerate(key_locks):
        ver = key_lock.version.name
        if ver not in versions:
            versions[ver] = []
        versions[ver].append(i)

    print("\\nVersion distribution:")
    for ver, indices in versions.items():
        print(f"  {ver}: {len(indices)} key locks (indices: {indices})")

    # Check for duplicates
    unique_hashes = set()
    duplicates = []

    for i, key_lock in enumerate(key_locks):
        cipher_hash = key_lock.ciphertext_hash
        if cipher_hash in unique_hashes:
            duplicates.append(i)
        else:
            unique_hashes.add(cipher_hash)

    if duplicates:
        print(f"\\nDuplicate key locks found at indices: {duplicates}")
    else:
        print("\\nNo duplicate key locks found")

def validate_key_lock_chain(key_locks: list[KeyLock]) -> bool:
    """Validate that key locks form a valid encryption chain."""

    print("=== Key Lock Chain Validation ===")

    if not key_locks:
        print("Empty key lock chain")
        return True

    # Check that all use compatible algorithms
    algorithms = set(kl.algorithm for kl in key_locks)
    if len(algorithms) > 1:
        print(f"Warning: Multiple algorithms in chain: {[a.name for a in algorithms]}")

    # Check version consistency
    versions = set(kl.version for kl in key_locks)
    if len(versions) > 1:
        print(f"Warning: Multiple versions in chain: {[v.name for v in versions]}")

    # Validate each key lock
    valid_count = 0
    for i, key_lock in enumerate(key_locks):
        try:
            # Basic validation
            _ = key_lock.public_key
            _ = key_lock.cipher_text
            _ = key_lock.ciphertext_hash
            valid_count += 1
            print(f"✓ Key lock {i}: Valid")
        except Exception as e:
            print(f"✗ Key lock {i}: Invalid - {e}")

    is_valid = valid_count == len(key_locks)
    print(f"\\nChain validation: {'✓ Valid' if is_valid else '✗ Invalid'}")
    print(f"Valid key locks: {valid_count}/{len(key_locks)}")

    return is_valid

def extract_key_lock_metadata(key_lock: KeyLock) -> dict:
    """Extract comprehensive metadata from a key lock."""

    try:
        return {
            "algorithm": {
                "name": key_lock.algorithm.name,
                "value": key_lock.algorithm.value
            },
            "version": {
                "name": key_lock.version.name,
                "value": key_lock.version.value
            },
            "public_key": {
                "length": len(key_lock.public_key),
                "hash": key_lock.public_key_hash,
                "preview": key_lock.public_key[:32] + "..."
            },
            "ciphertext": {
                "length": len(key_lock.cipher_text),
                "hash": key_lock.ciphertext_hash
            },
            "serialization": {
                "size": len(key_lock.serialize()),
                "data_type": key_lock.data_type().name
            }
        }
    except Exception as e:
        return {"error": str(e)}

# Usage examples
def key_lock_examples():
    """Demonstrate key lock usage."""

    # Get key locks from some source (e.g., encrypted data)
    key_locks = get_key_locks_from_encrypted_data()

    if key_locks:
        # Analyze first key lock
        analyze_key_lock(key_locks[0])

        # Compare multiple key locks
        if len(key_locks) > 1:
            compare_key_locks(key_locks)

        # Validate the chain
        validate_key_lock_chain(key_locks)

        # Extract metadata
        metadata = extract_key_lock_metadata(key_locks[0])
        print(f"\\n=== Metadata ===")
        for category, data in metadata.items():
            if isinstance(data, dict):
                print(f"{category}:")
                for key, value in data.items():
                    print(f"  {key}: {value}")
            else:
                print(f"{category}: {data}")

if __name__ == "__main__":
    key_lock_examples()

Example: Key Lock Security Analysis

from keychain.core.key_lock import KeyLock
from keychain.constants import EncryptionScheme

class KeyLockSecurityAnalyzer:
    """Analyzer for key lock security properties."""

    def __init__(self):
        # Define security levels for different algorithms
        self.algorithm_security = {
            EncryptionScheme.ECIES_ECP_SECP256R1: "medium",
            EncryptionScheme.ECIES_ECP_SECP384R1: "high",
            EncryptionScheme.ECIES_ECP_SECP521R1: "ultra",
            EncryptionScheme.RSA_OAEP_SHA_2048: "medium",
            EncryptionScheme.RSA_OAEP_SHA_3072: "high",
            EncryptionScheme.RSA_OAEP_SHA_4096: "ultra"
        }

    def analyze_algorithm_security(self, key_lock: KeyLock) -> dict:
        """Analyze the security level of the encryption algorithm."""

        algorithm = key_lock.algorithm
        security_level = self.algorithm_security.get(algorithm, "unknown")

        analysis = {
            "algorithm": algorithm.name,
            "security_level": security_level,
            "algorithm_class": self._get_algorithm_class(algorithm),
            "key_size": self._estimate_key_size(algorithm),
            "quantum_resistant": self._is_quantum_resistant(algorithm)
        }

        return analysis

    def _get_algorithm_class(self, algorithm: EncryptionScheme) -> str:
        """Get the general class of the encryption algorithm."""
        name = algorithm.name
        if "ECIES" in name:
            return "Elliptic Curve Integrated Encryption"
        elif "RSA" in name:
            return "RSA Encryption"
        elif "DLIES" in name:
            return "Discrete Logarithm Integrated Encryption"
        elif "ELGAMAL" in name:
            return "ElGamal Encryption"
        else:
            return "Unknown"

    def _estimate_key_size(self, algorithm: EncryptionScheme) -> str:
        """Estimate the key size from the algorithm name."""
        name = algorithm.name
        if "256" in name:
            return "256-bit"
        elif "384" in name:
            return "384-bit"
        elif "521" in name:
            return "521-bit"
        elif "2048" in name:
            return "2048-bit"
        elif "3072" in name:
            return "3072-bit"
        elif "4096" in name:
            return "4096-bit"
        else:
            return "Unknown"

    def _is_quantum_resistant(self, algorithm: EncryptionScheme) -> bool:
        """Check if algorithm is considered quantum resistant."""
        # Note: Currently no algorithms are truly quantum resistant
        # This is for future post-quantum algorithms
        return False

    def generate_security_report(self, key_locks: list[KeyLock]) -> str:
        """Generate a comprehensive security report."""

        if not key_locks:
            return "No key locks to analyze"

        report_lines = ["KEY LOCK SECURITY ANALYSIS", "=" * 30, ""]

        # Overall statistics
        total = len(key_locks)
        security_counts = {"unknown": 0, "medium": 0, "high": 0, "ultra": 0}
        algorithm_counts = {}

        for key_lock in key_locks:
            analysis = self.analyze_algorithm_security(key_lock)
            security_level = analysis["security_level"]
            algorithm = analysis["algorithm"]

            security_counts[security_level] += 1
            algorithm_counts[algorithm] = algorithm_counts.get(algorithm, 0) + 1

        # Security level distribution
        report_lines.append("Security Level Distribution:")
        for level, count in security_counts.items():
            if count > 0:
                percentage = count / total * 100
                report_lines.append(f"  {level.title()}: {count} ({percentage:.1f}%)")

        report_lines.append("")

        # Algorithm distribution
        report_lines.append("Algorithm Distribution:")
        for algorithm, count in sorted(algorithm_counts.items()):
            percentage = count / total * 100
            report_lines.append(f"  {algorithm}: {count} ({percentage:.1f}%)")

        report_lines.append("")

        # Security recommendations
        report_lines.append("Security Recommendations:")

        low_security = security_counts["unknown"] + security_counts.get("low", 0)
        if low_security > 0:
            report_lines.append(f"  ⚠ {low_security} key locks use weak algorithms")
            report_lines.append("    Consider upgrading to higher security algorithms")

        if security_counts["ultra"] == total:
            report_lines.append("  ✓ All key locks use ultra-high security algorithms")
        elif security_counts["high"] + security_counts["ultra"] >= total * 0.8:
            report_lines.append("  ✓ Most key locks use high security algorithms")
        else:
            report_lines.append("  ⚠ Consider using higher security algorithms")

        # Quantum resistance
        quantum_resistant = sum(1 for kl in key_locks
                              if self._is_quantum_resistant(kl.algorithm))
        if quantum_resistant == 0:
            report_lines.append("  ⚠ No quantum-resistant algorithms detected")
            report_lines.append("    Consider post-quantum cryptography for future-proofing")

        return "\\n".join(report_lines)

    def recommend_algorithm_upgrade(self, key_lock: KeyLock) -> str:
        """Recommend algorithm upgrades for a key lock."""

        current = key_lock.algorithm
        current_security = self.algorithm_security.get(current, "unknown")

        if current_security == "ultra":
            return f"Current algorithm {current.name} is already ultra-high security"

        # Recommend upgrades based on current algorithm class
        if "ECIES" in current.name:
            return f"Consider upgrading from {current.name} to ECIES_ECP_SECP521R1 for ultra security"
        elif "RSA" in current.name:
            return f"Consider upgrading from {current.name} to RSA_OAEP_SHA_4096 for ultra security"
        else:
            return f"Consider upgrading {current.name} to a higher security algorithm"

# Usage example
def security_analysis_example():
    """Demonstrate key lock security analysis."""

    analyzer = KeyLockSecurityAnalyzer()
    key_locks = get_key_locks_from_system()

    if key_locks:
        # Analyze individual key lock
        first_analysis = analyzer.analyze_algorithm_security(key_locks[0])
        print("First Key Lock Analysis:")
        for key, value in first_analysis.items():
            print(f"  {key}: {value}")

        # Generate security report
        report = analyzer.generate_security_report(key_locks)
        print(f"\\n{report}")

        # Get upgrade recommendations
        for i, key_lock in enumerate(key_locks[:3]):  # First 3
            recommendation = analyzer.recommend_algorithm_upgrade(key_lock)
            print(f"\\nKey Lock {i} upgrade: {recommendation}")

if __name__ == "__main__":
    security_analysis_example()

Error Handling

Key lock operations can raise various exceptions:

Example:

from keychain.exceptions import KeychainValidationError, KeychainSecurityError

try:
    # Create key lock from serialized data
    key_lock = KeyLock(serialized_data)

    # Access properties
    public_key = key_lock.public_key
    cipher_text = key_lock.cipher_text
    algorithm = key_lock.algorithm

    # Verify integrity
    cipher_hash = key_lock.ciphertext_hash

    # Check algorithm security
    if key_lock.algorithm.name.endswith("4096"):
        print("High security algorithm detected")

except KeychainValidationError as e:
    print(f"Validation error: {e}")
except KeychainSecurityError as e:
    print(f"Security error: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")

See Also