Security is not a feature.
It is the architecture.

v1.0  ·  Document: ntk-security-arch-v1  ·  Report an issue →

Encryption Model

Every file is encrypted with AES-256-GCM on-device before any network operation. Encryption keys are derived locally and never transmitted in plaintext. The cloud receives only ciphertext.

Claim
The cloud provider never receives plaintext file content.
Claim
AES-GCM provides authenticated encryption — tampering is detectable.

Vault Key Architecture

Each vault has a randomly-generated 256-bit master key. The key is wrapped with a password-derived key (PBKDF2 + HKDF) and stored encrypted at rest. Optionally, the wrapped key can be further sealed inside Android Keystore with biometric binding.

[ntk] vault_key = random_256bit()
[ntk] wrapping_key = PBKDF2(password, salt, 310000)
[ntk] stored = AES_GCM_wrap(vault_key, wrapping_key)
[ntk] server_copy = none
Claim
Vault keys cannot be recovered without the user's password or enrolled biometric.

Provider Secrets

Cloud provider credentials (OAuth tokens, S3 keys, etc.) are encrypted at rest using the vault key. Access requires an unlocked vault session. Credentials are wiped from memory when the vault is locked.

Claim
Provider credentials are encrypted with the vault key; plaintext only exists in memory during an active vault session.

Zero Trust Storage

Downloaded files are temporary. Unpinned files are automatically swept from the device after a configurable TTL. The sweep runs at app start and on a background schedule. Pinned files are retained until explicitly unpinned.

[ntk] file.status = dehydrated // not on-device by default
[ntk] file.pin = false // not pinned
[ntk] ttl_sweep → delete local copy after TTL
[ntk] on_unlock: sweep_expired_files()

Auth Protocol

Authentication uses DPoP-bound JWTs (RFC 9449). Each request is cryptographically bound to a device-held ES384 key pair in Android Keystore. JWKS rotation is supported. WebAuthn passkeys are the primary credential.

Claim
Access tokens are DPoP-bound — stolen tokens cannot be replayed from another device.

dABAC Policy Enforcement

Distributed Attribute-Based Access Control evaluates access on every file operation. Policy is AND-of-OR: every top-level clause must be satisfied, and each clause is satisfied if any one of its attribute conditions is true. Evaluation is local — no server round-trip. Default posture is denial: no policy match means no access.

[dabac] default_posture = DENY
[dabac] clause_1: [ dept == "eng" OR dept == "sec" ] // OR
[dabac] clause_2: [ clearance == "high" ] // AND
[dabac] unknown_attr → evaluates as false, not error
[dabac] server_round_trip = false
Claim
Access decisions are made locally on-device — the cloud provider cannot influence or observe policy evaluation.

Threat Model

Threat Status Mitigation
Cloud provider breach Mitigated Provider only receives AES-GCM ciphertext; no key material
ntk server breach Mitigated Server holds no vault keys or file content
Token theft / replay Mitigated DPoP binding ties tokens to device-held private key
Device theft (locked) Mitigated Vault requires password or biometric; Keystore hardware binding
Device theft (unlocked) Partial TTL sweep limits on-device file exposure; vault auto-lock on configurable timeout
Weak user password Out of scope Password strength enforcement is a UX concern; passkeys recommended
OS-level rootkit / malware Out of scope Assumes Android security model integrity; not mitigated at app layer
Network interception Mitigated All transfers over TLS; app-level encryption provides defense-in-depth

Convinced? Or want to verify every claim yourself?