Search code examples
python-3.xencryptionhash3des

Converting md5 hash to a proper 3DES key in python3


I have a function written in c# that you can pass an ascii string as the key, and the encrypted string from a database and decode the data.

I've verified that the code works by writing a simple c# program to decode the data. The code snippet converts the key string to bytes and MD5 hashes it.

C# Code Snippet, omitting some code that converted the byteHash to an ascii string for output in the compiled program

key = "joetest"

byte[] byteHash =  cryptoServiceProvider.ComputeHash(Encoding.ASCII.GetBytes(key));

byteHash = "f2fc0f481787cc4cbb15f7ded4412fe4"

I run the following commands and Python3 and get the same byteHash

key = "joetest" 
encoded_key = key.encode("ascii")
m = hashlib.md5()
m.update(encoded_key)
hex_key = m.hexdigest()
print(hex_key)

hex_key = "f2fc0f481787cc4cbb15f7ded4412fe4"

I've tried encoding 'hex_key' as binary.

My issue is I'm trying to pass hex_key into 2 different python3 crypto programs. Cryptodome and pyDes. Both tell me that i'm passing in an invalid key.

The C# code that uses byteHash is as follows

tripleDesCryptoServiceProvider.Key = byteHash;

tripleDesCryptoServiceProvider.Mode = CipherMode.ECB;

byte[] byteBuff = Convert.FromBase64String(encryptedString);

string strDecrypted = Encoding.UTF8.GetString(tripleDesCryptoServiceProvider.CreateDecryptor().TransformFinalBlock(byteBuff, 0, byteBuff.Length));

This all works, i was able to decrypt data when i passed in the encrypted string into this function.

Using pyDes i'm using this code

from pyDes import *
import base64
import hashlib


my_data = "fK/jw6/25y0="
#my_data is the word 'test' encrypted with the key of 'joetest'

#This code takes the key string and converts it to an MD5 hash
my_key = "joetest"
encoded_key = my_key.encode("ascii")    #Encode the data as binary data
m = hashlib.md5()           
m.update(encoded_key)
hex_key = m.hexdigest()         #Convert the key to an MD5 hash
encoded_hex_key = hex_key.encode()  #Make the MD5 key a binary key  

#Convert the Base64 encoded string to the format that the decoder wants
decoded_data = base64.b64decode(my_data)

k = triple_des(encoded_hex_key, ECB, padmode=PAD_PKCS5)
my_out = k.decrypt(decoded_data)
print("my_out")
print(my_out)
exit()

The error i'm getting is:

(3destest) c:\3des-test\3destest>joe3des_test3.py
Traceback (most recent call last):
  File "C:\3des-test\3destest\joe3des_test3.py", line 20, in <module>
    k = triple_des(encoded_hex_key, ECB, padmode=PAD_PKCS5)
  File "c:\3des-test\3destest\lib\site-packages\pyDes.py", line 710, in __init__
    self.setKey(key)
  File "c:\3des-test\3destest\lib\site-packages\pyDes.py", line 719, in setKey
    raise ValueError("Invalid triple DES key size. Key must be either 16 or 24 bytes long")
ValueError: Invalid triple DES key size. Key must be either 16 or 24 bytes long

Using pyCryptodome, i've tried this code

from Cryptodome.Cipher import DES3
import base64
import hashlib

# Converts the key string to an MD5 hash
key = "joetest" 
encoded_key = key.encode("ascii")
m = hashlib.md5()
m.update(encoded_key)
hex_key = m.hexdigest()

#Decodes the string to binary digits
encryptedString = base64.b64decode("fK/jw6/25y0=")

#Create the cipher to decrypt the data
cipher = DES3.new(hex_key, DES3.MODE_ECB)
decryptedString = cipher.decrypt(encryptedString)

And i get this error

Traceback (most recent call last):
  File "C:\3des-test\3destest\joe3des_test2.py", line 16, in <module>
    cipher = DES3.new(hex_key, DES3.MODE_ECB)
  File "c:\3des-test\3destest\lib\site-packages\Cryptodome\Cipher\DES3.py", line 174, in new
    return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs)
  File "c:\3des-test\3destest\lib\site-packages\Cryptodome\Cipher\__init__.py", line 55, in _create_cipher
    return modes[mode](factory, **kwargs)
  File "c:\3des-test\3destest\lib\site-packages\Cryptodome\Cipher\_mode_ecb.py", line 175, in _create_ecb_cipher
    cipher_state = factory._create_base_cipher(kwargs)
  File "c:\3des-test\3destest\lib\site-packages\Cryptodome\Cipher\DES3.py", line 99, in _create_base_cipher
    key = adjust_key_parity(key_in)
  File "c:\3des-test\3destest\lib\site-packages\Cryptodome\Cipher\DES3.py", line 80, in adjust_key_parity
    raise ValueError("Not a valid TDES key")
ValueError: Not a valid TDES key

My python MD5 hash is 32 hex characters long. Assuming my math is right, 32 * 4 is 128 bits. And the error is saying it must be 16 or 24 bytes long. 16 * 8 is also 128 bits. So the byte string value i'm passing it should be correct. I think I'm missing something, but can't seem to figure it out.

Update 2-Jan-2018 Based on answer below here's a copy of the code that I used to confirm this will decrypt the data from the DB.

from pyDes import *
import base64
import hashlib

#my_data is the word 'test' encrypted with the key of 'joetest'
my_data = "fK/jw6/25y0="


#This code takes the key string and converts it to an MD5 hash
my_key = "joetest"
encoded_key = my_key.encode("ascii")
m = hashlib.md5()
m.update(encoded_key)
digest_key = m.digest()

#Convert the Base64 encoded string to the format that the decoder wants
decoded_data = base64.b64decode(my_data)

k = triple_des(digest_key, ECB)
my_out = k.decrypt(decoded_data)
print("my_out")
print(my_out.decode("ascii"))

Solution

  • The disconnect here is that pyDes.triple_des() is looking for a binary key, but what you are giving it is an encoded string with the hex representation of that key. Since pyDes doesn't expect the hex string, try just giving it the raw digest instead (i.e. m.digest() instead of m.hexdigest()). No need to .encode() it either.