NYCPHP Meetup

NYPHP.org

[nycphp-talk] Thoughts on encryption

Michael B Allen ioplex at gmail.com
Thu May 6 14:25:30 EDT 2010


On Thu, May 6, 2010 at 1:15 PM, Anthony Papillion <papillion at gmail.com> wrote:
> So I've used encryption on a personal level and even on the server
> through SSL but I've not done much more in PHP than using either the
> MD5() or SHA1() functions on passwords. I tend to be a very paranoid
> type with user information and I'm constantly thinking about
> weaknesses in systems and how they could be exploited.
>
> My initial encryption method was to either md5 or SHA1 passwords, and
> stick them in the database. While I know it's difficult to 'reverse
> the sausage machine' on these encrypted strings, it's not impossible.
> An attacker could determine an MD5 or SHA1 password through a simple
> dictionary attack. So, in essence, the encryption is useless.
>
> My current method is to concatenate the username+password+username and
> then either MD5 or SHA1 that and store that as the password in the
> database. But, really, is this anymore secure to a sophisticated,
> thinking attacker? Certainly, if I could think of it, they could, and
> it would again be trivial to write a script to execute a simple
> dictionary attack and figure out the password.
>
> I also know there are many other encryption methods out there but,
> isn't it true that *all* of them are compromisable by that simple
> manner or am I missing something critical here? Perhaps the only way
> to mitigate the risk is to institute a 3 strikes policy (which pisses
> users off but is secure) and to them change the users password to some
> absolutely random 50 digit gobbledygook string of characters.
>
> Am I being overly paranoid here or are these valid concerns?  Am I
> simply missing something?

Hi Anthony,

MD5 and SHA1 password hashes are considered weak. You are correct that
someone got a hold of your hashes they could use a dictionary of
common passwords to devise some of your user's passwords.

There are a few ways to deal with this. The simplest is to just force
users to create complicated passwords. Make them use passwords that
are at least 8 characters and contain at least one digit and one
non-alphanumeric character. This makes a dictionary attack much less
practical (but by no means impossible if you have a lot of resources).
The other way is to use a hashing algorithm with a larger bitwidth.
Another is to add a salt. Better still, use all of these techniques.

One pedantic note: MD5 and SHA1 are not encryption algorithms. They
are hashing algorithms. With encryption you take plaintext and convert
it to ciphertext and then you can do the reverse and get the plaintext
back. With hashing you take plaintext and convert it to a hash which
is just a random bit of data but of course given the same input you
always get the same output. But with a hash you cannot convert it back
to plaintext.

Personally I recommend that you do not invent your own hashing
algorithm. It only creates an opportunity to make a mistake that can
be exploited and it does not increase security anywhere near as much
as increasing the bitwidth. Just use a standard hashing method so that
passwords can be migrated, code is understood and can be ported, etc.

I would recommend using SSHA256 which is computed as follows:

1. Convert the plaintext password to UTF-8. In PHP you can use iconv for this.

2. Generate an 8 byte random salt. In PHP you can use mt_rand for this.

3. Generate the SHA256 hash of the UTF-8 plaintext password + salt. In
PHP 5 you can use hash_init('sha256'), then hash_update($utf8password)
followed by hash_update($salt) and hash_final to get the hash.

4. Concatenate the hash followed by the salt, convert the result to
Base64 and then prefix it with the "{SSHA256}" label to get a result
that looks like:

  {SSHA256}1LzicRO5StQs9kSR4UvTZbgfyhiiknzwDUhKaAgXUEa1uyL/s1Pd/A==

Here's an example with real values and salt used so that you can check
your computations as you go:

  Plaintext:
  opensaysme

  Salt in Hexadecimal:
  B5 BB 22 FF B3 53 DD FC

  SHA256 Hash of Plaintext and Salt in Hexadecimal:
  D4 BC E2 71 13 B9 4A D4 2C F6 44 91 E1 4B D3 65
  B8 1F CA 18 A2 92 7C F0 0D 48 4A 68 08 17 50 46

  SSHA256 Text Representation (this is what you put in the DB):
  {SSHA256}1LzicRO5StQs9kSR4UvTZbgfyhiiknzwDUhKaAgXUEa1uyL/s1Pd/A==

Note that even though I show the values in hex for the purpose of this
message, all of the computations are done using binary which means in
PHP you're going to need to write helper functions that use ord and
chr quite a bit.

This 256 salted password hash is standard and is understood by
software like LDAP servers. Combined with complex password
requirements, this would disappoint even a serious cracker.

If your system does not support sha256, do SSHA128 instead using the
sha128 algorithm (aka sha1) + salt. Otherwise it is computed in
exactly the same way but of course it will only be 128 bits instead of
256. But at least you'll have a salt which will greatly slow down a
dictionary attack.

Mike

-- 
Michael B Allen
Java Active Directory Integration
http://www.ioplex.com/



More information about the talk mailing list