From ca3415c632525f6522e8a685c905a6d77e4b5747 Mon Sep 17 00:00:00 2001 From: Bastian de Byl Date: Fri, 12 Apr 2019 23:23:42 -0400 Subject: [PATCH] Began write-up on pass-check.sh --- content/post/password_checker.md | 109 +++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 content/post/password_checker.md diff --git a/content/post/password_checker.md b/content/post/password_checker.md new file mode 100644 index 0000000..548fbd0 --- /dev/null +++ b/content/post/password_checker.md @@ -0,0 +1,109 @@ +--- +title: "Password Checking Script" +date: 2019-04-13 +lastmod: 2019-04-13 +draft: true +tags: ["linux","code"] +categories: ["Blog"] +contentCopyright: false +hideHeaderAndFooter: false +--- +Having been inspired by the HIBP[^1] password checker, I set out to write a +script with the following goals: + +1. Check for duplicate/re-used passwords +1. Check the strength of each password +1. Check passwords against the `pwnedpass` API + + +# Preface +It's worth nothing that I use [`passwordstore`](https://www.passwordstore.org/) +to generate, and manage my passwords. On mobile, this is done using the official +[OpenKeychain](https://www.openkeychain.org/), and +[Password Store](https://github.com/zeapo/Android-Password-Store). Passwords are +shared across my devices using Git[^2] + +# Pump Your Brakes +Instead of jumping right into checking all my passwords, in plain-text, against +the `pwnedpasswords` API, it would be best to figure out how to safely transform +them to `sha1sum`[^3]. The API supports sending the first 5 characters of a `sha1sum`, +returning a list of all `sha1sum`s of exposed passwords (_with the exposed +count_) for the user to verify them on their end. + +# Gathering Passwords +The easiest way to get a comprehensive list (_associative array_[^4]) of +passwords and their `pass` path was to use `find` to look for `*.gpg` files in +my `.password-store` directory: +```bash +# Fetches all passwords in $PASSDIR and checks for duplicates (base check) +getpws() +{ + # Loop over the find (newline-in-filename safe) + while read -r -d '' p; do + # Remove the root directory, and file extension + p=$(printf "%s" "$p" | sed "s|^$PASSDIR/||" | sed "s/.gpg//") + + # Collect the trimmed, sha1 passwords + pwsha=$(pass "$p" | awk 'FNR==1 {printf "%s", $0}' | sha1sum | awk '{printf "%s", toupper($1)}') + pws["$p"]="$pwsha" + done < <(find "$PASSDIR" -name "*.gpg" -type f -print0) +} +``` +To note, `find` with `-print0` is used to avoid printing newline characters +(_unlikely, but good practice_), so that we can utilize the null terminator `''` +within `read -d ''`. Also, `read -r` simply prevents backslashes from being +treated in a special way (_also good practice!_)[^5] + +It may be worth mentioning, to folks less familiar with `awk`, that the +`FNR==1`, in this context, simply helps to get rid of any newline oddities from +being piped into `sha1sum`. I discovered incorrect `sha1sum` values **without** +`FNR==1` resulting in a useless password check! + +{{% admonition note Note %}} +`IFS=` would not have fixed the above newline issue, as the problem stems +from the output of `pass "$p"` and **not** the filenames. +{{% /admonition %}} + +That takes care of gathering our passwords, but we'll revisit this again in the +next part. + +# Sharing is not Caring +The most efficient way of checking for duplicates was simply to iterate over the +array of passwords gathered, and check against the current one found in the +`getpws()` function's loop. The names of the duplicate passwords are stored in +_another_ associative array for printing later as part of the "report". +```bash +# Checks for duplicate sha1sums of passwords in the associative array +checkdupes() +{ + for i in "${!pws[@]}"; do + if [[ "$2" == "${pws[$i]}" ]]; then + pwdupes["$1"]="$i" + fi + done +} +``` + +That being done, we just incorporate it into the above `getpws()` loop! +```bash +getpws() +{ + while read -r -d '' p; do + ... + checkdupes "$p" "$pwsha" + done < <(find "$PASSDIR" -name "*.gpg" -type f -print0) +} +``` + +This accomplishes our *first goal* of checking duplicate passwords -- +**hooray!** + +Next up: _Passwortstärke_ + +# TODO + +[^1]: [Have I Been Pwned](https://haveibeenpwned.com/Passwords) +[^2]: [`pass` Extended Git Example](https://git.zx2c4.com/password-store/about/#EXTENDED%20GIT%20EXAMPLE) +[^3]: [SHA-1 (Secure Hashing Algorithm)](https://en.wikipedia.org/wiki/SHA-1) +[^4]: [Arrays (Bash Reference Manual)](https://www.gnu.org/software/bash/manual/html_node/Arrays.html) +[^5]: [`man read`](https://linux.die.net/man/2/read)