MasterSafe Authenticator: a private, offline authenticator and password vault

My desktop app for one-time codes and passwords: how it works, how the code is built, every feature, and an honest look at how secure it is.

MasterSafe Authenticator logo

MasterSafe Authenticator is a desktop app I build in .NET 10 for Windows and Linux. It generates the one-time codes (TOTP and HOTP) that protect your accounts and keeps them, with your passwords, in an encrypted vault on your own computer. It needs no account and no cloud, and it sends no telemetry. The only network connection it ever makes is to a backup server you choose yourself.

What the name promises and what it does not: no software is unbreakable. This page explains what MasterSafe protects, how, and where the limits are.

297

automated test methods in the repository

27 of 41

OWASP ASVS checks met in my self-assessment

0

telemetry, accounts or log files

Everything it does

All the features of the app, grouped by what they are for. The interface is in English for now.

Codes

TOTP and HOTP

RFC 6238 and RFC 4226, with SHA-1, SHA-256 or SHA-512 and 6 or 8 digits. Add accounts from an otpauth:// link or a QR code image: drag it onto the window or choose the file.

Passwords

Password vault

KeePass-style entries with a password generator. Copied codes and passwords are cleared from the clipboard after 30 seconds.

Passwords

Folders and bulk actions

A folder tree for passwords, with an icon for each folder chosen from a set of 24. Create, rename, move and delete folders, and select several entries to move or delete them together.

Passwords

Attached files

Attach files to an entry, up to 5 MiB each and 50 MiB per vault. They stay encrypted inside the vault and are included in recovery backups.

Unlock

Three ways to unlock

Master password (Argon2id), Windows Hello or a FIDO2 security key, tested with a Thales SafeNet key. Each one is a separate key slot.

Session

Auto-lock

The vault locks after the idle time you choose. Locking wipes the key and the decrypted data from memory.

Backup

Encrypted backups

.sauth backups to a local folder or a WebDAV server such as Nextcloud or ownCloud, over https only. There is no plaintext export.

Recovery

Recovery key

A recovery key and recovery backups get your data back if you forget the master password. The app can generate the passphrase for the key. There is no backdoor.

Vaults

Vaults page

Shows where your files live, opens any vault file (a USB stick, another folder), and archives or deletes old vaults after a confirmation.

Import

KeePass import

Reads KeePass and KeePassXC XML or CSV exports. Groups become folders, and files attached in XML exports come along. A summary comes first and nothing is added until you confirm.

Releases

Verifiable downloads

Every file has a SHA-256 checksum and an ML-DSA-65 post-quantum signature, and a small tool checks them all in one step.

Desktop

Everyday use

System tray, light and dark themes, in-app help, and settings that are remembered between runs.

How the vault protects your data

Your accounts and passwords are encrypted with one random 256-bit data key. That key is never stored as it is. It is kept once per unlock method, in a slot, wrapped under a key that only that method can produce. So changing the master password, or adding Windows Hello, never re-encrypts the vault.

Key hierarchy of the vault Master password Argon2id + salt Windows Hello signature + HKDF FIDO2 security key hmac-secret + HKDF Password slot Hello slot Security key slot Random 256-bit data key wiped from memory on lock Your accounts and passwords AES-256-GCM
Each unlock method opens its own slot, and every slot leads to the same data key. Wrapping uses AES-256-GCM.
  • Everything is authenticated. AES-256-GCM protects the contents, and the header and slots are bound in too, so pieces of one vault cannot be swapped into another and a slot cannot be relabelled.
  • Saves are atomic. The new file is written and flushed first, then swapped in, and the previous version stays as vault.sauth.bak.
  • Files are treated as untrusted. Argon2 parameters, file sizes (100 MiB for vaults and backups), decompressed size (96 MiB) and attached files (5 MiB each, 50 MiB in total) are limited before any work starts, so a crafted file cannot exhaust memory.
  • A wrong key never overwrites. A save first proves the key can open the existing vault.

How the code is built

The solution is C# on .NET 10 with an Avalonia 12 (opens in a new tab) MVVM interface, split into small projects. Dependencies point one way: the domain knows nothing about the screens, and every cryptographic operation lives in one library. Windows-only code sits behind #if WINDOWS, and unlock methods implement a single interface, ISecretProvider, so the vault format does not depend on a platform.

Layers of the MasterSafe solution INTERFACE MasterSafe.App Avalonia 12 desktop app MasterSafe.Cli release verification tool SERVICES Backup backups, WebDAV Platform Hello, FIDO2, tray QR QR codes SECURITY Crypto Argon2id, AES-GCM, slots PostQuantum ML-KEM, ML-DSA DOMAIN Core TOTP, HOTP, Base32, otpauth, accounts, passwords
Dependencies point downward. Core has no dependencies at all.

