Security architecture

Security is the product, not the garnish.

User-owned data, device-linked unlock events, no default cloud dependency, and recovery logic that preserves — not sabotages — the trust model. Every boundary is explicit and every session opens intentionally.

Privacy principle

You should own your data, not rent it from a platform.

Access principle

Sessions should open intentionally and close intentionally.

Recovery principle

Recovery should exist without becoming a backdoor.

AI principle

Assistant workflows must respect the same trust boundary as the vault.

Layer 1

Vault encryption — AES-256-GCM + ChaCha20-Poly1305.

Every secret stored in Phantom Obscura is encrypted at rest using a dual-cipher strategy. AES-256-GCM is the primary cipher; ChaCha20-Poly1305 is available as a software-only alternative for devices without AES-NI. Both use authenticated encryption — tampering with ciphertext is detected before any plaintext is returned.

// AES-256-GCM encrypt with authenticated associated data // From Phantom Obscura — GiblexVault.Security.ZK.Primitives private static byte[] EncryptWithAesGcm( AesGcm aes, byte[] nonce, byte[] aad, byte[] plain) { var tag = new byte[16]; var ct = new byte[plain.Length]; aes.Encrypt(nonce, plain, ct, tag, aad); // Output: ciphertext | tag var result = new byte[ct.Length + tag.Length]; Buffer.BlockCopy(ct, 0, result, 0, ct.Length); Buffer.BlockCopy( tag, 0, result, ct.Length, tag.Length); return result; }
// Cipher-suite dispatch — AES-GCM or XChaCha20 // XChaCha20-Poly1305 via NSec for non-AES-NI devices public static byte[] Encrypt( CipherSuite s, byte[] key, byte[] nonce, byte[] aad, byte[] plain) { if (s == CipherSuite.XChaCha20Poly1305) { using var k = Key.Import( AeadAlgorithm.XChaCha20Poly1305, key, KeyBlobFormat.RawSymmetricKey); var ct = new byte[plain.Length + AeadAlgorithm.XChaCha20Poly1305.TagSize]; AeadAlgorithm.XChaCha20Poly1305 .Encrypt(k, nonce, aad, plain, ct); return ct; } using var aes = new AesGcm(key.AsSpan(), 16); return EncryptWithAesGcm(aes, nonce, aad, plain); }
Layer 2

Key derivation — Argon2id key material hardening.

The user's key material never touches the vault directly. It is stretched through Argon2id — a memory-hard, timing-attack-resistant KDF that makes brute-force infeasible even against offline captures. A per-vault random salt ensures no two vaults produce the same derived key.

// Argon2id key derivation via Isopoh.Cryptography // From Phantom Obscura — per-vault salt, tunable cost public static byte[] DeriveKey( ReadOnlySpan<byte> password, ReadOnlySpan<byte> salt, KdfParams p) { var cfg = new Argon2Config { Type = Argon2Type.HybridAddressing, Version = Argon2Version.Nineteen, TimeCost = Math.Max(1, p.Ops), MemoryCost = Math.Max(8, p.MemMiB) * 1024, Lanes = Math.Max(1, p.Parallelism), Threads = Math.Max(1, p.Parallelism), Password = password.ToArray(), Salt = salt.ToArray(), HashLength = 32 }; using var hash = new Argon2(cfg).Hash(); return hash.Buffer[..32].ToArray(); }
// Memory is zeroed after derivation — no residue finally { CryptographicOperations.ZeroMemory( cfg.Password); CryptographicOperations.ZeroMemory( cfg.Salt); } // The derived key feeds AEAD encryption. // Key material is never stored — not hashed, // not in a config, not in telemetry. // If the user loses it, Recovery is the // only restoration path.
Layer 3

USB key binding — physical session boundary.

Phantom Key binds vault access to a physical USB device. The system detects paired drives by volume serial number and GUID through WMI queries. Ed25519 keypairs sign vault headers and container manifests using NSec.Cryptography. The vault can require the key's presence before any unlock or session extension — removing the USB device blocks access.

// USB volume binding — detects paired removable drives // From Phantom Key — PhantomKey.Core.Usb public bool IsBoundDevicePresent( UsbBindingConfig cfg) { if (!cfg.Enabled) return true; var found = EnumerateRemovableVolumes() .ToList(); return found.Any(v => cfg.AllowedVolumeSerials.Contains( v.VolumeSerial) || cfg.AllowedVolumeGuids.Contains( v.VolumeGuid)); } // WMI query for removable drives (DriveType = 2) using var searcher = new ManagementObjectSearcher( "SELECT DeviceID, VolumeSerialNumber " + "FROM Win32_LogicalDisk WHERE DriveType = 2");
// Ed25519 via NSec.Cryptography // Signs vault headers and container manifests public static (byte[] pub, byte[] priv) Generate() { using var k = Key.Create( SignatureAlgorithm.Ed25519, new KeyCreationParameters { ExportPolicy = KeyExportPolicies.AllowPlaintextExport }); return ( k.Export(KeyBlobFormat.RawPublicKey), k.Export(KeyBlobFormat.RawPrivateKey)); } public static bool VerifyString( string msg, byte[] sig, byte[] pub) { var pk = PublicKey.Import( SignatureAlgorithm.Ed25519, pub, KeyBlobFormat.RawPublicKey); return SignatureAlgorithm.Ed25519 .Verify(pk, Encoding.UTF8.GetBytes(msg), sig); }
Layer 4

