Skip to main content

PQC Secure Enclave SDK for on-device AI. ML-KEM-768 key encapsulation + AES-256-GCM encrypted model weights and credentials, pluggable backends for iOS Secure Enclave, Android StrongBox, Qualcomm QSEE.

Project description

PQC Secure Enclave SDK

PQC Native ML-KEM-768 AES-256-GCM iOS + Android Ready License Version

Quantum-safe on-device AI. A clean Python SDK for storing AI model weights, LoRA adapters, tokenizers, and API credentials in device secure enclaves using ML-KEM-768 key encapsulation + AES-256-GCM encryption. Pluggable backends for Apple Secure Enclave, Android StrongBox, and Qualcomm QSEE let you ship quantum-resistant on-device AI today - without waiting for the platform vendors to finish their PQC rollouts.

The Problem

Your phone runs AI inference constantly: autocomplete, voice recognition, image classification, on-device LLMs. The model weights and API credentials those features rely on sit in device storage for years - Apple Neural Engine, Qualcomm AI Engine, and MediaTek APU models typically persist across OS upgrades. Today they are protected by classical cryptography baked into the secure element.

This is the HNDL threat model (Harvest Now, Decrypt Later) applied to on-device AI:

  • An attacker who exfiltrates encrypted weight files today - from backups, compromised cloud sync, supply-chain tooling, or forensic device imaging - can store them indefinitely.
  • When a cryptographically relevant quantum computer arrives, every RSA/ECDSA-wrapped symmetric key is retroactively broken and the plaintext weights fall out.
  • For proprietary fine-tunes, biometric templates, and long-lived OAuth refresh tokens, "eventually decrypted" is functionally equivalent to "decrypted".

The Solution

Wrap every on-device AI artifact in a PQC-protected envelope:

  • ML-KEM-768 (FIPS 203, NIST PQC) for the session key that the enclave unwraps.
  • AES-256-GCM (FIPS 197) for the artifact body. Key is 32 bytes, nonce 12 bytes, tag 16 bytes.
  • SHA3-256 content hash authenticated via AES-GCM AAD - any metadata tampering breaks decryption.
  • ML-DSA (FIPS 204) signatures for device attestations that commit to what was stored.
  • Pluggable backends: iOSEnclaveBackend, AndroidEnclaveBackend, QSEEBackend, plus InMemoryEnclaveBackend for tests.

Installation

pip install pqc-enclave-sdk

Development:

pip install -e ".[dev]"

Quick Start

from pqc_enclave_sdk import (
    ArtifactKind,
    EnclaveVault,
    InMemoryEnclaveBackend,
)

backend = InMemoryEnclaveBackend(device_id="iphone-alice", device_model="iphone-15-pro")
vault = EnclaveVault(backend=backend)

vault.unlock()
vault.put_artifact(
    name="llama-3.2-1b-int4",
    kind=ArtifactKind.MODEL_WEIGHTS,
    content=weights_bytes,
    version="1.0.0",
    app_bundle_id="com.example.localllm",
)
vault.save()
vault.lock()

# Later, in the same process or another app launch:
vault.unlock()
weights = vault.get_artifact("llama-3.2-1b-int4").content

Architecture

  Your App                EnclaveVault            EnclaveBackend          Device Secure Enclave
  --------                ------------            --------------          ---------------------
      |                        |                         |                          |
      | put_artifact(bytes)    |                         |                          |
      | ---------------------> |                         |                          |
      |                        | 1. derive session key   |                          |
      |                        |    via ML-KEM-768       |                          |
      |                        | 2. AES-256-GCM encrypt  |                          |
      |                        |    with content-hash AAD|                          |
      |                        | 3. store_session_key ------------------------------>|
      |                        |                         | wraps w/ hardware KEK    |
      |                        | 4. save_artifacts       |                          |
      |                        | ----------------------> |                          |
      |                        |                         | persists ciphertext      |
      |                        |                         | to Keychain/Keystore     |
      |                        |                         |                          |
      | get_artifact(name)     |                         |                          |
      | ---------------------> |                         |                          |
      |                        | 5. load_session_key --------------------------------|
      |                        |    (unwrap inside SEP)                             |
      |                        | 6. AES-256-GCM decrypt  |                          |
      | <--- plaintext         |                         |                          |

Artifact Kinds

