use python to create compatible ldap password (md5crypt) on windows - python

Do you know how to create a ldap compatible password (preferred md5crypt) via python on Windows
I used to write something like this in Linux but the crypt module is not present on Windows
char_set = string.ascii_uppercase + string.digits
salt = ''.join(random.sample(char_set,8))
salt = '$1$' + salt + '$'
pwd = "{CRYPT}" + crypt.crypt(str(old_password),salt)

The Passlib python library contains cross-platform implementations of all the crypt(3) algorithms. In particular, it contains ldap_md5_crypt, which sounds like exactly what you want. Here's how to use it (this code will work on windows or linux):
from passlib.hash import ldap_md5_crypt
#note salt generation is automatically handled
hash = ldap_md5_crypt.encrypt("password")
#hash will be similar to '{CRYPT}$1$wa6OLvW3$uzcIj2Puf3GcFDf2KztQN0'
#to verify a password...
valid = ldap_md5_crypt.verify("password", hash)
I should note that while MD5-Crypt is widely supported (Linux, all the BSDs, internally in openssl), it's none-the-less not the strongest hash available really horribly insecure, and should be avoided if at all possible. If you want the strongest hash that's compatible with linux crypt(), SHA512-Crypt is probably the way to go. It adds variable rounds, as well as some other improvements over MD5-Crypt internally.

From here http://www.openldap.org/faq/data/cache/347.html
One of the variants for generating SHA-hash can be:
import sha
from base64 import b64encode
ctx = sha.new("your_password")
hash = "{SHA}" + b64encode(ctx.digest())
print(hash)
This code is for Python.
# python my_sha.py
{SHA}Vk40DNSEN9Lf6HbuFUzJncTQ0Tc=
I (and not only me) don't recommend to use MD5 anymore.
PS. Follow the link you can try some windows variants.

You'll want to use fcrypt, which is a pure Python implementation of the Unix module crypt. It's a bit slower than crypt but it has the same functionality.

Disclaimer: I know Google, not cryptography.
From the crypt docs:
This module implements an interface to
the crypt(3) routine, which is a
one-way hash function based upon a
modified DES algorithm; see the Unix
man page for further details. Possible
uses include allowing Python scripts
to accept typed passwords from the
user, or attempting to crack Unix
passwords with a dictionary.
You could have a look at md5crypt.py. Alternatively, crypt for Windows is part of GnuWin32. Here's some of the Unix man page; the Windows interface should be similar.
CRYPT(3) Linux
Programmer's Manual
CRYPT(3)
NAME
crypt, crypt_r - password and data encryption
SYNOPSIS
#define _XOPEN_SOURCE
#include <unistd.h>
char *crypt(const char *key, const char *salt);
char *crypt_r(const char *key, const char *salt,
struct crypt_data *data);
Link with -lcrypt.
DESCRIPTION
crypt() is the password encryption function. It is based on
the Data
Encryption Standard algorithm with variations intended (among
other
things) to discourage use of hardware implementations of a key
search.
key is a user's typed password.
salt is a two-character string chosen from the set [a–zA–Z0–9./].
This
string is used to perturb the algorithm in one of 4096 different
ways.
By taking the lowest 7 bits of each of the first eight characters
of
the key, a 56-bit key is obtained. This 56-bit key is used to
encrypt
repeatedly a constant string (usually a string consisting of
all
zeros). The returned value points to the encrypted password, a
series
of 13 printable ASCII characters (the first two characters
represent
the salt itself). The return value points to static data whose
content
is overwritten by each call.
Warning: The key space consists of 2**56 equal 7.2e16 possible
values.
Exhaustive searches of this key space are possible using massively
par‐
allel computers. Software, such as crack(1), is available which
will
search the portion of this key space that is generally used by
humans
for passwords. Hence, password selection should, at minimum,
avoid
common words and names. The use of a passwd(1) program that checks
for
crackable passwords during the selection process is recommended.
The DES algorithm itself has a few quirks which make the use of
the
crypt() interface a very poor choice for anything other than
password
authentication. If you are planning on using the crypt()
interface for
a cryptography project, don't do it: get a good book on encryption
and
one of the widely available DES libraries.

Related

Cracking passwords with DES algorithm given hash and salt

I am given a hash ("1u9Tc6HX") and the salt ("Ff"), and I am told to crack the password knowing that it has been hashed with DES algorithm. Using hashcat, I have known that the password is ("michael") and I am now trying to hash this password in order to compare it with the hash given.
However, I have tried using (openssl enc) command but it always asks me for the password used for encryption, what I am not given, so I don't know how to hash ("michael") using DES and salt ("Ff") and get ("1u9Tc6HX"). I am open to change the procedure and try other things in case you think is easier to crack by other way. (I am working with python)
Any comment and help is appreciated.
Pd:
Example: Ff1u9Tc6HXxJo
Enunciate: The password has been hashed using the DES algorithm. The entry consists
in 13 printable ASCII characters, where the two first characters represent the salt.
With DES, only the first 8 characters of the password are used.
Passlib is a popular library for password hashing:
>>> import passlib.hash
>>> passlib.hash.des_crypt.hash('michael', salt='Ff')
'Ff1u9Tc6HXxJo'