Each project has one job, and you can read all of it on GitHub:

ProjectWhat it does
MasterSafe.Core (opens in a new tab)RFC 6238 TOTP, RFC 4226 HOTP, Base32, otpauth parser, account, password and attachment models, KeePass import
MasterSafe.Crypto (opens in a new tab)Argon2id, AES-256-GCM, vault format 3 with key slots, attachment container, atomic file repository, bounded GZip
MasterSafe.PostQuantum (opens in a new tab)ML-KEM-768, hybrid ECDH P-384 + ML-KEM-768, ML-DSA-65 release signing
MasterSafe.Backup (opens in a new tab)Password and recovery-key backups, local folder and WebDAV providers
MasterSafe.Platform (opens in a new tab)Windows Hello and FIDO2 unlock providers, system tray
MasterSafe.QR (opens in a new tab)QR decoding and generation with ZXing.Net and SkiaSharp
MasterSafe.App (opens in a new tab)The Avalonia desktop interface: views, view models and services
MasterSafe.Cli (opens in a new tab)Release tools: verify-release, verify, fingerprint, keygen, sign

By size, the app is about 12,400 lines of C# and XAML in src, with another 6,000 lines of tests. The tests cover RFC vectors, vault security and the view models. MasterSafe.Data is a persistence library the app does not use at present.

Lines of code per project MasterSafe.App MasterSafe.App: 6,453 6,453 MasterSafe.Tests MasterSafe.Tests: 6,009 6,009 MasterSafe.Core MasterSafe.Core: 1,449 1,449 MasterSafe.Crypto MasterSafe.Crypto: 1,403 1,403 MasterSafe.Backup MasterSafe.Backup: 799 799 MasterSafe.Data MasterSafe.Data: 656 656 MasterSafe.Platform MasterSafe.Platform: 610 610 MasterSafe.PostQuantum MasterSafe.PostQuantum: 545 545 MasterSafe.QR MasterSafe.QR: 260 260 MasterSafe.Cli MasterSafe.Cli: 178 178
Lines of .cs and .axaml files per project, blank lines included, at version 1.3.1. Tests are shown in grey.

Here is a small, real example of the rule that files are untrusted. Argon2 parameters come from the vault file, so Models.cs (opens in a new tab) checks them before any memory is allocated:

public void Validate()
{
    if (DegreeOfParallelism is < 1 or > MaxParallelism
        || Iterations is < 1 or > MaxIterations
        || MemorySizeKib < 8 * DegreeOfParallelism
        || MemorySizeKib > MaxMemorySizeKib
        || KeyLength != 32)
    {
        throw new InvalidDataException("The key-derivation parameters in this file are outside the accepted range.");
    }
}

Other good starting points are VaultService.cs (opens in a new tab) for the slots, HybridKemProvider.cs (opens in a new tab) for the hybrid scheme and Fido2HmacSecretProvider.cs (opens in a new tab) for security keys. No cryptographic algorithm is written by hand: they come from .NET, the operating system and a published Argon2 library.

If you forget the master password

There is no backdoor, so a lost password cannot be reset. Instead you prepare for it. On the Recovery page you create a recovery key, and now and then a recovery backup that only that key can open. Any device with the public key can write one, and no password is needed to create it. You can choose the passphrase yourself or let MasterSafe generate one: 30 random characters without look-alike letters, shown once so you can write it down.

How a recovery backup is encrypted Recovery public key the app keeps only this Hybrid encapsulation ECDH P-384 + ML-KEM-768 Shared secret HKDF-SHA-384 Random data key wrapped by the shared secret recovery-*.sauth whole vault, AES-256-GCM
Only the private recovery key can open the backup. It lives in a .msrk file protected by a passphrase of at least 12 characters, and you keep that file away from this computer.
  • First, try another unlock method. Windows Hello or a security key may still open the vault.
  • Then, use "Forgot your master password?" on the sign-in screen to restore a recovery backup into a new vault.
  • Last, start a new vault. The old one moves to an archive, it is never deleted, and it can be opened if the password turns up.

What about quantum computers?

Encrypted data stolen today could be kept and attacked later, so each part of the app was looked at separately. ML-KEM and ML-DSA come from .NET 10 and the operating system (Windows CNG, or OpenSSL 3.5+ on Linux). If the provider is missing, the code stops instead of producing weak output.

PartImpact of a quantum computerPosition
Vault at restShor does not apply. Grover cuts AES-256 to about 128 bitsSafe with a strong passphrase
Recovery backupsPlain RSA or elliptic curves would be brokenHybrid ECDH P-384 + ML-KEM-768: stays secret if either one survives
Release filesRSA or ECDSA signatures could be forgedSigned with ML-DSA-65 (FIPS 204)
Security key slotSymmetric HMAC-SHA-256 inside the keyNot affected the way RSA is; the key and its PIN are still needed
Windows Hello slotUses an RSA key in the TPMNot yet post-quantum. Safe against someone holding only the vault file. If this matters to you, do not add Hello

