Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python crypt in OSX

I have a Django application which resets unix user passwords running in an Ubuntu machine, but my development environment is OS X and I've come across this annoying situation:

OS X:

>>> import crypt
>>> crypt.crypt('test','$1$VFvON1xK$')
'$1SoNol0Ye6Xk'

Linux:

>>> import crypt
>>> crypt.crypt('test','$1$VFvON1xK$')
'$1$VFvON1xK$SboCDZGBieKF1ns2GBfY50'

From reading the pydoc for crypt, I saw it uses an OS-specific crypt implementation, so I also tested the following code in both systems with the same results as Python:

#include <unistd.h>

int main() {
        char *des = crypt("test","$1$VFvON1xK$ls4Zz4XTEuVI.1PnYm28.1");
        puts(des);
}

How can I have OS X's crypt() implementation generate the same results as Linux crypt()?
And why isn't that covered by the Python implementation (as I would expect from such cases for cross-platform deployment)?

like image 228
Filipe Pina Avatar asked Oct 24 '12 15:10

Filipe Pina


2 Answers

As an update to @synthesizerpatel's answer, the .encrypt() method is now deprecated in passlib and replaced by the .hash() method:

from passlib.hash import md5_crypt
hash = md5_crypt.hash("test", salt="VFvON1xK")
print(hash)
like image 157
Matthieu Boileau Avatar answered Oct 14 '22 14:10

Matthieu Boileau


This is because Linux's glibc handles passwords differently - the salt of the password on Linux corresponds to the type of hash that it generates. OSX crypt() is plain-old DES encryption, (which is horrible).

glibc supports a variety of hash algorithms (MD5, Blowfish, SHA-256, etc).

If we take a look at the crypt.3 manpage, we can see:

   If salt is a character string starting with the characters "$id$" followed by
   a string terminated by "$":

          $id$salt$encrypted

   then instead of using the DES machine, id identifies the encryption method
   used and this then determines how the rest of the password string is
   interpreted.  The following values of id are supported:

          ID  | Method
          ---------------------------------------------------------
          1   | MD5
          2a  | Blowfish (not in mainline glibc; added in some
              | Linux distributions)
          5   | SHA-256 (since glibc 2.7)
          6   | SHA-512 (since glibc 2.7)

So, given that information.. lets take your password from the second example using Linux's crypt

$1$VFvON1xK$SboCDZGBieKF1ns2GBfY50' ('test', encrypted with salt=VFvON1xK)


1                       == MD5
VFvON1xK                == Salt
SboCDZGBieKF1ns2GBfY50  == Hashed password

Luckily for you, there is a cross-platform solution for this, passlib.hash.md5_crypt.

Here's how you'd use it:

from passlib.hash import md5_crypt
hash = md5_crypt.encrypt("test",salt="VFvON1xK")
print hash

When run on Linux or OSX, produces the glibc friendly password hash of:

$1$VFvON1xK$SboCDZGBieKF1ns2GBfY50

Identical to the original produced on the Linux machine.

like image 37
synthesizerpatel Avatar answered Oct 14 '22 13:10

synthesizerpatel