Why would "$2a" vs "$2b" matter?

I was trying to write a script to add users into a MySQL database. I finally get all of the users into the database, but then the login of my app won't authorize them. I try a bunch of different solutions and then I notice the older user's passwords start with "$2a" and the ones I've added are "$2b". So I insert the code below.
password = bcrypt.hashpw(password.encode("UTF-8"), bcrypt.gensalt(11))
password = password.decode("UTF-8")
password = password[:2] + "a" + password[3:] #Why does this work??
Suddenly I can login no problem. So why would having "$2a" work and not "$2b"? The web app isn't mine and I can't find the code where it checks the password. If it helps, the webapp was made in Java and uses spring for validation.
Here's Wikipedia on Bcrypt:
$2$ (1999)
The original Bcrypt specification defined a prefix of $2$. This follows the Modular Crypt Format [...]
$2a$
The original specification did not define how to handle non-ASCII character, nor how to handle a null terminator. The specification was revised to specify that when hashing strings:
the string must be UTF-8 encoded
the null terminator must be included
With this change, the version was changed to $2a$
$2b$ (February 2014)
A bug was discovered in the OpenBSD implementation of bcrypt. They were storing the length of their strings in an unsigned char (i.e. 8-bit Byte). If a password was longer than 255 characters, it would overflow and wrap at 255.
You are adding the new format, while the program only supports validating the old format.
Since the new and old format are compatible for passwords < 255 chars, switching the header works. However, if you ever try to add a password >= 256 chars this way, it'll be rejected as invalid.

Customized hash function for Python