Certificate system — signed policy enforcement.

Giblex uses a local certificate authority model. A root ECDSA certificate is loaded from the device or from an embedded resource. Security policies and manifests are verified against this root at runtime using X.509 certificate-based ECDSA validation. No external CA is trusted by default. Unsigned or tampered policies are rejected before they can take effect.

// Root trust — certificate-based policy verification // From Phantom Attestor — PhantomVault.Core.Services public static ECDsa CreateRootVerifierFromCert( string certPath) { if (!File.Exists(certPath)) throw new FileNotFoundException( "Root certificate not found", certPath); var certBytes = File.ReadAllBytes(certPath); // Dispose cert after extracting public key using var cert = X509CertificateLoader.LoadCertificate( certBytes); return cert.GetECDsaPublicKey() ?? throw new InvalidOperationException( "Certificate does not contain " + "an ECDSA public key."); }
// Signed policy enforcement at runtime // Policies cannot load without valid ECDSA signature public PolicyService( ECDsa? rootVerifier, string policyJson, bool requireSignature = true) { if (HasSignature(policyJson)) { if (rootVerifier == null) throw new ArgumentNullException( nameof(rootVerifier)); PolicyVerifier.VerifyPolicy( policyJson, rootVerifier); _signatureVerified = true; } else if (requireSignature) throw new CryptographicException( "Policy signature required."); _policy = ObscuraPolicy .FromVerifiedJson(policyJson); _engine = new PolicyEngine( _policy, rootVerifier); }
Layer 5

Policies — tiered authentication gates.

Each authentication request is evaluated against a tiered policy engine with three independent gates: Windows Hello user verification freshness, Phantom PIN validation, and USB device binding. Policy tier levels — Low, Medium, High, Critical — determine which gates are required. Policies are ECDSA-signed and verified at load time — unsigned policies are rejected.

// Tiered authentication policy — per-request evaluation // From Phantom Key — PhantomKey.Core.Policy public enum PolicyTier { Low, Medium, High, Critical } public sealed record AuthRequest( string RpId, PolicyTier PolicyTier, bool RequireUsb, bool RequireHelloUv, bool RequirePhantomPin); public sealed record PolicyResult( bool Allowed, string Code, string Detail);
// Three-gate policy enforcement // UV freshness, Phantom PIN, USB binding public PolicyResult Evaluate( AuthRequest req, IUsbBinding usb, ILocalPin pin) { // Gate 1 — Windows Hello UV freshness if (req.RequireHelloUv) { var age = DateTimeOffset.UtcNow - _lastUvTimestamp; if (age.TotalSeconds > _cfg.UvFreshnessSeconds) return new(false, "UV_STALE", "User verification expired."); } // Gate 2 — USB device binding if (req.RequireUsb || req.PolicyTier >= PolicyTier.High) { if (!usb.IsBoundDevicePresent( _cfg.UsbBinding)) return new(false, "USB_REQUIRED", "Bound USB not present."); } return new(true, "OK", "Policy satisfied."); }
Layer 6

Containers — isolated encrypted volumes within a vault.

A single vault can contain multiple containers, each with its own encryption key, policy, and access scope. Containers allow users to compartmentalise secrets — one for financial credentials, one for medical records, one for work — and unlock only what is needed. Each container is independently encrypted: compromising one does not expose others.

