MD4 hash code generated from Python are different from the online. I know it must be due to encoding. Can you help?
from Crypto.Hash import MD4
psk = 'The quick brown fox jumps over the lazy dog'
h = MD4.new()
h.update(psk.encode('UTF-16LE'))
print(f'UTF-16LE: {h.hexdigest()}')
h.update(psk.encode('UTF-16'))
print(f'UTF-16: {h.hexdigest()}')
h.update(psk.encode('UTF-8'))
print(f'UTF8: {h.hexdigest()}')
h.update(psk)
print(f'UTF8?: {h.hexdigest()}')
The hash outputs for 'The quick brown fox jumps over the lazy dog' in different encoding are:
UTF-16LE: 4e6a076ae1b04a815fa6332f69e2e231
UTF-16: db8ae265b09c6ffa1e2fc163d66f64a4
UTF8: 324563ee68cc8009c82778d70d958723
UTF8?: 1aaf934b705b1d2aab69b0cf2a9cd87b
The online MD4 hash function (https://emn178.github.io/online-tools/md4.html) would give
1bee69a46ba811185c194762abaeae90
Update:
Thank you for comment, I have updated the code:
import getpass
from Crypto.Hash import MD4
psk = 'The quick brown fox jumps over the lazy dog' #getpass.getpass()
h = MD4.new(data=psk.encode('UTF-16LE'))
print(f'UTF-16LE: {h.hexdigest()}')
h = MD4.new(data=psk.encode('UTF-16'))
print(f'UTF-16: {h.hexdigest()}')
h = MD4.new(data=psk.encode('UTF-8'))
print(f'UTF8: {h.hexdigest()}')
h = MD4.new(data=psk)
print(f'UTF8?: {h.hexdigest()}')
The new output is
UTF-16LE: 4e6a076ae1b04a815fa6332f69e2e231
UTF-16: c6274a58a30e434503b45d2ce95e6c19
UTF8: 1bee69a46ba811185c194762abaeae90
UTF8?: 1bee69a46ba811185c194762abaeae90
I also discovered that https://emn178.github.io/online-tools/md4.html use UTF-16 even though I passed it a file with UTF-16LE encoding.
WPA2 Enterprise requires text to be encoded in UTF-16LE.
With update you obviously update the hash, meaning you feed in more pieces of your message. So you are actually feeding in the string multiple times with different encodings which in the end gives a hash for more than just your string.
If you only update once you'll get the expected result.
from Crypto.Hash import MD4
psk = 'The quick brown fox jumps over the lazy dog'
h = MD4.new()
h.update(psk.encode('UTF-8'))
print(f'UTF8: {h.hexdigest()}')
From the documentation of digest, from which the hexdigest
method is a derivative:
Return the digest of the strings passed to the
update()
method so far. This is a string ofdigest_size
bytes which may contain non-ASCII characters, including null bytes.