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>
162 lines
5.7 KiB
Python
162 lines
5.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Claim 4: cryptographic erasure makes ciphertext permanently undecryptable.
|
|
|
|
The strongest claim in the set, resting on standard cryptography alone:
|
|
|
|
1. a payload (a STAND-IN blob, not a real model) is envelope-encrypted
|
|
with AES-256-GCM: fresh data key, wrapped by a capability wrapping key
|
|
held only by the key authority;
|
|
2. a valid licence decrypts it;
|
|
3. an EXFILTRATED COPY of the sealed unit is taken, and decrypts fine
|
|
BEFORE erasure (stolen ciphertext plus a licensed key release);
|
|
4. the authority DESTROYS the wrapping key;
|
|
5. both the original AND the exfiltrated copy are now permanently
|
|
undecryptable: every decrypt attempt raises. The escaped copy is
|
|
useless.
|
|
|
|
Scope, stated plainly: the guarantee is about key destruction. If the KEY
|
|
had been exfiltrated before erasure, erasure would not help; key custody is
|
|
an external key-store / hardware concern and is named open work.
|
|
"""
|
|
|
|
import copy
|
|
import hashlib
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
|
|
|
from capability_licensing import (
|
|
CertificateAuthority,
|
|
KeyAuthority,
|
|
KeyDestroyedError,
|
|
RevocationList,
|
|
UnsealError,
|
|
unseal,
|
|
)
|
|
|
|
failures = []
|
|
|
|
|
|
def check(label: str, condition: bool, evidence: str) -> None:
|
|
marker = "ok " if condition else "FAIL"
|
|
print(f" [{marker}] {label}")
|
|
print(f" {evidence}")
|
|
if not condition:
|
|
failures.append(label)
|
|
|
|
|
|
def main() -> int:
|
|
print("=== Claim 4: crypto-erasure defeats even an exfiltrated copy ===\n")
|
|
|
|
authority = CertificateAuthority()
|
|
root = authority.create_root("Reference Root Authority")
|
|
organisation = authority.issue_organisation(root.serial, "Reference Research Organisation")
|
|
licence, _licence_key = authority.issue_capability(
|
|
organisation.serial,
|
|
"demonstration-capability",
|
|
claims={"grant": "research demonstration only"},
|
|
)
|
|
keys = KeyAuthority(
|
|
trusted_roots=[root],
|
|
intermediates=[organisation],
|
|
revocation_list=RevocationList(),
|
|
)
|
|
|
|
payload = b"STAND-IN CAPABILITY UNIT (not a real model)\n" + os.urandom(256 * 1024)
|
|
payload_digest = hashlib.sha256(payload).hexdigest()
|
|
sealed = keys.seal_unit("unit-erasure-001", payload, licence.serial)
|
|
print(f" stand-in payload: {len(payload):,} bytes plaintext, "
|
|
f"sha256 {payload_digest[:16]}...")
|
|
print(f" sealed unit: {sealed.ciphertext_size():,} bytes AES-256-GCM "
|
|
"ciphertext; the only wrapping key lives at the key authority\n")
|
|
|
|
# 1. A valid licence decrypts the original.
|
|
plaintext = keys.request_decrypt(sealed, licence)
|
|
check(
|
|
"a valid licence decrypts the sealed unit",
|
|
hashlib.sha256(plaintext).hexdigest() == payload_digest,
|
|
"decrypted plaintext digest matches the original payload",
|
|
)
|
|
|
|
# 2. An adversary takes a byte-for-byte copy of the sealed unit.
|
|
exfiltrated = copy.deepcopy(sealed)
|
|
check(
|
|
"an exfiltrated byte-for-byte copy of the sealed unit is taken",
|
|
exfiltrated == sealed and exfiltrated is not sealed,
|
|
"the copy is identical ciphertext, held outside the authority's control",
|
|
)
|
|
|
|
# 3. Before erasure, the exfiltrated copy decrypts (same ciphertext, and
|
|
# the wrapping key still exists at the authority).
|
|
copy_plaintext = keys.request_decrypt(exfiltrated, licence)
|
|
copy_decryptable_before_erase = (
|
|
hashlib.sha256(copy_plaintext).hexdigest() == payload_digest
|
|
)
|
|
check(
|
|
"BEFORE erasure the exfiltrated copy decrypts",
|
|
copy_decryptable_before_erase,
|
|
f"copy_decryptable_before_erase={copy_decryptable_before_erase} "
|
|
"(this is the honest baseline: the copy was a real threat)",
|
|
)
|
|
|
|
# 4. The authority destroys the wrapping key.
|
|
keys.destroy(sealed.unit_id)
|
|
print("\n >>> CRYPTO-ERASE: the authority zeroises and discards the only "
|
|
"copy of the wrapping key <<<\n")
|
|
|
|
# 5. The ORIGINAL is now undecryptable: the request raises.
|
|
original_error = None
|
|
try:
|
|
keys.request_decrypt(sealed, licence)
|
|
except KeyDestroyedError as exc:
|
|
original_error = exc
|
|
check(
|
|
"AFTER erasure the ORIGINAL raises on decryption",
|
|
original_error is not None,
|
|
f"KeyDestroyedError: {original_error}",
|
|
)
|
|
|
|
# 6. The EXFILTRATED COPY is equally dead: same ciphertext, same
|
|
# destroyed key.
|
|
copy_error = None
|
|
try:
|
|
keys.request_decrypt(exfiltrated, licence)
|
|
except KeyDestroyedError as exc:
|
|
copy_error = exc
|
|
check(
|
|
"AFTER erasure the EXFILTRATED COPY raises on decryption",
|
|
copy_error is not None,
|
|
f"KeyDestroyedError: {copy_error}",
|
|
)
|
|
|
|
# 7. Ciphertext-level evidence: even bypassing the authority, unsealing
|
|
# the stolen copy with any other key fails AES-256-GCM
|
|
# authentication. Without the destroyed 256-bit wrapping key there is
|
|
# no path to the plaintext.
|
|
bypass_error = None
|
|
try:
|
|
unseal(exfiltrated, os.urandom(32))
|
|
except UnsealError as exc:
|
|
bypass_error = exc
|
|
check(
|
|
"bypassing the authority with a guessed key fails authentication",
|
|
bypass_error is not None,
|
|
f"UnsealError: {bypass_error}",
|
|
)
|
|
|
|
print()
|
|
if failures:
|
|
print(f"RESULT: FAIL - {len(failures)} check(s) did not behave as claimed")
|
|
return 1
|
|
print(
|
|
"RESULT: PASS - before erasure both the original and the exfiltrated "
|
|
"copy decrypted; after destroying the wrapping key, both raise on every "
|
|
"decrypt attempt. The escaped ciphertext is permanently useless."
|
|
)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|