added entropy and password source to pwdscore

This commit is contained in:
fatalerrors
2026-04-01 18:15:11 +02:00
parent 8fe11776cb
commit 84e6fdd429

View File

@@ -273,43 +273,67 @@ export -f genpwd
pwdscore()
{
local verbose=0
local PARSED
local read_stdin=0
local password=""
PARSED=$(getopt -o hv --long help,verbose -n 'pwdscore' -- "$@")
if [[ $? -ne 0 ]]; then return 1; fi
eval set -- "$PARSED"
while true; do
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
printf "pwdscore: Score a password from 1 to 100.\n\n"
printf "Usage: pwdscore [options] <password>\n\n"
printf "Usage: pwdscore [options] <password>\n"
printf " pwdscore [options] --stdin\n"
printf " pwdscore [options] # prompt on terminal\n\n"
printf "Options:\n"
printf "\t-h, --help\t\tDisplay this help screen\n"
printf "\t-v, --verbose\t\tShow details about the computed score\n"
printf "\t-i, --stdin\t\tRead the password from standard input\n\n"
printf "Note:\n"
printf " Passwords containing '!' should be quoted, or passed via --stdin.\n"
return 0
;;
-v|--verbose)
verbose=1
shift
;;
-i|--stdin)
read_stdin=1
shift
;;
--)
shift
break
;;
*)
disp E "Invalid options, use \"pwdscore --help\" to display usage."
-*)
disp E "Invalid option '$1'. Use \"pwdscore --help\" to display usage."
return 1
;;
*)
break
;;
esac
done
[[ $# -ne 1 ]] && {
disp E "Please provide exactly one password to score."
return 1
}
if (( read_stdin )); then
[[ $# -eq 0 ]] || {
disp E "Do not pass a positional password when using --stdin."
return 1
}
IFS= read -r password || true
elif [[ $# -eq 0 ]]; then
if [[ -t 0 ]]; then
read -r -s -p 'Password: ' password < /dev/tty || true
printf '\n' > /dev/tty
else
IFS= read -r password || true
fi
else
[[ $# -eq 1 ]] || {
disp E "Please provide exactly one password to score."
return 1
}
password="$1"
fi
local password="$1"
local lower=${password,,}
local length=${#password}
local score=0
@@ -319,6 +343,9 @@ pwdscore()
local c1=0 c2=0 c3=0
local ch=""
local has_lower=0 has_upper=0 has_digit=0 has_symbol=0
local pool_size=0
local entropy_bits="0.0"
local entropy_score=0
local -A seen=()
if [[ -z $password ]]; then
@@ -338,29 +365,66 @@ pwdscore()
score=$(( length * 2 ))
fi
[[ $password =~ [a-z] ]] && { has_lower=1; ((score += 12)); }
[[ $password =~ [A-Z] ]] && { has_upper=1; ((score += 12)); }
[[ $password =~ [0-9] ]] && { has_digit=1; ((score += 12)); }
[[ $password =~ [^[:alnum:]] ]] && { has_symbol=1; ((score += 14)); }
if [[ $password =~ [a-z] ]]; then
has_lower=1
pool_size=$(( pool_size + 26 ))
score=$(( score + 12 ))
fi
if [[ $password =~ [A-Z] ]]; then
has_upper=1
pool_size=$(( pool_size + 26 ))
score=$(( score + 12 ))
fi
if [[ $password =~ [0-9] ]]; then
has_digit=1
pool_size=$(( pool_size + 10 ))
score=$(( score + 12 ))
fi
if [[ $password =~ [^[:alnum:]] ]]; then
has_symbol=1
pool_size=$(( pool_size + 33 ))
score=$(( score + 14 ))
fi
for (( i=0; i<length; i++ )); do
ch=${password:i:1}
if [[ -z ${seen["$ch"]+x} ]]; then
seen["$ch"]=1
((unique_count++))
unique_count=$(( unique_count + 1 ))
fi
done
(( score += (unique_count * 10) / length ))
score=$(( score + (unique_count * 10) / length ))
if (( pool_size > 1 )); then
entropy_bits=$(awk -v len="$length" -v pool="$pool_size" \
'BEGIN { printf "%.1f", len * (log(pool) / log(2)) }')
entropy_score=$(awk -v bits="$entropy_bits" 'BEGIN {
if (bits < 28) print -35;
else if (bits < 36) print -25;
else if (bits < 60) print -10;
else if (bits < 80) print 0;
else if (bits < 100) print 5;
else print 10;
}')
score=$(( score + entropy_score ))
fi
if [[ $lower =~ (password|admin|root|qwerty|azerty|welcome|letmein|secret|changeme) ]]; then
((score -= 25))
score=$(( score - 25 ))
fi
if [[ $lower =~ (1234|abcd|qwer|0000|1111|aaaa) ]]; then
((score -= 15))
score=$(( score - 15 ))
fi
if [[ $password =~ (.)\1\1 ]]; then
score=$(( score - 10 ))
fi
if (( length < 8 )); then
score=$(( score - 10 ))
fi
if (( unique_count * 2 < length )); then
score=$(( score - 10 ))
fi
[[ $password =~ (.)\1\1 ]] && ((score -= 10))
(( length < 8 )) && ((score -= 10))
(( unique_count * 2 < length )) && ((score -= 10))
for (( idx=0; idx<length-2; idx++ )); do
printf -v c1 '%d' "'${lower:idx:1}"
@@ -368,13 +432,16 @@ pwdscore()
printf -v c3 '%d' "'${lower:idx+2:1}"
if (( (c2 == c1 + 1 && c3 == c2 + 1) || \
(c2 == c1 - 1 && c3 == c2 - 1) )); then
((score -= 10))
score=$(( score - 10 ))
break
fi
done
(( score < 1 )) && score=1
(( score > 100 )) && score=100
if (( score < 1 )); then
score=1
elif (( score > 100 )); then
score=100
fi
if (( score >= 90 )); then
rating='excellent'
@@ -397,6 +464,8 @@ pwdscore()
printf 'Digits: %s\n' "$([[ $has_digit -eq 1 ]] && echo yes || echo no)"
printf 'Symbols: %s\n' "$([[ $has_symbol -eq 1 ]] && echo yes || echo no)"
printf 'Unique chars: %d\n' "$unique_count"
printf 'Entropy: ~%s bits\n' "$entropy_bits"
printf 'Entropy modifier: %+d\n' "$entropy_score"
else
printf '%d\n' "$score"
fi