Security Architecture

Zero-trust, by construction.

ntkDesktop's security model is not a layer applied after design — it is the design. This document specifies the threat model, cryptographic primitives, policy evaluation, and device-binding protocol that enforce zero-trust at every data path.

Threat Model

ntkDesktop assumes the cloud storage backend is untrusted. The threat model is explicit about what is and is not protected.

Protected
Confidentiality File contents are ciphertext at every point outside the local device. Integrity AEAD authentication tag covers each shard. Tampered shards are rejected. Authorization dABAC policy is evaluated locally. Provider cannot influence access decisions. Key secrecy Per-file symmetric keys never leave the device in plaintext. Token binding Auth tokens are bound to the device key via DPoP proofs.
Out of scope
Physical access Local device compromise is not defended against at the sync layer. Metadata File names and sizes are visible to storage providers as object keys and sizes. Availability DoS against the storage backends is not addressed by ntkDesktop. Side channels Timing or power-analysis attacks are not mitigated.
Passive cloud attacker Can read all stored objects. Sees only ciphertext + IDA shards. guaranteed
Active cloud attacker Can modify stored objects. Modification detected by AEAD tag verification.
Network attacker All traffic uses TLS 1.3. Token replay blocked by DPoP nonce binding.
Compromised provider credential k-of-n sharding means compromising one provider reveals no plaintext.

Envelope Encryption

Every file is encrypted with a unique per-file key using streaming AEAD. No two files share a key. Key material is never stored on the cloud provider.

Cipher parameters
Algorithm AES-256-GCM Key size 256 bits (32 bytes) Nonce 96 bits, deterministic per-segment (segment index || file key id) Segment size 4096 bytes (aligned to CF API block boundary) Auth tag 128 bits, covers ciphertext + segment index AAD Key derivation HKDF-SHA256 from device master key + file identity

Streaming AEAD encrypts each 4096-byte segment independently. This allows random-access reads during hydration without decrypting the full file. The segment index is included in the AAD to prevent segment reordering attacks.

Key lifecycle
1. Device master key generated on first enrollment, stored in DPAPI-protected store. 2. Per-file key = HKDF(master_key, file_id || version). 3. Per-file key wrapped with device public key, stored in sidecar manifest. 4. On hydration: manifest sidecar fetched → key unwrapped locally → segments decrypted. 5. Key material zeroed from memory after use.

IDA Shard Dispersal

After encryption, each file is split into n shards using Information Dispersal Algorithm. Any k shards are sufficient to reconstruct the file. Compromising fewer than k providers reveals nothing.

IDA parameters
Scheme Rabin IDA over GF(2^8) Configuration k-of-n, user-configurable (e.g. 3-of-5, 4-of-6) Shard size ceil(file_size / k) + overhead Shard auth Each shard has its own AES-256-GCM AEAD tag Manifest Sidecar JSON binds shard order, checksums, and wrapped file key Alignment All shard boundaries 4096-byte aligned

Each shard is independently authenticated. A corrupt or missing shard is detected immediately during reconstruction. The manifest sidecar is stored alongside the shards and is required for hydration.


dABAC Policy

Dynamic Attribute-Based Access Control evaluates access on every file operation. Policy is AND-of-OR: each top-level clause must be satisfied, and each clause is satisfied if any one of its attribute conditions is true.

Policy evaluation rules
Default DENY — no policy match = access denied Unknown attr DENY — unknown attribute evaluates as false, not error AND semantics All clauses in the policy must be satisfied OR semantics Within a clause, any one condition is sufficient Evaluation Local, no server round-trip required Caching Policy cached per sync-root startup; invalidated on version change
// Example: allow access if (dept=eng OR dept=sec) AND (clearance=high)

Policy {
  clause_1: [ dept == "eng", dept == "sec" ]   // OR
  clause_2: [ clearance == "high" ]             // AND with clause_1
}

Evaluation:
  subject.dept      = "eng"   → clause_1 = PASS
  subject.clearance = "high"  → clause_2 = PASS
  result                      = ALLOW

  subject.dept      = "mkt"   → clause_1 = FAIL
  result                      = DENY  (short-circuit)

Device Binding

Auth tokens are cryptographically bound to the enrolling device using DPoP (Demonstrating Proof-of-Possession). A stolen token cannot be replayed from a different device.

DPoP parameters
Proof type JWS compact serialization, ES256 Claims jti (unique), htm (HTTP method), htu (URI), iat, ath (access token hash) Key storage Device key in DPAPI-protected store (Windows CNG) JWKS rotation Server rotates JWKS; client caches with TTL + background refresh Token lifetime Access: 15m. Refresh: 7d. Refresh bound to device key at issuance. Enrollment One-time offline enrollment generates device keypair + CSR

Audit Surface

All file operations emit structured JSON log lines. Every CFAPI callback records a fixed set of required fields for correlation and forensic analysis.

Required fields per CFAPI operation
component Module emitting the log entry event Operation type (fetch_data, validate_data, dehydrate, etc.) msg Human-readable description file.path_norm Normalized file path (no trailing separators) provider.id Cloud provider identifier object.key Storage object key bucket.name Bucket or container name duration.ms Wall-clock duration of the operation err.code HRESULT or custom error code (0 on success) status.code Outcome code (ok, error, denied, etc.)

Logs are written as .jsonl (newline-delimited JSON). Use XDrive-logcat to filter and format log streams. The full field dictionary is maintained in the logging field dictionary.