Inside ATLOCK v4: A Deep Technical Teardown
TL;DR — ATLOCK is a ~3,000-line, single-file Python security suite for Windows that combines OS-level lockdown, NTFS ACL file locking, a Fernet/PBKDF2-encrypted password vault, and webcam-based intruder response — all wrapped in a customtkinter UI and shipped as one .exe. This post breaks down how it's built, why certain decisions were made, and — just as importantly — where the trade-offs are, because a security tool that hides its own weak points isn't a security tool.
🔗 Source: https://github.com/Akhouri-Anmol-Kumar/ATLOCK
🌐 Studio: https://akhouri-anmol-kumar.github.io/Akhouri-systems/
- What ATLOCK actually is
ATLOCK is a Total Security Suite built by solo developer Akhouri Anmol Kumar under the Akhouri Systems banner. It ships as a single PyInstaller .exe — no installer, no setup wizard, no external service dependency — and bundles four subsystems behind one gold-on-black customtkinter interface:
Module What it does
Lockdown Full-screen countdown lock with OS-level input hardening
File Guard NTFS ACL-level file locking — not "hidden," genuinely access-denied
Password Vault Fernet (AES) encrypted local store for credentials/PINs
Intruder Ops Webcam photo/video capture + alarm on failed unlock attempts
What makes this interesting from an engineering standpoint isn't the feature list — it's how much of it lives at the OS boundary rather than in the Python/Tkinter layer, and the honesty of the in-source documentation about where the security model bends.
- Architecture at a glance
The whole app is one process, several background threads, and a handful of JSON files acting as an ad-hoc local database:
ATLOCK_v4.py
├── SecurityHardener → WH_KEYBOARD_LL hook + Task Manager watchdog thread
├── CameraEngine → OpenCV photo/video capture, mutex-guarded
├── SoundEngine → winsound tone sequences (non-blocking)
├── FileGuard / WindowsFileLock → win32security DACL manipulation
├── PasswordVault → PBKDF2-HMAC-SHA256 + Fernet(AES-128-CBC+HMAC)
├── IntruderOps → orchestrator: camera + sound + masked logging
├── AppLockState → 10-hour hard-lockout state machine
├── NotificationManager → 24h auto-purging security event log
└── ATLockApp (CTk) → tab-based UI shell
There's no external server, no telemetry, no network call anywhere in the file — every "smart" behavior is local. That's a deliberate architectural stance: the attack surface is the machine itself, not an API.
Here's the control flow for the two most interesting subsystems:
Wrong Vault Password
Attempt Count
IntruderOps.on_wrong:level=warn
Photo capture + soft beep
Masked entry inNotificationManager
IntruderOps.on_wrong:level=crit
Photo + 10s video + alarm
AppLockState.engage_lock10h
AppHardLockOverlay:fullscreen, ungrabbable
- The crypto layer, line by line
This is where a lot of "security suite" side-projects fall apart — either by rolling their own cipher, or by hashing passwords with unsalted MD5 and calling it a day. ATLOCK's vault doesn't do that. Let's look at what it actually does.
Master password hashing — PBKDF2-HMAC-SHA256, 200,000 iterations, random 16-byte salt per vault:
def hash_secret(s: str, salt: bytes = b"", iterations: int = PBKDF2_ITERATIONS) -> str:
if CRYPTO_AVAILABLE:
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=iterations,
)
return kdf.derive(s.encode("utf-8")).hex()
return hashlib.sha256(salt + s.encode("utf-8")).hexdigest() # fallback only
200k iterations puts this solidly in "resistant to offline brute force on commodity hardware" territory as of 2026 — not Argon2id-tier, but a legitimate, well-understood KDF choice, and notably not the naive sha256(password) you see in a lot of hobby projects.
Entry encryption — every vault entry (label, username, password, notes) is individually Fernet-encrypted with a key derived from the same PBKDF2 pipeline, keyed to the session:
python
def _encrypt_entry(self, entry_plain: dict, key: bytes) -> dict:
plaintext = json.dumps(entry_plain).encode("utf-8")
token = Fernet(key).encrypt(plaintext)
return {"data": token.decode("ascii"), "id": entry_plain.get("id")}
Fernet gives you AES-128-CBC + HMAC-SHA256 authentication and a timestamp, all in one primitive — a good default when you don't want to hand-roll IV management. The vault never keeps a decrypted copy at rest; _session_key lives only in memory and is dropped on lock (lock_session() sets it to None).
Password-change flow re-derives a new salt and re-encrypts every entry rather than re-wrapping the old key — meaning a compromised old master password can't be replayed against new entries:
python
old_key = self._key_for(old_pw)
old_entries = self._decrypt_all(old_key)
new_salt = secrets.token_bytes(16)
new_key = derive_fernet_key(new_pw, new_salt)
self._db["entries"] = [self._encrypt_entry(e, new_key) for e in old_entries]
That's the right call — a lot of vault implementations just re-encrypt the key, which leaves you one leaked old-master-password away from full plaintext recovery even after rotation.
Where it's honestly weaker: encrypt_for_disk
Settings-level secrets (not vault entries — things like capture toggles) go through a separate, weaker path: a machine-bound key with a hardcoded salt:
python
salt = b"atlock-v4-fixed-salt-v1" # fixed salt; key is machine-bound
key = derive_fernet_key(base64.b16encode(machine_bound_key()).decode("ascii"), salt)
machine_bound_key() derives from the Windows MachineGuid, username/domain, and a static string. This is explicitly not meant to resist a determined attacker with local access — it's meant to stop the settings file from being human-readable plaintext if someone browses to %APPDATA%. The source comment says as much: "Not military-grade, but ensures credentials aren't trivially portable." That kind of self-graded threat model in the comments is rarer than it should be in this space — most projects either over-claim or don't say anything at all.
- File Guard: locking files at the NTFS ACL level
This is the part that separates ATLOCK from "rename the file and hide it" utilities. On Windows, FileGuard doesn't obfuscate — it rewrites the file's DACL (Discretionary Access Control List) to explicitly deny Everyone:
python
sd = win32security.GetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION)
dacl = win32security.ACL()
everyone, _, _ = win32security.LookupAccountName("", "Everyone")
dacl.AddAccessDeniedAce(win32security.ACL_REVISION, con.FILE_ALL_ACCESS, everyone)
sd.SetSecurityDescriptorDacl(True, dacl, False)
win32security.SetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION, sd)
This is a legitimate Windows security primitive — the same mechanism enterprise EDR and DLP tools use, just invoked directly via pywin32 instead of a driver. The practical effect: even a user with the file's original NTFS permissions gets PermissionError on open, not just "hidden from Explorer."
Two engineering details worth calling out:
Graceful degradation. If pywin32 isn't installed or the ACL call throws, FileGuard falls back to a rename-based lock (.ATLOCK_.locked). It's strictly weaker — a rename is trivially reversible by anyone who finds the file — but it means the feature doesn't hard-crash on a stripped-down Python environment.
Owner-escapable by design. DACL-based locks are reversible by the file owner or an administrator using icacls/takeown — that's inherent to how NTFS ACLs work, not a bug in ATLOCK. The honest framing here is "keeps casual and even moderately technical intruders out," not "un-crackable," and the README doesn't oversell it as the latter.
- OS-level lockdown: a real WH_KEYBOARD_LL hook
The Lockdown module doesn't just draw a fullscreen Tkinter window — it installs a low-level keyboard hook via ctypes and runs a watchdog thread that kills Task Manager on sight:
python
class SecurityHardener:
_BLOCKED_VK = {0x09, 0x1B, 0x5B, 0x5C, 0x5D, 0x73, 0x79, 0xA4, 0xA5} # Tab, Esc, Win keys, F4, F10...
def _hook_thread_run(self):
WH_KEYBOARD_LL = 13
self._hook_id = user32.SetWindowsHookExW(WH_KEYBOARD_LL, self._hook_cb, hmod, 0)
...
This runs a genuine Win32 message pump on a dedicated thread — necessary because SetWindowsHookExW requires an active message loop to actually intercept events. Doing this correctly (own thread, own GetMessageW loop, careful hook install/uninstall symmetry in engage()/disengage()) is the kind of detail that's easy to get wrong and cause a hung hook that survives process exit. Combining a keyboard hook with a polling watchdog for Task Manager is a defense-in-depth pattern straight out of kiosk-mode software — appropriate here since the goal is literally "make the screen impossible to escape for N minutes," with a single emergency override as the safety valve.
- Intruder Ops: the orchestration layer
Rather than scattering camera/sound/logging calls across the vault and file guard code paths, everything funnels through one class:
python
class IntruderOps:
def on_wrong(self, context_label, attempted_pw, level="warn", ...):
threading.Thread(target=worker, daemon=True).start()
def _respond(self, context, attempted_pw, level, detail, photo_ov, video_ov):
if level == "crit": _sound.critical()
else: _sound.wrong()
if cfg.get("enable_camera", True): camera.capture_photo()
if level == "crit": self._record_blocking(video_path)
notif_mgr.add(..., attempted_passwords=[attempted_pw], ...)
Two things worth noting architecturally:
Everything fires on a background thread, so a slow webcam open (cv2.VideoCapture can block for hundreds of ms) never freezes the Tkinter main loop — a real risk in single-threaded UI frameworks.
A single mutex (_cam_lock) guards the camera across both photo and video paths, preventing the classic "two threads fight over /dev/video0" race that shows up in a lot of hobby camera code.
The masking discipline
Every wrong password that triggers a response is masked before it's ever written to disk or displayed:
python
def mask_password(pw: str) -> str:
if not pw: return "(empty)"
n = len(pw)
if n == 1: return f"{pw[0]}* (1 char)"
return f"{pw[0]}{'*' * min(n-1, 8)} ({n} chars)"
This is a small function, but it's the kind of thing that's genuinely easy to skip under deadline pressure — logging the raw failed attempt is useful for debugging and a real liability if that log ever leaks, since people frequently mistype their real password into the wrong field. Masking at the source, rather than at the display layer, means there's no code path where the plaintext attempt reaches disk at all.
- What I'd flag as an outside reviewer
In the spirit of this being a technical deep-dive and not a press release:
Fixed-salt settings encryption (encrypt_for_disk) is fine for its stated purpose (obfuscation, not confidentiality) but shouldn't be confused with the vault's actual security guarantees — the source comments already draw this line, which is good practice.
DACL locks are owner/admin-reversible by design — this is a Windows ACL property, not a flaw, but it's worth being explicit that File Guard's threat model is "casual/opportunistic access," not "hostile local admin."
The keyboard-hook + Task-Manager-kill combo is powerful enough that antivirus/EDR products will very plausibly flag it (this is called out in the README as a known SmartScreen false positive for unsigned PyInstaller builds) — worth knowing before you distribute a build broadly.
Single-file, single-process design keeps the mental model simple, but also means a crash in the UI thread and a crash in, say, the video-writer thread aren't cleanly isolated from each other — log_exc() swallowing exceptions broadly is a reasonable choice for "never crash the security lock," but it does mean failures are silent unless someone checks .atlock_error.log.
None of these are "gotchas" — they're the normal shape of trade-offs in a solo-developer, no-external-dependency security tool, and the codebase is unusually candid about most of them in its own comments.
- Why this is a good reference project
If you're learning systems-adjacent Python, ATLOCK is a genuinely useful thing to read end-to-end because it touches:
Real Win32 API usage via ctypes and pywin32 (hooks, DACLs, LockWorkStation)
Correct KDF/AEAD usage with cryptography (PBKDF2 → Fernet, not a hand-rolled cipher)
Thread-safe hardware access (webcam mutex, background workers that never block the UI thread)
A local, dependency-free notification/state system built entirely on JSON files
That combination — real OS primitives and correct cryptographic practice — is more instructive than most "security app" tutorials that stop at hashlib.sha256(password).
Links
🔗 Source code: https://github.com/Akhouri-Anmol-Kumar/ATLOCK
🌐 Akhouri Systems: https://akhouri-anmol-kumar.github.io/Akhouri-systems/
Built solo by Akhouri Anmol Kumar. If you read the source and find something worth discussing — better or worse — that's the point of open-sourcing it.
If you found this teardown useful, a star on the repo goes a long way for a solo-dev project.
Repo: https://github.com/Akhouri-Anmol-Kumar/ATLOCK
🌟star it 🙏
ATLOCK
"We Build What Others Forgot To Fix"
Top comments (0)