Clean-room reference implementation (Ed25519 certificate chain, AES-256-GCM envelope, three-rung revocation ladder, crypto-erasure) with runnable examples and 36 tests that reproduce each demonstrated claim on stand-in payloads. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
90 lines
2.8 KiB
Python
90 lines
2.8 KiB
Python
"""Claim 4: crypto-erasure makes both the original and an exfiltrated copy
|
|
permanently undecryptable."""
|
|
|
|
import copy
|
|
import os
|
|
|
|
import pytest
|
|
|
|
from capability_licensing import (
|
|
KeyDestroyedError,
|
|
UnsealError,
|
|
generate_wrapping_key,
|
|
seal,
|
|
unseal,
|
|
)
|
|
|
|
|
|
def test_exfiltrated_copy_decrypts_before_erasure(sealed_setup):
|
|
exfiltrated = copy.deepcopy(sealed_setup.sealed)
|
|
plaintext = sealed_setup.keys.request_decrypt(
|
|
exfiltrated, sealed_setup.chain.capability
|
|
)
|
|
assert plaintext == sealed_setup.payload
|
|
|
|
|
|
def test_after_erasure_both_copies_are_undecryptable(sealed_setup):
|
|
exfiltrated = copy.deepcopy(sealed_setup.sealed)
|
|
|
|
# Honest baseline: the copy is decryptable before erasure.
|
|
assert (
|
|
sealed_setup.keys.request_decrypt(exfiltrated, sealed_setup.chain.capability)
|
|
== sealed_setup.payload
|
|
)
|
|
|
|
sealed_setup.keys.destroy(sealed_setup.sealed.unit_id)
|
|
|
|
with pytest.raises(KeyDestroyedError):
|
|
sealed_setup.keys.request_decrypt(
|
|
sealed_setup.sealed, sealed_setup.chain.capability
|
|
)
|
|
with pytest.raises(KeyDestroyedError):
|
|
sealed_setup.keys.request_decrypt(
|
|
exfiltrated, sealed_setup.chain.capability
|
|
)
|
|
|
|
|
|
def test_ciphertext_is_useless_without_the_exact_wrapping_key():
|
|
wrapping_key = generate_wrapping_key()
|
|
payload = b"STAND-IN CAPABILITY UNIT (not a real model)\n" + os.urandom(2048)
|
|
sealed = seal("unit-raw-001", payload, wrapping_key, "CERT-example")
|
|
|
|
# The exact key decrypts.
|
|
assert unseal(sealed, wrapping_key) == payload
|
|
|
|
# Any other key fails AES-256-GCM authentication: no partial decryption,
|
|
# no garbage plaintext, a hard failure.
|
|
with pytest.raises(UnsealError):
|
|
unseal(sealed, os.urandom(32))
|
|
|
|
# A single flipped bit in the key also fails: recovery requires the
|
|
# destroyed key exactly, not something close to it.
|
|
near_miss = bytearray(wrapping_key)
|
|
near_miss[0] ^= 0x01
|
|
with pytest.raises(UnsealError):
|
|
unseal(sealed, bytes(near_miss))
|
|
|
|
|
|
def test_tampered_ciphertext_fails_authentication():
|
|
import dataclasses
|
|
|
|
wrapping_key = generate_wrapping_key()
|
|
payload = b"STAND-IN CAPABILITY UNIT (not a real model)\n" + os.urandom(2048)
|
|
sealed = seal("unit-raw-002", payload, wrapping_key, "CERT-example")
|
|
|
|
tampered_hex = bytearray(sealed.payload_ciphertext_hex.encode())
|
|
tampered_hex[0] = ord("f") if tampered_hex[0] != ord("f") else ord("0")
|
|
tampered = dataclasses.replace(
|
|
sealed, payload_ciphertext_hex=tampered_hex.decode()
|
|
)
|
|
with pytest.raises(UnsealError):
|
|
unseal(tampered, wrapping_key)
|
|
|
|
|
|
def test_sealed_unit_reports_payload_digest(sealed_setup):
|
|
import hashlib
|
|
|
|
assert (
|
|
sealed_setup.sealed.payload_sha256
|
|
== hashlib.sha256(sealed_setup.payload).hexdigest()
|
|
)
|