SnowCode

The third password manager option (syncless)

Password mangers often come in 2 types: online and offline ones.

The online password managers are dependent on a cloud platform, many of them are premium, some of them are self-hostable and free. Offline password managers on the other hand (like Keepass) is only a file of encrypted passwords.

Both of them have their advantages and disadvantages. But there's a third option which is free and doesn't require any database. This option therefore cannot be hacked or database leaked. This option is called "syncless password manager"

How it works

I actually like to call them "password calculators" instead of "password managers" because they aren't actually managing anything. It's just a bunch of math. The code of those is actually very simple.

You can make one of those password calculators in less than 5 lines of code. The way it works is by using the hashing function (a one-way function that creates a "fingerprint" for data)

  1. Retreive the master password, the site name and the username
  2. Hash all of those
  3. (optional) base64 them to have uppercases, special characters, etc. This is only for crappy websites that doesn't understand special characters don't mean security.

Because the hash function cannot be reversed, someone that knows the final output, the username and the site name cannot retrieve the master password. Two people with the same master password on the same site also won't have the same final password either.

The website-specific passwords looks completely random, but they aren't. For instance, this is an example:

snowcode@snowcode:~$ python3 master.py
Username> bob@protonmail.com
Website> codeberg.org
Master password> averysecurepassword567855*
NmEwMGI3NDhlNWUzNzI=

If a single character changes in any of the values, the final password will be completly different

Pros and cons

Pros:

  • Free
  • Universal (because it's calculated, you can get your passwords on any device without leaking your data)
  • Lightweight and easy (no server, no database, nothing)
  • Secure and unique passwords for all sites
  • Respects the stupid rules of some websites about password length, special characters, etc.

Cons:

  • Master password cannot be changed without changing all the passwords
  • Master password is key, if it gets corrupted, all your passwords might also be.

Making it even more secure

If you want to improve the security even more, you can do the following:

  • Change the hash algrithm to something slower and harder to crack (like bcrypt)
  • Make your master password harder to crack
  • Add a random string of characters before hashing to reduce the impact of a master password leak. The problem is that this random string of characters will have to be synced.

Example of code

Here are a few different examples of application of this algorithm. They are NOT all compatible.

  • Short bash script using sha512, base64 (the password is only the first 20 characters)
USERNAME="<yourusername><some additional random stuff for additional security>"
read -p "Website> " WEBSITE
read -sp "Master password> " MASTER_PASSWORD
PASSWORD=$(echo "$USERNAME $WEBSITE $MASTER_PASSWORD" | sha512sum | base64 | head -c 20)
echo "$PASSWORD"
  • Short python script (from master)
from getpass import getpass
from base64 import b64encode as b64
from hashlib import sha512

username = "<yourusername><some additional random stuff for additional security>"
url = input("Website > ")
master = getpass("Password > ")

password = str(b64(bytes(sha512(bytes(username + url + master, "utf-8")).hexdigest(), "utf-8"))).split("'")[1][-20:]
  • Short user script (for browsers) (from master, compatible with the python script)
// ==UserScript==
// @name           Master-Browser
// @description    A sync-less password manager in your browser!
// @version        v0.4
// @include        *
// @grant          GM_setClipboard
// @require        https://raw.githubusercontent.com/emn178/js-sha512/master/src/sha512.js
// ==/UserScript==

function gen(username, url) {
  var master = document.activeElement.value
  var password = btoa(sha512(username + url + master))
  document.activeElement.value = ""
  GM_setClipboard(password.slice(password.length - 20))
}


(function() {
  var username = "<your username here>"
  document.addEventListener('keydown', function(e) {
    if (e.keyCode == 74 && e.altKey) {
      console.log("Copying username")
      GM_setClipboard(username)
    }

    if (e.keyCode == 71 && e.altKey) {
      var url = document.URL.split("://")[1].split("/")[0]
      gen(username, url)
    }

    if (e.keyCode == 85 && e.altKey) {
      var url = prompt("What is the url (include 'www.')")
      gen(username, url)
    }
  }, false)
})()