Skip to content
Advertisement

how to make correctly way AES.encrypt contain control character in Python3

I’m going to change encrypt logic from php to python3.

The original code has logic for padding ascii, i brought it into my python code.

from

function toPkcs7 ($value)
{
    $padSize = 16 - (strlen ($value) % 16) ;
    return $value . str_repeat (chr ($padSize), $padSize) ;
}

to

def to_pkcs7(s):
    padding_size = 16 - (len(s) % 16)
    return s + (chr(padding_size) * padding_size)

but two of encrytor work different when to_pkcs7 got 11 characters (ex “12345678901”) and return result contain control character(ex 12345678901x05x05x05x05x05, chr(5) means ENQ x05).

i think the control character of result purhaps ignored in AES of python3. because php toPkcs7 and python3 to_pkcs7 are return same length of string.

for instance

# in php
$message = toPkcs7($message);
echo strlen($message);  # 16
$encrypted = openssl_encrypt($message, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);

# in python3
message = to_pkcs7(message) 
print(len(message))  # 16
cipher = AES.new(key, AES.MODE_CBC, iv())
encrypted = cipher.encrypt(message.encode("utf-8"))

I wonder how to make my python code works like php.

Advertisement

Answer

In the posted PHP code, padding is done twice, which is unnecessary (and actually even a bug).

The purpose of padding is that the length of the plaintext is an integer multiple of the block size (16 bytes for AES), which is a requirement for block ciphers. This is already achieved by the first padding, i.e. the second padding is useless. It only causes a (redundant) complete block with (here) 0x10 values to be appended, which unnecessarily inflates the ciphertext.

In order to get the ciphertext of the double padded plaintext with the Python code, simply double padding is needed as well:

message = to_pkcs7(to_pkcs7(message)) 

To pad only once in the PHP code, please note the following: openssl_encrypt() implicitly uses PKCS7 padding, i.e. the custom padding is not necessary and therefore simply needs to be removed. However, if the custom padding should be applied, then simply the implicit padding has to be disabled (by setting the OPENSSL_ZERO_PADDING flag). Both variants provide the same result.

By the way, PyCryptodome (unlike legacy PyCrypto) supports PKCS7 in a dedicated module.

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement