pythondjangopython-3.xccavenue

Correctly migrate from Python 2 md5 library to Python 3 hashlib


I'm trying to integrate a 3rd party payment gateway (CCAvenue) in Django 1.11, Python 3.5.2

The reference code provided by the 3rd party uses the deprecated library md5 to encrypt texts.

from Crypto.Cipher import AES
import md5

def pad(data):
    length = 16 - (len(data) % 16)
    data += chr(length)*length
    return data

def encrypt(plainText,workingKey):
    iv = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'
    plainText = pad(plainText)
    encDigest = md5.new ()
    encDigest.update(workingKey)
    enc_cipher = AES.new(encDigest.digest(), AES.MODE_CBC, iv)
    encryptedText = enc_cipher.encrypt(plainText).encode('hex')
    return encryptedText

How do I make the above encrypt() method Python 3 compatible using the hashlib library of Python 3? Can you post the whole method?


Solution

  • WARNING: Don't use crypto or pycrypto anymore! read more

    Here's a Python 3 compatible way of doing the same:

    from binascii import hexlify, unhexlify
    from Crypto.Cipher import AES
    from hashlib import md5
    
    from django.utils.encoding import force_bytes
    
    iv = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'
    # for python 3.9 & pycryptodome, this need to be byte
    iv = b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'
    
    BS = 16
    
    
    def _pad(data):
        return data + (BS - len(data) % BS) * chr(BS - len(data) % BS)
    
    
    def _unpad(data):
        return data[0:-ord(data[-1])]
    
    
    def encrypt(plain_text, working_key):
        plain_text = _pad(plain_text)
        enc_cipher = AES.new(md5(force_bytes(working_key)).digest(), AES.MODE_CBC, _iv)
        return hexlify(enc_cipher.encrypt(plain_text)).decode('utf-8')
    
    
    def decrypt(cipher_text, working_key):
        encrypted_text = unhexlify(cipher_text)
        dec_cipher = AES.new(md5(force_bytes(working_key)).digest(), AES.MODE_CBC, _iv)
        return _unpad(dec_cipher.decrypt(encrypted_text).decode('utf-8'))