// Zero-knowledge container — per-container CEK via HKDF // From Phantom Obscura — GvContainerZk public static async Task CreateAsync( string path, byte[] masterKey, EngineOptions opts) { var kdf = new KdfParams { Salt = RandomNumberGenerator .GetBytes(32), Ops = opts.ArgonOpsLimit, MemMiB = opts.ArgonMemMiB, Parallelism = opts.ArgonParallelism }; // Container encryption key via HKDF-SHA256 var cek = Hkdf.Sha256(masterKey, kdf.Salt, Encoding.UTF8.GetBytes( "container::cek")); // Write: magic | header | Ed25519 sig | TOC await using var fs = File.Create(path); await fs.WriteAsync(Magic); CryptographicOperations.ZeroMemory(cek); }
// Per-entry data encryption key wrapping // Each file gets a unique DEK wrapped by the CEK var dek = RandomNumberGenerator.GetBytes(32); // Wrap DEK under container key using AEAD var wrapped = KeyWrap.WrapAead( suite, cek, dek, header); // Encrypt file content with DEK var nonce = RandomNumberGenerator.GetBytes( Aead.GetSuite(suite).NonceSize); var ct = Aead.Encrypt( suite, dek, nonce, header, paddedPlain); // Paranoid mode: entry names are HMAC-SHA256 // hashed, file sizes padded to 64 KB boundary. // An observer sees uniform noise. toc.Entries.Add(new Entry( name, realLen, offset, ct.Length, wrapped)); CryptographicOperations.ZeroMemory(dek);
Layer 7

Decoy vaults — plausible deniability by design.

Phantom Attestor supports active decoy vaults: when suspicious behaviour is detected, the system activates a convincing fake credential database. Decoy entries include realistic passwords, WiFi keys, credit cards, and API tokens generated for well-known sites. The decoy vault looks indistinguishable from a real one — an attacker wastes time on plausible fakes while the real vault remains protected.

// Decoy vault activation — on suspected compromise // From Phantom Attestor — DecoyVaultService public async Task<VaultDatabase> ActivateDecoyVaultAsync() { _logger?.LogCritical( "ACTIVATING DECOY VAULT — " + "Suspected security compromise"); var decoys = _generator .GenerateDecoyCredentials( _options.CredentialCount); var groups = OrganizeCredentialsIntoGroups(decoys); _decoyDatabase = new VaultDatabase { VaultName = "Personal Vault", Description = "Secure Password Manager", Created = DateTime.UtcNow.AddDays( -new Random().Next(180, 730)), Groups = groups }; _isDecoyActive = true; return _decoyDatabase; }
// Realistic fake credential generation // Passwords, WiFi, credit cards, API keys public List<Credential> GenerateDecoyCredentials(int? count) { int n = count ?? _rng.Next(15, 31); var creds = new List<Credential>(); int passwords = (int)(n * 0.6); int wifiCount = _rng.Next(2, 5); int creditCards = _rng.Next(1, 3); int apiKeys = _rng.Next(2, 4); for (int i = 0; i < passwords; i++) creds.Add(GeneratePasswordEntry()); for (int i = 0; i < wifiCount; i++) creds.Add(GenerateWiFiEntry()); // Each entry uses common sites, realistic // usernames, and proper password patterns. // An attacker wastes time on plausible fakes. return creds; }
Layer 8

Recovery — HKDF key wrapping with no backdoor.

Phantom Recovery wraps the vault master key inside an AES-GCM envelope, keyed by an HKDF-derived key encryption key. The recovery key is 32 random bytes generated locally and never transmitted. The KEK uses HKDF-SHA256 with domain separation, ensuring the recovery key serves only its intended purpose. There is no Giblex-held master key, no server-side recovery token, and no reset email.

// Recovery key wrap — HKDF + AES-GCM envelope // From Phantom Obscura — Recovery module public static byte[] WrapMasterKey( byte[] masterKey, byte[] recoveryKey) { var kek = Hkdf.Sha256( recoveryKey, new byte[32], Encoding.UTF8.GetBytes("rk->kek")); var nonce = RandomNumberGenerator .GetBytes(12); using var aes = new AesGcm(kek.AsSpan(), 16); var tag = new byte[16]; var ct = new byte[masterKey.Length]; aes.Encrypt(nonce, masterKey, ct, tag); // Output: nonce | ciphertext | tag return Concat(nonce, ct, tag); }
// Recovery unwrap — only the recovery key can // reconstruct the KEK and decrypt the master key public static byte[] UnwrapMasterKey( byte[] wrapped, byte[] recoveryKey) { var kek = Hkdf.Sha256( recoveryKey, new byte[32], Encoding.UTF8.GetBytes("rk->kek")); var nonce = wrapped[..12]; var ct = wrapped[12..^16]; var tag = wrapped[^16..]; var plain = new byte[ct.Length]; using var aes = new AesGcm(kek.AsSpan(), 16); aes.Decrypt(nonce, ct, tag, plain); return plain; } // No server-held key, no Giblex backdoor. // Recovery key is generated locally and // never transmitted. If lost, the vault // is irrecoverable by design.
Layer 9

Integrity verification — tamper-evident audit log.

Phantom Examiner maintains a cryptographic audit trail. Every vault operation — unlock, entry read, export, policy change — is hashed into a Merkle chain. If any log entry is altered or removed, the chain breaks. This gives users and auditors verifiable evidence of what happened and when, without exposing the secrets themselves.

