Commit Diff


commit - 2b6ecc0555bb8b39947baf07223d2d3f84c2d3a8
commit + 9346f86cf71d70878426fcce33e52c43d7e5a4f7
blob - 055d8fe7cb155a1a64e5825dac2eb255d94584e1
blob + a3d72cd633f1f796919e90c2bf36a8df12599ef4
--- badphrase
+++ 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