chillibear.com

SSHA passwords in various languages

I’ve just had yet another problem with PHP and its extensions on one of my servers (should have taken my own advice, this time no number of re-compiles or order tweakage of the extensions.ini file seems to work … I’ve hit the buffers with using mhash.

Now that might not be a bad thing, the extension is obsolete anyway, but I’ve been using it to generate SSHA (_salted_ SHA) passwords for my email server for some time in a command line PHP script. I wrote the script ages ago, it’s one of those I’m always intending to replace. Anyhow I needed to fix it quickly and replace the mhash code (below) I could no longer use.

function HashPassword($password)
{
  mt_srand((double)microtime()*1000000);
  $salt = mhash_keygen_s2k(MHASH_SHA1, $password, substr(pack('h*', md5(mt_rand())), 0, 8), 4);
  $hash = "{SSHA}".base64_encode(mhash(MHASH_SHA1, $password.$salt).$salt);
  return $hash;
}

I had a bit of a look at the PHP docs again and a glance over the IMAP FAQs (since IMAP passwords are often SSHA) and found a nice page with SSHA generating code in a various languages. I’ve repeated them here with a touch of my own tweaking for my benefit.

PHP

function HashPassword($password)
{
  $salt = 'microtime()*1000000';
  for ($i=1;$i<=10;$i++) {
    $salt .= substr('0123456789abcdef',rand(0,15),1);
  }
  $hash = "{SSHA}".base64_encode(pack("H*",sha1($password.$salt)).$salt);
  return $hash;
}

Ruby

require 'sha1'
require 'base64'

def hashPassword(password)
  chars = ('a'..'z').to_a + ('0'..'9').to_a
  salt = Array.new(10, '').collect { chars[rand(chars.size)] }.
join '{SSHA}' + Base64.encode64( Digest::SHA1.digest(password+salt)+salt ).chomp! end

An alternate for generating the salt could be:

Array.new(10/2) { rand(256) }.pack('C*').unpack('H*').first

(the random string length in this case is 10).

Python

import hashlib
from base64 import urlsafe_b64encode as encode
from base64 import urlsafe_b64decode as decode

def hashPassword(password):
    salt = os.urandom(4)
    h = hashlib.sha1(password)
    h.update(salt)
    return "{SSHA}" + encode(h.digest() + salt)

I’m using the PHP at present, but must rewrite my script in Ruby to be consistent with everything else. So the code above hasn’t been double checked.

Written on 07 Dec 2009 and categorised in PHP, Perl, Python, and Ruby, tagged as Exim, ssha, ldap, and dovecot

Home, Post archive

site copyright Eric Freeman

Valid XHTML 1.0 Strict