pythonencryption3des

DES3 encryption result on python is different from des-ede3-cbc result of php


PHP code

// php 8.1.13
$text = '1';
$key = base64_decode('3pKtqxNOolyBoJouXWwVYw==');
$iv = base64_decode('O99EDNAif90=');
$encrypted = openssl_encrypt($text, 'des-ede3-cbc', $key, OPENSSL_RAW_DATA, $iv);
$hex = strtoupper(bin2hex($encrypted));
echo $hex;

The result is FF72E6D454B84A7C

Python3.8 pycryptodome 3.20.0

import binascii
import base64
from Crypto.Cipher import DES3
from Crypto.Util.Padding import pad

key = base64.b64decode('3pKtqxNOolyBoJouXWwVYw==')
iv = base64.b64decode('O99EDNAif90=')

cipher = DES3.new(key, DES3.MODE_CBC, iv)

data = '1'
data = data.encode('utf-8')
data = pad(data, DES3.block_size)

encrypted = cipher.encrypt(data)

print(binascii.hexlify(encrypted).decode('utf-8').upper())

The result is A311743FB5D91569

Why are these two results different, and how can I make python's results consistent with PHP's?

I've tried using pycryptodome and pyDes and can't achieve the same result as PHP


Solution

  • The reason for the different results is that different TripleDES variants are used in both codes.

    des-ede3-cbc in the PHP code specifies 3TDEA, which requires a 24 bytes key. Since the key used is only 16 bytes in size, PHP/OpenSSL silently pads it with 0x00 values to the required size of 24 bytes.

    With PyCryptodome, the key length determines the variant. Since the key is 16 bytes in size, 2TDEA is applied. For this reason the result is different.

    In order to also use 3TDEA, the key must be explicitly padded in the Python code, i.e. expanded to 24 bytes with 0x00 values:

    key = base64.b64decode('3pKtqxNOolyBoJouXWwVYw==') + b'\x00'*8
    

    If this key is applied in the Python code, the result is the same as in the PHP code.