Skip to content

Latest commit

 

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Human Authenticator 🔒

A tool that lets two people verify — over a phone call or a video meeting — that the person on the other side really is who they claim to be. It takes the 2FA idea from login systems and applies it to human-to-human identity verification.

How it works

  1. Two people meet in person and agree on a shared secret code.
  2. Each of them stores that code locally, under the other person's name.
  3. When verification is needed, both run the program. It derives a 6-digit TOTP code (RFC 6238 — the same algorithm behind Google Authenticator) from the shared secret and the current 30-second time window.
  4. If the same code appears on both screens, the person on the other side is genuine.

Because the codes are standard TOTP, the other side does not have to install this program. When adding a contact you can export a QR code and they can scan it into any authenticator app — Google Authenticator, 1Password, Authy — and read the same 6 digits from their phone.

The secret code never travels over the network; it stays on both machines in an encrypted local database.

Motivation

I started this project after the recent wave of deepfake meeting incidents.

Almost every project addressing this problem works by detecting artifacts and glitches in the video stream. That is a one-way mechanism: on a false negative — when the system mistakes a real person for a deepfake — there is no second way to verify anyone.

Human Authenticator provides a secondary, independent mechanism instead. It never looks at the video; it looks at a secret the two people shared beforehand.

Requirements

  • Python 3.9+
  • colorama, cryptography, pyotp, qrcode, pillow (see requirements.txt)

Installation

git clone https://github.com/zer0x711/human_authenticator
cd human_authenticator
pip install -r requirements.txt

First run: create the database

python3 authenticator.py --setup

This asks for a password and encrypts your local database (persons.json) with it. Every command from then on will prompt for that password.

Caution

This password is yours alone and is completely separate from the codes coworkers share with each other. Its only job is to encrypt the local database.

If you lose it, the database cannot be recovered — you will have to establish every stored code again from scratch.

Adding a contact

Coworkers meet in person and agree on a shared secret code. Both sides store that code under the other person's name, so both machines derive the same verification code at the same time.

python3 authenticator.py --add ahmet

The command asks for your database password first, then for the secret code you share with that person. Finally it offers to export a QR code:

pass>
secret key> our-shared-code
Do you want to create a qr? (y/n): y
File name (x.png): ahmet.png

The QR encodes a standard otpauth://totp/... provisioning URI, so the other person can scan ahmet.png straight into their authenticator app instead of installing this tool.

Caution

The generated PNG contains the shared secret in plain form — anyone who gets the image can produce your verification codes. Hand it over in person, then delete it. Never commit it to the repository.

Tip

Think of these codes as private message channels. Using a separate code for every person you talk to is the single most important security practice: if one code leaks, only your verification with that one person is affected.

Usage

Listing stored contacts

python3 authenticator.py -l

Showing your code

python3 authenticator.py -a ahmet
Authenticating: ahmet
103125

Six digits, refreshed every 30 seconds. Read them out to the other person and compare — they will see the same code, whether they run this program or scan the QR into an authenticator app. Press Ctrl+C to exit.

Checking someone else's code

Instead of comparing by eye, let the other person read their code out and type it in:

python3 authenticator.py -a ahmet -v
Authenticating: ahmet
key> 103125
True

True means the code is genuine for that contact right now, False means it is not. The prompt keeps asking, so you can check several codes in a row; Ctrl+C exits.

Note

-v works together with -a <name> — it needs to know whose code to check. On its own it just prints the help text.

Command reference

Command Description
--setup Creates and encrypts the database (one-time)
-l, --list Lists stored contacts
--add <name> Adds a new contact, optionally exporting a QR code
-a, --authenticate <name> Shows the live verification code for that person
-a <name> -v, --verify Prompts for a code and checks it against that contact
-h, --help Help

Security notes

  • The database is encrypted with AES-256-GCM. The key is derived from your password using PBKDF2-HMAC-SHA256 (600,000 iterations, random salt); the password itself is never written to disk.
  • GCM is authenticated encryption: if persons.json is tampered with on disk, the program fails loudly instead of silently accepting corrupted data.
  • Password input is not echoed to the screen (getpass).
  • Codes follow RFC 6238 (TOTP) rather than a homegrown scheme, so the construction is a standard, widely reviewed one — and it interoperates with existing authenticator apps.
  • Verification codes are never transmitted or stored; they are recomputed from the secret code and the clock every time.
  • An exported QR image carries the shared secret. Treat the PNG like the secret itself: hand it over in person and delete it afterwards.

Threat model

What it assumes

  • The two people met in person and exchanged the secret without anyone observing it.
  • Both endpoints are trustworthy — no malware, no keylogger, no attacker with an unlocked session on either machine.
  • Both system clocks are roughly correct.

If any of these does not hold, the guarantees below do not hold either.

What it protects against

  • Deepfaked video and cloned voice. The check never looks at the video or listens to the audio, so a perfect deepfake gains the attacker nothing: it cannot produce the code.
  • A wrong answer from video-based detection. This is a second, independent channel, so a real person wrongly flagged as a deepfake still has a way to prove who they are.
  • Spoofed accounts, numbers and display names. Impersonating an identity does not impersonate the shared secret.
  • An eavesdropped or hostile channel. The secret is never transmitted. Codes expire in 30 seconds, so a recorded code is worthless later.
  • A stolen laptop. The contact database is encrypted at rest; without the password it reveals neither names nor secrets.

What it does NOT protect against

  • A live relay (man-in-the-middle). This is the important one. Whoever reads their code out loud first hands a valid code to the listener. An attacker sitting between two calls can hear A's code and repeat it to B within the same 30-second window, and both sides will think they verified each other.

    Reduce it, but understand you are not eliminating it: have both sides say the code at the same moment, or split it — A reads the first three digits, B reads the last three. A real fix needs a challenge-response exchange where the answer is never spoken in full; that is not implemented today.

  • A compromised machine. Malware on either endpoint can read the secret from memory while the program runs, or capture the database password as it is typed.

  • A leaked secret. Anyone holding the shared secret — from an exported QR image, a screenshot, a photo of a notebook — produces exactly the same codes you do. There is no way to tell the two apart. Rotate the contact if you suspect this.

  • Guessing, at scale. A code is six digits: a single guess has a one-in-a-million chance per window, and --verify does not rate-limit attempts. This matters only if you let someone try repeatedly; a human on a call does not get that many tries.

  • Someone talking you out of the check. "My camera is broken, let's skip it" is still the cheapest attack on any verification scheme. The tool cannot help if it is not used.

Known limitations

  • Codes change every 30 seconds. A code read out just before a window boundary may already be stale by the time the other side checks it. If that happens, wait for the next window and compare again.
  • Clocks must agree. TOTP counts 30-second windows from the Unix epoch in UTC, so time zones do not matter — but the two clocks still have to agree. If a machine's clock has drifted, the codes will not match; keeping system time synced (NTP, which is the default on macOS, Windows and most Linux distros) is enough.
  • Each contact needs its own secret. Reusing one secret across several people means any of them can impersonate the others to you.

Releases

Packages

Contributors

Languages