Translation of a PHP Script to Python3 (Django)

  django, php, python, python-3.x

I am attempting to convert from scratch the following PHP script into Python for my Django Project:

Note that it is my understanding that this script should handle values sent from a form, sign the data with the Secret_Key, encrypt the data in SHA256 and encode it in Base64

<?php

define ('HMAC_SHA256', 'sha256');
define ('SECRET_KEY', '<REPLACE WITH SECRET KEY>');

function sign ($params) {
  return signData(buildDataToSign($params), SECRET_KEY);
}

function signData($data, $secretKey) {
    return base64_encode(hash_hmac('sha256', $data, $secretKey, true));
}

function buildDataToSign($params) {
        $signedFieldNames = explode(",",$params["signed_field_names"]);
        foreach ($signedFieldNames as $field) {
           $dataToSign[] = $field . "=" . $params[$field];
        }
        return commaSeparate($dataToSign);
}

function commaSeparate ($dataToSign) {
    return implode(",",$dataToSign);
}

?>

Here is what I have done so far :

def sawb_confirmation(request):
    if request.method == "POST":

        form = SecureAcceptance(request.POST)
        if form.is_valid():

            access_key = 'afc10315b6aaxxxxxcfc912xx812b94c'
            profile_id = 'E25C4XXX-4622-47E9-9941-1003B7910B3B'
            transaction_uuid = str(uuid.uuid4())
            signed_field_names = 'access_key,profile_id,transaction_uuid,signed_field_names,unsigned_field_names,signed_date_time,locale,transaction_type,reference_number,amount,currency'
            signed_date_time = datetime.datetime.now()
            signed_date_time = str(signed_date_time.strftime("20%y-%m-%dT%H:%M:%SZ"))
            locale = 'en'
            transaction_type = str(form.cleaned_data["transaction_type"]) 
            reference_number = str(form.cleaned_data["reference_number"])
            amount = str(form.cleaned_data["amount"])
            currency = str(form.cleaned_data["currency"])

            # Transform the String into a List
            signed_field_names = [x.strip() for x in signed_field_names.split(',')]

            # Get Values for each of the fields in the form
            values = [access_key, profile_id, transaction_uuid,signed_field_names,'',signed_date_time,locale,transaction_type,reference_number,amount,currency]

            # Insert the signedfieldnames in their place in the list (MUST BE KEPT)
            values[3] = 'access_key,profile_id,transaction_uuid,signed_field_names,unsigned_field_names,signed_date_time,locale,transaction_type,reference_number,amount,currency'
            
            # Merge the two lists as one
            DataToSign = list(map('='.join, zip(signed_field_names, values)))

            # Hash Sha-256
            API_SECRET = 'bb588d4f96ac491ebd43cceb18xx149b79291f874f1a41fcbf5bc078bb6c8793af2df5ad4b174f80bd5f24a4e4eec6fdabdxxxxxc6c1410db40252deea613e0b976748539294438694ba08xx4ba831d3d850349cacfa445f9706aa57be7f8e61aab0be2288054dbe88ec6200ccd7c72888bcc0aa373f42059ec248d3c86b0f45'
            message = '{} {}'.format(DataToSign, API_SECRET)

            signature = hmac.new(bytes(API_SECRET , 'latin-1'), msg = bytes(message , 'latin-1'), digestmod = hashlib.sha256).hexdigest().upper()

            base64string = base64.b64encode( bytes(signature, "utf-8") )

When printing the variables as they come, I obtain the following :

VALUES :  ['afc10315b6aa3b2a8cfc91253812b94c', 'E25C4FE4-4622-47E9-9941-1003B7910B3B', '0b59b0ae-bd25-4421-a231-bb83dcfc91fa', 'access_key,profile_id,transaction_uuid,signed_field_names,unsigned_field_names,signed_date_time,locale,transaction_type,reference_number,amount,currency', '', '2021-03-06T22:07:30Z', 'en', 'authorization', '1615068450109', '100', 'USD']
DATATOSIGN :  ['access_key=afc10315b6aa3b2a8cfc91253812b94c', 'profile_id=E25C4FE4-4622-47E9-9941-1003B7910B3B', 'transaction_uuid=0b59b0ae-bd25-4421-a231-bb83dcfc91fa', 'signed_field_names=access_key,profile_id,transaction_uuid,signed_field_names,unsigned_field_names,signed_date_time,locale,transaction_type,reference_number,amount,currency', 'unsigned_field_names=', 'signed_date_time=2021-03-06T22:07:30Z', 'locale=en', 'transaction_type=authorization', 'reference_number=1615068450109', 'amount=100', 'currency=USD']
SIGNATURE :  953C786EB9884CEC13C24118B00125BDCFE23AFF8AB02E7BEF29A83156C55C16
BASE64STRING :  b'OTUzQzc4NkVCOTg4NENFQzEzQzI0MTE4QjAwMTI1QkRDRkUyM0FGRjhBQjAyRTdCRUYyOUE4MzE1NkM1NUMxNg=='

I think I am getting pretty close from the final result I would like to achieve since I would then simply have to post the Base64String to a specific URL.

However, I am unsure of a couple of things which may seem a bit off :

  1. Is my "translation" of the PHP code into Python correct? Am I meant to merge my lists with a result in "DATATOSIGN"? I am not proficient in PHP so I might have misunderstood how to present the data.

  2. The signature in Base64 should be 44 chars AT ALL TIME like "WrXOhTzhBjYMZROwiCug2My3jiZHOqATimcz5EBA07M=" when using the PHP Sample Code but mine way exceeds this limitation.

If you need any additional information, please do not hesitate to ask.

Hope you can give me pointers !

Source: Ask PHP

LEAVE A COMMENT