// Audit log entry — hash-linked chain // Tamper with any entry and the chain breaks public sealed record AuditEntry { public long Sequence { get; init; } public DateTime Timestamp { get; init; } public string Action { get; init; } public string TargetId { get; init; } public byte[] PrevHash { get; init; } public byte[] EntryHash { get; init; } public byte[] ComputeHash() { var payload = Encoding.UTF8.GetBytes( $"{Sequence}|{Timestamp:O}" + $"|{Action}|{TargetId}"); var combined = new byte[ PrevHash.Length + payload.Length]; PrevHash.CopyTo(combined, 0); payload.CopyTo(combined, PrevHash.Length); return SHA256.HashData(combined); } }
// Chain verification — detect tampering public static bool VerifyChain( IReadOnlyList<AuditEntry> log) { for (int i = 1; i < log.Count; i++) { var expected = log[i - 1].EntryHash; var actual = log[i].PrevHash; if (!expected.SequenceEqual(actual)) return false; // chain break var recomputed = log[i].ComputeHash(); if (!recomputed.SequenceEqual( log[i].EntryHash)) return false; // hash tampered } return true; } // Log entries reference vault operations // by ID, never by content. The audit trail // proves what happened without revealing // what was inside.
Layer 10

Secure memory — wipe after use, no lingering secrets.

Decrypted secrets, derived keys, and session tokens are held in pinned, non-pageable memory and overwritten with zeros the moment they leave scope. This prevents cold-boot attacks, swap-file leaks, and crash-dump exposure. The pattern is enforced at the framework level so individual features cannot accidentally skip it.

// SecureBuffer — pinned + zeroed on dispose // Prevents swap-file and crash-dump leakage public sealed class SecureBuffer : IDisposable { private readonly byte[] _data; private GCHandle _pin; private bool _disposed; public SecureBuffer(int length) { _data = new byte[length]; _pin = GCHandle.Alloc( _data, GCHandleType.Pinned); } public Span<byte> Span => _disposed ? throw new ObjectDisposedException( nameof(SecureBuffer)) : _data; public void Dispose() { if (_disposed) return; CryptographicOperations .ZeroMemory(_data); _pin.Free(); _disposed = true; } }
// Usage pattern — key material never lingers public void DecryptAndProcess( byte[] blob, byte[] vaultKey) { using var keyBuf = new SecureBuffer(vaultKey.Length); vaultKey.CopyTo(keyBuf.Span); using var plain = new SecureBuffer(blob.Length); AesGcmHelper.Decrypt( blob, keyBuf.Span, plain.Span); // Process the decrypted data... HandleEntry(plain.Span); // When this block exits, both keyBuf // and plain are zeroed automatically. // No plaintext survives in memory. }
Trust boundaries

Four boundaries that define the architecture.

01 · Device boundary

Data lives on your device by default. No vague "private cloud" — local ownership comes first.

02 · Device boundary

Phantom Key acts as a physical trust anchor for session unlock and controlled access events.

03 · Recovery boundary

Recovery is a first-class product concern with dedicated architecture, not an afterthought bolted on later.

04 · Intelligence boundary

Giblex Assistant workflows remain inside the secure architecture. Intelligence does not bypass the vault.

Compliance direction

Serious commitment, honest framing.

  • ISO 27001 and SOC 2 roadmap framing
  • GDPR alignment language for EU expansion
  • Privacy-first jurisdiction awareness
  • Annual audits, threat modelling, and bug bounty direction
These represent our active compliance roadmap and operating direction. Certifications are in progress and will be announced as they are achieved.
Full protection stack

Ten layers, one trust surface.

Layer 10 — Secure memory

Pinned buffers, zero-on-dispose. No plaintext survives in memory after use.

Layer 9 — Integrity & audit

Hash-chained log. Tamper-evident. Proves what happened without revealing what was inside.

Layer 8 — Recovery wrapping

HKDF key wrapping + AES-GCM envelope. Recovery key generated locally. No server-side reset.

Layer 7 — Decoy vaults

Fake credential databases activated on compromise. Realistic entries waste attacker time.

Layer 6 — Containers

Independent encryption per compartment. Unlock only what you need.

Layer 5 — Policies

Tiered policy gates: UV freshness, Phantom PIN, USB binding. Per-request enforcement.

Layer 4 — Certificates

Local CA with ECDSA verification. Policies must be signed. No external trust anchor.

Layer 3 — USB key binding

WMI volume binding + Ed25519 signing. Device paired by serial and GUID. Removal blocks access.

Layer 2 — Key derivation

Argon2id. Memory-hard. Per-vault salt. Key material never stored or transmitted.

Layer 1 — Vault encryption

AES-256-GCM + ChaCha20-Poly1305. Unique nonce per entry. Authenticated encryption.