01
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. |
02
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.
03
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.
04
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)
05
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
06
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.