Superficial problems
There are several problems with your script. It breaks if the password contains a number of special characters. Try entering input such as:
a space
two spaces
a * star ← try this one in different directories
bbbbbbbbbb ← try this one in a directory containing a file called a
endswithabackslash\
Read Why does my shell script choke on whitespace or other special characters?. All of it. Do not write any shell scripts that are remotely related to security until you understand all of it.
Oh, and [:alnum:]
works perfectly. You probably intended to write if [ -z …
or if ! [ -n …
instead of if ! [ -z …
.
There's no such thing as the strength of a password
The idea of “password strength” is a myth. It's a myth that's spread by a lot of websites, but it's still a myth. There is no such thing as the strength of a password, there is only the strength of a password generation process.
Having special characters in a password does not make it stronger. A password is a compromise between ease of memorizing and ease of cracking, and special characters make passwords significantly harder to memorize but not significantly harder to crack, as analyzed in this thread on Security Stack Exchange (the short story, the math, some complements — exercise: in this wrong answer, which parts completely ignore the facts?). The idea that special characters make a password stronger is based on the assumption that people who write password crackers are idiots. Guess what: they aren't. There's money to be made by cracking passwords, so you can bet there are people who invest in doing it well.
So how should I choose passwords then?
Randomly. If your method to choose a password doesn't include a source of randomness (with a computer, or rolling a dice if you like it old-school), it's no good.
Diceware is a popular choice, but any method that follows the XKCD pattern — pick multiple “words” at random from some dictionary — is good.
A correct script
#!/bin/sh
echo -n "Enter a password : "
IFS= read -r password
LEN=${#password}
if [ "$LEN" -lt 10 ]; then
printf "%s is smaller than 10 characters\n" "$password"
fi
if [ -z "$(printf %s "$password" | tr -d "[:alnum:]")" ]; then
printf "%s only contains ASCII letters and digits\n" "$password"
else
printf "%s contains characters other than ASCII letters and digits\n" "$password"
fi
Using tr
in this way overcomplicates things. The shell is perfectly able to check whether a string contains characters among a certain set.
#!/bin/sh
echo -n "Enter a password : "
IFS= read -r password
LEN=${#password}
if [ "$LEN" -lt 10 ]; then
printf "%s is smaller than 10 characters\n" "$password"
fi
case "$password" in
*[![:alnum:]]*)
printf "%s contains characters other than ASCII letters and digits\n" "$password";;
*)
printf "%s only contains ASCII letters and digits\n" "$password";;
esac
(Note that the statement about ASCII letters and digits is true for Ubuntu's /bin/sh
, but in bash [:alnum:]
includes all letters and digits in the current locale, not just the ASCII ones.)
john
, see github.com/magnumripper/JohnTheRipper for instructions and the latest version.