1

I've got this weird old app that I'm trying to support and it stores the passwords in plain text and I'd like to hash them. I'd really like to have an input file in csv with a username,password for each line, but I'm trying just the password at first until I get that part figured out. I'm trying to hash a list of passwords that are in plaintext to another file and keep the list in order. I was snooping around on here and think it needs to be done with a while read statement, but it's not exactly working right.

here's what I've got so far:

#!/bin/bash

while read line
do 
    /bin/echo -n "$ line" | sha256sum >> /tmp/hashes.txt
done < pwd.txt

In the input file pwd.txt each line is a different password. When I run this in a script all it's doing is repeating the hash from the first password over and over, but it's doing it the correct amount of times for the lines in the input file. I'd really appreciate some guidance on what I'm doing wrong or if there's a better way.

3
  • 2
    This line should be: /bin/echo -n "$line" | sha256sum >> /tmp/hashes.txt You have one space after dollar sign Commented May 15, 2015 at 17:21
  • 2
    You have a space between $ and line. If that typo is in your script as well all you are doing is hashing the text $ line over and over.
    – jw013
    Commented May 15, 2015 at 17:23
  • 4
    If you want this technique to be even moderately secure, don't forget to also salt your passwords!
    – user43791
    Commented May 15, 2015 at 17:51

2 Answers 2

4

First, your immediate syntax error: "$ line" is the 6-character string dollar, space, l, i, n, e. To take the value of the variable line, use "$line". Note that if the value is -e or -E, echo will parse it as an option and print nothing. To avoid this, use printf %s instead. Also, plain read strips whitespace at the beginning and end of the line and treats backslashes as escape characters; to read the line literally, use IFS= read -r.

while IFS= read -r line; do
  printf %s "$line" | …
fi

Do not use SHA-256 to hash passwords. While it's better than plain text, it's still bad. SHA-256 is not an acceptable way to hash passwords because password hashes must be salted and slow. See How to securely hash passwords? for a detailed explanation. You can use the commonly available mkpasswd utility to generate decent password hashes; use the SHA-256 or SHA-512 (despite its name, they're ok because they don't actually compute a SHA2 hash, they compute an iterated hash, which is acceptably slow). The generated hash includes a random salt.

printf %s "$line" | mkpasswd -s -m SHA-512

In your application, call the system's crypt function to verify these hashes. If the programming language you're using doesn't give you access to the standard library crypt function, use a PBKDF2, bcrypt or scrypt library, and use that library to generate the converted hashes as well (again, do not use plain SHA-256 or SHA-512).

0
-1

EDIT Instead of sha256sum, it's far better to use something more robust. (Hat tip: user Gilles). The glibc crypt routine iterates the salted string through sha256 for a minimum of 5000 rounds. The idea is this makes password crackers require many more resources / time to find a matching string. You can use this technique on pretty much any system by replacing the sha256sum:

sha256sum() { 
    read password
    salt=`openssl rand -base64 8`
    perl -le "print crypt('${password}','\$6\$${salt}\$')";
}

This generates an 8-character salt and passes the first line of input and the generated salt through crypt.

If your input is something like username,password and no quote marks or anything, you can use... a gazillon techniques to do this. One is:

while IFS=, read username pass ; do 
    /bin/echo -n "$username,"
    echo "$pass" | sha256sum |cut -d' ' -f1
done < input.txt >output.txt

In this version, your output is now username,hash and each line corresponds to the input of the first file.

5
  • 1
    While the shell advice is ok, the security advice is dangerously incomplete. $RANDOM isn't large enough for a salt, it's only 15 bits. sha256sum is not an acceptable way of computing a hash because it isn't slow. You're inventing a password hash algorithm, and as those things always go, it isn't a good one. Commented May 16, 2015 at 0:51
  • I am not inventing one. This is what Postgresql uses. Sha256 is what modern Linux uses. The original Unix salt implementation was ~10 bits -- TWO alphanumeric characters of the user's password.
    – Otheus
    Commented May 16, 2015 at 18:15
  • Besides, these were suggestions.
    – Otheus
    Commented May 16, 2015 at 18:16
  • I don't know what Postgresql uses, but I do know that this is not what any modern Linux uses (or any old Linux, for that matter). The original Unix implementation is not secure with today's computing speeds. The “SHA-256” algorithm in Linux is not SHA-256(password+salt), it's a construction that iterates SHA-256 many times, making it slow. It's also a hash algorithm, not encryption in any guise, despite being called crypt. There is unfortunately some confusing terminology floating around, but that's no excuse for recommending bad password hashing. Commented May 17, 2015 at 10:27
  • @Gilles I appreciate your pointing out the flaws in my post. I agree: my initial random salt was dangerously incomplete, and thus I updated my post. I also thank you for pointing out (which I verified myself from source) that crypt iterates through the hash (thousands of times). I quibbled at your statement that I was "inventing" an algorithm when I was not. I also quibble that it's "bad". But I will update my post again.
    – Otheus
    Commented May 17, 2015 at 11:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .