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)?
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)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With