1 Commits

Author SHA1 Message Date
fatalerrors
84e6fdd429 added entropy and password source to pwdscore 2026-04-01 18:15:11 +02:00

View File

@@ -273,43 +273,67 @@ export -f genpwd
pwdscore() pwdscore()
{ {
local verbose=0 local verbose=0
local PARSED local read_stdin=0
local password=""
PARSED=$(getopt -o hv --long help,verbose -n 'pwdscore' -- "$@") while [[ $# -gt 0 ]]; do
if [[ $? -ne 0 ]]; then return 1; fi
eval set -- "$PARSED"
while true; do
case "$1" in case "$1" in
-h|--help) -h|--help)
printf "pwdscore: Score a password from 1 to 100.\n\n" 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 "Options:\n"
printf "\t-h, --help\t\tDisplay this help screen\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-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 return 0
;; ;;
-v|--verbose) -v|--verbose)
verbose=1 verbose=1
shift shift
;; ;;
-i|--stdin)
read_stdin=1
shift
;;
--) --)
shift shift
break break
;; ;;
*) -*)
disp E "Invalid options, use \"pwdscore --help\" to display usage." disp E "Invalid option '$1'. Use \"pwdscore --help\" to display usage."
return 1 return 1
;; ;;
*)
break
;;
esac esac
done done
[[ $# -ne 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." disp E "Please provide exactly one password to score."
return 1 return 1
} }
password="$1"
fi
local password="$1"
local lower=${password,,} local lower=${password,,}
local length=${#password} local length=${#password}
local score=0 local score=0
@@ -319,6 +343,9 @@ pwdscore()
local c1=0 c2=0 c3=0 local c1=0 c2=0 c3=0
local ch="" local ch=""
local has_lower=0 has_upper=0 has_digit=0 has_symbol=0 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=() local -A seen=()
if [[ -z $password ]]; then if [[ -z $password ]]; then
@@ -338,29 +365,66 @@ pwdscore()
score=$(( length * 2 )) score=$(( length * 2 ))
fi fi
[[ $password =~ [a-z] ]] && { has_lower=1; ((score += 12)); } if [[ $password =~ [a-z] ]]; then
[[ $password =~ [A-Z] ]] && { has_upper=1; ((score += 12)); } has_lower=1
[[ $password =~ [0-9] ]] && { has_digit=1; ((score += 12)); } pool_size=$(( pool_size + 26 ))
[[ $password =~ [^[:alnum:]] ]] && { has_symbol=1; ((score += 14)); } 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 for (( i=0; i<length; i++ )); do
ch=${password:i:1} ch=${password:i:1}
if [[ -z ${seen["$ch"]+x} ]]; then if [[ -z ${seen["$ch"]+x} ]]; then
seen["$ch"]=1 seen["$ch"]=1
((unique_count++)) unique_count=$(( unique_count + 1 ))
fi fi
done 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 if [[ $lower =~ (password|admin|root|qwerty|azerty|welcome|letmein|secret|changeme) ]]; then
((score -= 25)) score=$(( score - 25 ))
fi fi
if [[ $lower =~ (1234|abcd|qwer|0000|1111|aaaa) ]]; then 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 fi
[[ $password =~ (.)\1\1 ]] && ((score -= 10))
(( length < 8 )) && ((score -= 10))
(( unique_count * 2 < length )) && ((score -= 10))
for (( idx=0; idx<length-2; idx++ )); do for (( idx=0; idx<length-2; idx++ )); do
printf -v c1 '%d' "'${lower:idx:1}" printf -v c1 '%d' "'${lower:idx:1}"
@@ -368,13 +432,16 @@ pwdscore()
printf -v c3 '%d' "'${lower:idx+2:1}" printf -v c3 '%d' "'${lower:idx+2:1}"
if (( (c2 == c1 + 1 && c3 == c2 + 1) || \ if (( (c2 == c1 + 1 && c3 == c2 + 1) || \
(c2 == c1 - 1 && c3 == c2 - 1) )); then (c2 == c1 - 1 && c3 == c2 - 1) )); then
((score -= 10)) score=$(( score - 10 ))
break break
fi fi
done done
(( score < 1 )) && score=1 if (( score < 1 )); then
(( score > 100 )) && score=100 score=1
elif (( score > 100 )); then
score=100
fi
if (( score >= 90 )); then if (( score >= 90 )); then
rating='excellent' rating='excellent'
@@ -397,6 +464,8 @@ pwdscore()
printf 'Digits: %s\n' "$([[ $has_digit -eq 1 ]] && echo yes || echo no)" 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 'Symbols: %s\n' "$([[ $has_symbol -eq 1 ]] && echo yes || echo no)"
printf 'Unique chars: %d\n' "$unique_count" printf 'Unique chars: %d\n' "$unique_count"
printf 'Entropy: ~%s bits\n' "$entropy_bits"
printf 'Entropy modifier: %+d\n' "$entropy_score"
else else
printf '%d\n' "$score" printf '%d\n' "$score"
fi fi