So how secure is it?

The honest answer depends on who is attacking and when. This is the threat model from the repository:

AttackerCan they read the vault?Why
Steals the vault or a backupOnly by guessing the master passwordAES-256-GCM and Argon2id. A long passphrase is what matters
Edits the vault fileNoEverything is authenticated, so a damaged file fails closed
Crafts a hostile fileNoParameters, sizes and decompression are limited first
Watches the networkNoOnly ciphertext leaves, and WebDAV requires https
Malware while the vault is lockedNoNothing on disk opens the vault without the password or the Hello prompt
Has your security key but not its PINNoThe key needs its PIN and a touch, and too many wrong PINs lock it
Has your computer and Windows PINYes, through Windows HelloHello is as strong as your PIN or biometrics
Gets a file you saved out of an entryYes, that fileA saved attachment is a normal file on disk, outside the vault. Delete it when you are done
Malware while the vault is unlockedYesSoftware running as you can read an unlocked app. Auto-lock only shortens the window

Slowing down password guessing

If someone steals the file, every guess at the master password has to pay the cost of Argon2id. The defaults are 128 MiB of memory, 3 passes and 4 lanes, against an OWASP minimum of 19 MiB and 2 passes. New master passwords need at least 12 characters.

Argon2id memory per password guess OWASP minimum OWASP minimum: 19 MiB 19 MiB MasterSafe MasterSafe: 128 MiB 128 MiB
More memory per guess makes large-scale cracking hardware more expensive. It helps a good passphrase but cannot rescue a weak one.

Self-assessment against OWASP ASVS

I assessed the app against the parts of OWASP ASVS 4.0.3 (opens in a new tab) that apply to an offline desktop program, and the full checklist (opens in a new tab) is public. It is a self-assessment, not a certification.

OWASP ASVS 4.0.3 checks by result Met Met: 27 27 Partial Partial: 7 7 Gap Gap: 4 4 Not applicable Not applicable: 3 3
The 41 rows of the ASVS table in the checklist. Met means implemented and covered by tests or CI.

Known limits

These are not hidden in small print. The repository lists them too:

  • No independent security review yet.
  • New master passwords are not checked against breached password lists, and there is no lock-out delay after wrong attempts in the app.
  • The Windows installer is not Authenticode-signed, so SmartScreen warns about it. The ML-DSA-65 signature is how you verify it.
  • Windows clipboard history may capture a copied value before it is cleared.
  • The master password you type is a .NET string, which cannot be wiped from memory until it is collected.
  • Hardware unlock works on Windows only, and only one security key per vault for now. On Linux the master password is the way in.
  • The Linux package is built and tested in CI, but it has not been tried on a real Linux desktop yet.

In short: with a long passphrase, a stolen vault or backup is very well protected, and the network never sees your secrets. It cannot protect you from malware running as you while the vault is open. Treat it as a carefully built, openly documented personal project that has not had an outside audit yet.

How every release is checked

Many security problems in practice come from outdated parts, so the pipeline does this work on every change. A known vulnerable package fails the build, CodeQL and Gitleaks run on each push, Dependabot proposes updates, and CI generates an SBOM that is attached to the release. Each release also bundles the newest patched .NET runtime available when it is built.

From a code change to a signed release Every push GitHub Actions Build and test Windows + Linux Package audit build fails if vulnerable CodeQL + Gitleaks code and secret scans Version tag self-contained builds ML-DSA-65 + SHA-256 checksum
Top row and code scans run on every change. A version tag then builds, signs and prepares a draft release.

Download and verify

Get version 1.3.1 from the releases page (opens in a new tab): the installer for Windows 10 and 11 (x64), or the package for Linux (x64 or arm64). No .NET installation is needed. Download every file into one folder, including masterSafe-release.pub and the MasterSafe-Cli tool, and run:

MasterSafe-Cli-1.3.1-win-x64.exe verify-release . masterSafe-release.pub

Every file must report signature valid, checksum ok, and the key fingerprint printed first must be:

28ad8deb1624d6f04fe9100e25edb2666ad904e02824af14ef2fe6c8d2a74b8a

The full steps, including how to build the checker from source, are in the README (opens in a new tab).

License and reporting a problem

MasterSafe Authenticator is freeware for personal, non-commercial use. The source is available for review and personal use, but it is not open source: commercial use and distributing modified versions are not permitted. See the license (opens in a new tab). Third-party components keep their own licenses, listed in the notices (opens in a new tab).

If you find a security problem, please use private reporting on GitHub (opens in a new tab) instead of a public issue.

Read more in the repository