Kind Purpose
MODEL_WEIGHTS Full model weight tensors (INT4 / INT8 / FP16 on-device checkpoints).
LORA_ADAPTER Low-rank fine-tune adapters; smaller but sensitive for proprietary tunes.
TOKENIZER Tokenizer vocab + merges; lower-sensitivity but integrity-critical.
CREDENTIAL API keys, OAuth tokens, auth bearer tokens.
BIOMETRIC_TEMPLATE Encoded face / fingerprint templates. Highest sensitivity.
INFERENCE_CACHE KV-cache blobs from prior conversations.
SAFETY_MODEL Jailbreak classifier / content-safety adapter.
OTHER Everything else.

Cryptography

Primitive Role Standard
ML-KEM-768 Session-key encapsulation to the enclave's PQC public key FIPS 203
AES-256-GCM Symmetric encryption of every artifact body FIPS 197 / SP 800-38D
SHA3-256 Content hash + canonical AAD hashing FIPS 202
ML-DSA-65 / 87 Signatures over DeviceAttestations FIPS 204

The AES-GCM AAD covers the full artifact metadata plus the content hash plus the key id - any metadata swap or cross-artifact key reuse is detected on decrypt.

Threat Model

Threat Mitigation
Device theft (attacker has the phone) Symmetric key never leaves the enclave. Access control requires biometrics / device unlock.
HNDL on stored weights (exfiltrated encrypted blobs today, decrypted post-CRQC) ML-KEM-768 session-key encapsulation; AES-256-GCM (Grover-adjusted 128-bit security).
Rogue app reading another app's artifacts AccessPolicy.allowed_bundle_ids filters callers; OS Keychain / Keystore access-control flags enforce at the kernel level.
Stale session key (long-lived re-use) DEFAULT_SESSION_TTL = 3600; is_unlocked re-checks expiration on every call.
Post-quantum forgery of attestation DeviceAttester signs with ML-DSA, not ECDSA.
Artifact swap (attacker substitutes one encrypted blob for another) AAD includes artifact_id and content hash; decryption of a swapped blob against the wrong metadata fails.
Downgrade to classical crypto Algorithm is baked into the AAD; a rewrite requires access to the PQC session key.

Backend Integration Guides

iOS Secure Enclave (CryptoKit sketch)

import CryptoKit

// 1. Generate a non-extractable SEP key at app install.
let sepKey = try SecureEnclave.P256.KeyAgreement.PrivateKey(
    accessControl: SecAccessControlCreateWithFlags(
        nil, kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
        [.privateKeyUsage, .biometryCurrentSet], nil)!
)

// 2. On unlock, receive the 32-byte AES-GCM key from the Python SDK
// (ideally via an ML-KEM-768 ciphertext the SEP decapsulates). Wrap it
// with the SEP key and write the sealed blob to the Keychain:
let sealedBox = try AES.GCM.seal(sessionKey, using: sepSymmetricKey)
SecItemAdd([
    kSecClass: kSecClassGenericPassword,
    kSecAttrService: "com.dyber.pqc.enclave",
    kSecAttrTokenID: kSecAttrTokenIDSecureEnclave,
    kSecValueData: sealedBox.combined!,
] as CFDictionary, nil)

Android StrongBox (Kotlin sketch)

val spec = KeyGenParameterSpec.Builder(
    "com.dyber.pqc.enclave.session",
    KeyProperties.PURPOSE_WRAP_KEY or KeyProperties.PURPOSE_ENCRYPT
  ).setBlockModes(KeyProperties.BLOCK_MODE_GCM)
   .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
   .setIsStrongBoxBacked(true)              // Titan M / Knox Vault
   .setUserAuthenticationRequired(true)
   .setUnlockedDeviceRequired(true)
   .build()
val kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore")
kpg.initialize(spec)
kpg.generateKeyPair()

Qualcomm QSEE (Trusted App sketch)

// Signed TA running inside QSEE; the Python SDK talks to it via QSEECom.
int pqc_enclave_ta_store_session(uint8_t *session_key, uint32_t len) {
    sealed_key_t sealed;
    ta_kek_wrap(g_ta_kek, session_key, len, &sealed);
    return qseecom_write_sealed_blob(&sealed);   // persists to Keystore
}

API Reference

EnclaveVault

Method Description
unlock(ttl_seconds=3600) Derive a session key via ML-KEM-768 and mark the vault usable.
lock() Wipe the session key from memory.
put_artifact(name, kind, content, ...) AES-256-GCM encrypt and store. Returns the EncryptedArtifact.
get_artifact(name_or_id) Decrypt and return EnclaveArtifact (metadata + plaintext).
delete_artifact(name_or_id) Remove by name or id.
list_artifacts() List ArtifactMetadata for everything in the vault.
save() Persist the encrypted store to the backend.
is_unlocked Property; also re-checks session expiry.