I would like to generate a human-readable hash with customized properties -- e.g., a short string of specified length consisting entirely of upper case letters and digits excluding 0, 1, O, and I (to eliminate visual ambiguity):
"arbitrary string" --> "E3Y7UM8"
A 7-character string of the above form could take on over 34 billion unique values which, for my purposes, makes collisions extremely unlikely. Security is also not a major concern.
Is there an existing module or routine that implements something like the above? Alternatively, can someone suggest a straightforward algorithm?
The method you should be using has similarities with password one-way encryption. Of course since you are going for readable, a good password function is probably out of the question.
Here's what I would do:
Take an MD5 hash of the email
Convert base32 which already eliminates O and I
Replace any non-readable characters with readable ones
Here's an example based on the above:
import base64 # base32 is a function in base64
import hashlib
email = "somebody#example.com"
md5 = hashlib.md5()
md5.update(email.encode('utf-8'))
hash_in_bytes = md5.digest()
result = base64.b32encode(hash_in_bytes)
print(result)
# Or you can remove the extra "=" at the end
result = result.strip(b'=')
Since it's a one-way function (hash), you obviously don't need to worry about reversing the process (you can't anyway). You can also replace any other characters you find non-readable with readable ones (I would go for lowercase versions of the characters, e.g. q instead of Q)
More about base32 here: https://docs.python.org/3/library/base64.html
You can simply truncate the beginning of an MD5sum algorithm. It should have approximately the same statistical properties than the whole string anyway:
import md5
m = md5.new()
m.update("arbitrary string")
print(m.hexdigest()[:7])
Same code with hashlib module:
import hashlib
m = hashlib.md5()
m.update("arbitrary string")
print(m.hexdigest()[:7])

Hashing (hiding) strings in Python

What I need is to hash a string. It doesn't have to be secure because it's just going to be a hidden phrase in the text file (it just doesn't have to be recognizable for a human-eye).
It should not be just a random string because when the users types the string I would like to hash it and compare it with an already hashed one (from the text file).
What would be the best for this purpose? Can it be done with the built-in classes?
First off, let me say that you can't guarantee unique results. If you wanted unique results for all the strings in the universe, you're better off storing the string itself (or a compressed version).
More on that in a second. Let's get some hashes first.
hashlib way
You can use any of the main cryptographic hashes to hash a string with a few steps:
>>> import hashlib
>>> sha = hashlib.sha1("I am a cat")
>>> sha.hexdigest()
'576f38148ae68c924070538b45a8ef0f73ed8710'
You have a choice between SHA1, SHA224, SHA256, SHA384, SHA512, and MD5 as far as built-ins are concerned.
What's the difference between those hash algorithms?
A hash function works by taking data of variable length and turning it into data of fixed length.
The fixed length, in the case of each of the SHA algorithms built into hashlib, is the number of bits specified in the name (with the exception of sha1 which is 160 bits). If you want better certainty that two strings won't end up in the same bucket (same hash value), pick a hash with a bigger digest (the fixed length).
In sorted order, these are the digest sizes you have to work with:
Algorithm Digest Size (in bits)
md5 128
sha1 160
sha224 224
sha256 256
sha384 384
sha512 512
The bigger the digest the less likely you'll have a collision, provided your hash function is worth its salt.
Wait, what about hash()?
The built in hash() function returns integers, which could also be easy to use for the purpose you outline. There are problems though.
>>> hash('moo')
6387157653034356308
If your program is going to run on different systems, you can't be sure that hash will return the same thing. In fact, I'm running on a 64-bit box using 64-bit Python. These values are going to be wildly different than for 32-bit Python.
For Python 3.3+, as #gnibbler pointed out, hash() is randomized between runs. It will work for a single run, but almost definitely won't work across runs of your program (pulling from the text file you mentioned).
Why would hash() be built that way? Well, the built in hash is there for one specific reason. Hash tables/dictionaries/look up tables in memory. Not for cryptographic use but for cheap lookups at runtime.
Don't use hash(), use hashlib.
You can simply use the base64 module to achieve your goal:
>>> import base64
>>> a = 'helloworld'
>>> encoded_str = base64.encodestring(a)
>>> encoded_str
'aGVsbG93b3JsZA=='
>>> base64.decodestring(encoded_str)
'helloworld'
>>>
of course you can also use the the hashlib module, it's more secure , because the hashed string cannot(or very very hard) be decoded latter, but for your question base64 is enough -- "It doesn't really have to be secure"
Note that Python's string hash is not "defined" - it can, and does, vary across releases and implementations. So storing a Python string hash will create difficulties. CPython's string hash makes no attempt to be "obscure", either.
A standard approach is to use a hash function designed for this kind of thing. Like this:
>>> import hashlib
>>> encoded = hashlib.sha1("abcdef") # "abcdef" is the password
>>> encoded.hexdigest()
'1f8ac10f23c5b5bc1167bda84b833e5c057a77d2'
That long string of hexadecimal digits is "the hash". SHA-1 is a "strong" hash function. You can get famous if you find two strings that hash to the same value ;-) And given the same input, it will return the same "hexdigest" on all platforms across all releases and implementations of Python.
Simply use the hash() built-in function, for example:
s = 'a string'
hash(s)
=> -8411828025894108412

How to hash strings in Python?

I have code that outputs all possible combinations of characters from a given character list as follows:
def charList():
charSet = string.ascii_letters + string.digits
for wordchars in product(charSet, repeat=8):
print(''.join(wordchars))
Now I need to turn the output strings into a DES hash then compare the output to user input to see if any matches are found.
Have been doing some research and haven't made much progress. So wondering if anyone on here could help?
If you want to hash strings (and not encrypt them), you can use the built-in hashlib module:
>>> import hashlib
>>> m = hashlib.md5()
>>> m.update("Nobody inspects")
>>> m.update(" the spammish repetition")
>>> m.digest()
'\xbbd\x9c\x83\xdd\x1e\xa5\xc9\xd9\xde\xc9\xa1\x8d\xf0\xff\xe9'
EDIT: as said in the comments, prefer hashlib.sha256() which is far more secured today.
Quick search for DES and Python gave me these libraries:
http://pypi.python.org/pypi/pycrypto/2.6
http://packages.python.org/passlib/lib/passlib.hash.des_crypt.html
http://docs.python.org/2/library/crypt.html
Platforms: Unix
This module implements an interface to the crypt(3) routine, which is
a one-way hash function based upon a modified DES algorithm; see the
Unix man page for further details. Possible uses include allowing
Python scripts to accept typed passwords from the user, or attempting
to crack Unix passwords with a dictionary.
Notice that the behavior of this module depends on the actual
implementation of the crypt(3) routine in the running system.
Therefore, any extensions available on the current implementation will
also be available on this module
crypt.crypt(word, salt)
word will usually be a user’s password as typed at a prompt or in a
graphical interface. salt is usually a random two-character string
which will be used to perturb the DES algorithm in one of 4096 ways.
The characters in salt must be in the set [./a-zA-Z0-9]. Returns the
hashed password as a string, which will be composed of characters from
the same alphabet as the salt (the first two characters represent the
salt itself).
Since a few crypt(3) extensions allow different values, with different
sizes in the salt, it is recommended to use the full crypted password
as salt when checking for a password.
A simple example illustrating typical use:
import crypt, getpass, pwd
def login():
username = raw_input('Python login:')
cryptedpasswd = pwd.getpwnam(username)[1]
if cryptedpasswd:
if cryptedpasswd == 'x' or cryptedpasswd == '*':
raise NotImplementedError(
"Sorry, currently no support for shadow passwords")
cleartext = getpass.getpass()
return crypt.crypt(cleartext, cryptedpasswd) == cryptedpasswd
else:
return 1

Categories

Resources