freebsd-ports/security/pwned-check/files/pwned-check.sh.in
Stefan Eßer b0df33bf38 Add support for the remote query API. This obviates the need to download
the > 10 GB pawned password hash list, which requires nearly 20 GB after
decompression.

The API does not transfer the queried password or its full SHA1 hash to
the server, but only the first 5 characters of the hash. This allows to
retrieve the full password hashes that match that prefix (typically in the
order of 500) and then to check whether the password to test matches any
of the hashes returned.

Approved by:	antoine (implicit)
2018-07-29 06:53:06 +00:00

131 lines
2.8 KiB
Bash

#!/bin/sh
#
# Copyright (c) 2017 by Stefan Esser <se@freebsd.org>
# All rights reserved.
#
# Distributed under the BSD 2-clause Simplified License.
#
CFGFILE="%%PREFIX%%/etc/pwned-check.conf"
[ -r "$CFGFILE" ] && . $CFGFILE
: ${DBDIR:=/var/db/pwned-check}
: ${URLBASE:=https://downloads.pwnedpasswords.com/passwords}
# Helper functions
progname ()
{
basename "$0"
}
errexit ()
{
echo $(progname)": $@"
exit 1
}
usage ()
{
echo "usage: "$(progname)" [-u]"
exit 2
}
# Fetch files with pwned password hashes
fetchpwfiles ()
{
umask 022
mkdir -p $DBDIR || errexit "No write permission on data directory."
local f s_txt s_txt_7z hash
while read f s_txt s_txt_7z hash
do
local f7z="$f.7z"
echo "Checking '$DBDIR/$f' ..."
local s_txt_is=$(stat -f %z $f 2>/dev/null)
if [ "$s_txt_is" != "$s_txt" ]; then
local s_txt_7z_is=$(stat -f %z $f7z 2>/dev/null)
if [ "$s_txt_7z_is" != "$s_txt_7z" ]; then
echo "Fetching '$DBDIR/$f7z' ..."
fetch -S $s_txt_7z "$URLBASE/$f7z" || errexit "Could not fetch '$URLBASE/$f7z'."
fi
echo "Checking '$DBDIR/$f7z' ..."
local hash_is=$(sha1 -q "$f7z")
if [ "$hash_is" != "$hash" ]; then
rm -f "$f7z"
errexit "File '$f7z' fails SHA1 check: '$hash_is' should be '$hash'."
fi
echo "Extracting '$DBDIR/$f' ..."
tar xOf "$f7z" | cut -d ":" -f 1 > "$f" || errexit "Decompression of file '$f7z' failed."
local s_txt_is=$(stat -f %z "$f")
if [ "$s_txt_is" != "$s_txt" ]; then
rm -f "$f"
errexit "File '$f' has size $s_txt_is after decompression, should be $s_txt."
fi
fi
rm -f "$f7z"
done <<EOF
pwned-passwords-ordered-2.0.txt 20567110522 9647404191 87437926c6293d034a259a2b86a2d077e7fd5a63
EOF
echo "All data files have been successfully downloaded and extracted."
# delete old data files (their content is included in the new datafiles)
while read f
do
rm -f $f $f.7z
done <<EOF
pwned-passwords-1.0.txt
pwned-passwords-update-1.txt
pwned-passwords-update-2.txt
EOF
}
# Password lookup
exitcode=0
lookup ()
{
local hash=$(echo "$1" | tr 'a-z' 'A-Z')
if [ "$USEFILES" = yes ]; then
look "$hash" pwned-passwords*.txt > /dev/null
else
expected=${hash#?????}
prefix=${hash%$expected}
fetch -q -o - https://api.pwnedpasswords.com/range/$prefix 2>/dev/null | grep -i "^$expected:" >/dev/null
fi
}
checkpw ()
{
local pwd="$1"
local hash=$(echo -n "$pwd" | sha1)
if lookup "$hash"; then
echo "$pwd"
exitcode=1
elif expr "$pwd" : '[A-Fa-f0-9]\{40\}$' > /dev/null; then
if lookup "$pwd"; then
echo "$pwd"
exitcode=1
fi
fi
}
# Main program
export LC_COLLATE=C
if cd "$DBDIR" && ls pwned-passwords*.txt; then
USEFILES=yes
fi >/dev/null 2>&1
if [ "$#" -gt 0 ]; then
if [ "$1" = "-u" ]; then
fetchpwfiles
exit 0
else
echo "usage: "$(progname)" [-u]"
exit 2
fi
fi
while read pwd
do
checkpw "$pwd"
done
exit $exitcode