EnclaveArtifact

Field / Method Description
metadata ArtifactMetadata frozen dataclass.
content Plaintext bytes.
sha3_256_hex() SHA3-256 of the content, hex.
content_hash(bytes) (static) SHA3-256 helper.

AccessPolicy / ArtifactPolicy

Method Description
AccessPolicy().add(rule) Attach a rule for an ArtifactKind.
.check(metadata, caller_bundle_id) Raises PolicyViolationError on deny.
ArtifactPolicy(kind, allowed_bundle_ids, require_biometric, max_uses_per_hour) Per-kind rule.

DeviceAttester

Method Description
DeviceAttester(identity, device_id, device_model, enclave_vendor) Bind an AgentIdentity to a device.
.attest(artifact_id, content_hash) Produce a signed DeviceAttestation.
DeviceAttester.verify(att) (static) Returns True / False.
DeviceAttester.verify_or_raise(att) (static) Raises AttestationError on invalid.

Exceptions

Exception When
EnclaveSDKError Base class.
UnknownArtifactError get_artifact / delete_artifact against a missing id or name.
EnclaveLockedError Operation attempted on a locked vault.
DecryptionError AES-GCM tag rejected ciphertext or AAD.
BackendError iOS / Android / QSEE backend refused or is stubbed.
AttestationError DeviceAttester.verify_or_raise saw an invalid signature.
PolicyViolationError AccessPolicy.check denied the caller.

Why PQC for On-Device AI

On-device model weights live on a user's phone for five or more years - longer than any reasonable cryptanalytic lead time against classical RSA/ECDSA. Proprietary fine-tunes, biometric templates, and OAuth refresh tokens embedded in those artifacts are exactly the kind of data a patient adversary will harvest now to decrypt later.

This is the HNDL threat model at its most concrete: the ciphertext blob is already on the user's device, already in cloud backups, and already syncing through MDM pipes. Every one of those copies is at risk the instant a CRQC arrives. ML-KEM-768 and AES-256-GCM close that window today - no platform-vendor timeline dependency, no waiting for iOS 19 or Android 16 to ship their post-quantum Keystore updates.

Examples

See the examples/ directory:

  • store_model_weights.py - 256 KB model weight lifecycle through an in-memory vault.
  • store_credentials.py - three API credentials across three different app bundles.
  • device_attestation.py - sign and verify a DeviceAttestation, and show the tamper case.

Run them:

python examples/store_model_weights.py
python examples/store_credentials.py
python examples/device_attestation.py

Development

pip install -e ".[dev]"
pytest
ruff check src/ tests/ examples/

Related

Part of the QuantaMrkt post-quantum tooling registry. See also:

  • QuantumShield - the underlying PQC toolkit (AgentIdentity, SignatureAlgorithm, generate_kem_keypair, sign / verify).
  • PQC Agent Wallet - sister tool for passphrase-unlocked credential vaults.
  • PQC GPU Driver - sister tool for keeping tensors encrypted on discrete accelerators.
  • PQC Hypervisor Attestation - sister tool for confidential-VM memory attestation.

License

Apache License 2.0. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pqc_enclave_sdk-0.1.0.tar.gz (24.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pqc_enclave_sdk-0.1.0-py3-none-any.whl (25.1 kB view details)

Uploaded Python 3

File details

Details for the file pqc_enclave_sdk-0.1.0.tar.gz.

File metadata

  • Download URL: pqc_enclave_sdk-0.1.0.tar.gz
  • Upload date:
  • Size: 24.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for pqc_enclave_sdk-0.1.0.tar.gz
Algorithm Hash digest
SHA256 cfa29b6802d7eaeaf29cc3997976f13d7c55bae56609483fa04f8c75fb200e2f
MD5 c8a8b19c89ca32928fd40637b6ae88f3
BLAKE2b-256 8aa16a6652a92decdb5d015c5bb2334efc69798da4ae9cccafff9f717d6888a6

See more details on using hashes here.

File details

Details for the file pqc_enclave_sdk-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pqc_enclave_sdk-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0d4f2501b7790d6c145459c1911ff7f1d991263c7621f55f5e9e0d1602dbe8f6
MD5 78e994dd49ebdf70fe8d4cd0f61188d6
BLAKE2b-256 37ca8fd0de6ec108f50dd663dc41f2ed4e1fceff37f3fbb40f48eefc3c2f262a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page