commit 9346f86cf71d70878426fcce33e52c43d7e5a4f7
parent 2b6ecc0555bb8b39947baf07223d2d3f84c2d3a8
Author: boredpasta <boredpasta@tutanota.com>
Date: Sat, 15 Mar 2025 21:21:11 +0200
badphrase: awkify!
Diffstat:
M | badphrase | | | 67 | +++++++++++++++++++++++++++++++++++++++++-------------------------- |
1 file changed, 41 insertions(+), 26 deletions(-)
diff --git a/badphrase b/badphrase
@@ -1,22 +1,21 @@
#!/bin/sh
set -e
-englishchars=26
-
-charmin=6
+charmin=0
charmax=0
copy=0
-entropymin=100
+entropymin=128
includenames=0
+verbose=0
wordlist=/usr/share/dict/words
-wordnum=4
+wordnum=8
usage() {
- echo "usage: ${0##*/} [-ci] [-e entropymin] [-l wordlist] [-m charmax] \
+ echo "usage: ${0##*/} [-chiv] [-e entropymin] [-l wordlist] [-m charmax] \
[-n charmin] [-w wordnum]" 1>&2
}
-while getopts ce:hil:m:n:w: arg; do
+while getopts ce:hil:m:n:vw: arg; do
case $arg in
c) copy=1;;
e) entropymin=${OPTARG};;
@@ -25,33 +24,49 @@ while getopts ce:hil:m:n:w: arg; do
l) wordlist=${OPTARG};;
m) charmax=${OPTARG};;
n) charmin=${OPTARG};;
+ v) verbose=1;;
w) wordnum=${OPTARG};;
?) usage; exit 1;;
esac
done
shift $((OPTIND - 1))
-# password length should satisfy entropy requirements
-minlen=$(echo "l(2^${entropymin})/l($englishchars)" | bc -l)
-if echo "${wordnum}*${charmin} >= ${minlen}" | bc -l | xargs test 1 -ne; then
- printf "%s: wordnum * charmin needs to be >= %.2f (entropymin = %d)\n" \
- "${0##*/}" "$minlen" "$entropymin" 1>&2
- exit 1
+# setup regex
+if [ "$includenames" -eq 1 ]; then
+ re_class='.'
+else
+ re_class='^[^A-Z]'
fi
+[ "$charmin" -lt 0 ] && charmin=0
+[ "$charmax" -le 0 ] && charmax=''
-# generate the passphrase
-sort -R "$wordlist" | \
-if [ "$includenames" -eq 0 ]; then
- grep '^[^A-Z]'
-else
- cat
-fi | \
-if [ "$charmax" -lt "$charmin" ]; then
- grep -x ".\{${charmin},\}"
-else
- grep -x ".\{${charmin},${charmax}\}"
-fi | \
-head -n "$wordnum" | \
+# password generation pipeline
+
+# filter and shuffle the wordlist
+grep -x "${re_class}\{${charmin},${charmax}\}" "$wordlist" | sort -R | \
+# test entropy against $entropymin and if that worked print first $wordnum lines
+{ awk -v prog="${0##*/}" -v entropymin="$entropymin" -v wordnum="$wordnum" -v \
+verbose="$verbose" '
+NR <= wordnum { line[NR] = $0 }
+END {
+ perms = NR
+ # show entropy
+ entropy = log(perms^wordnum) / log(2)
+ if (verbose)
+ printf("log2(%d^%d) = %.2f bits of entropy\n", perms, wordnum, \
+ entropy) >"/dev/stderr"
+ # stop if we dont satisfy entropy requirements
+ lengthmin = log(2^entropymin) / log(perms)
+ if (wordnum < lengthmin) {
+ printf("%s: wordnum needs to be >= %.2f so that entropy would be \
+ >= %d\n", prog, lengthmin, entropymin) >"/dev/stderr"
+ exit 1
+ } else {
+ for (i = 1; i < wordnum; i++)
+ print line[i]
+ }
+}' || exit 1; } | \
+# output passphrase
if [ "$copy" -eq 1 ]; then
paste -sd '' - | xclip -selection clipboard
else