Расшифровка строк на Python, которые были зашифрованы с помощью MCRYPT RIJNDAEL 256 в PHP


У меня есть функция в PHP, которая шифрует текст следующим образом:

function encrypt($text)
{
    $Key = "MyKey";

    return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $Key, $text, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))));
}

Как расшифровать эти значения в Python?

Author: dharmesh, 2011-11-21

3 answers

Чтобы расшифровать эту форму шифрования, вам нужно будет получить версию Rijndael. Один из них можно найти здесь. Затем вам нужно будет смоделировать заполнение ключа и текста, используемое в модуле PHP Mcrypt. Они добавляют '\0', чтобы заполнить текст и ввести нужный размер. Они используют 256-битный размер блока, а размер ключа, используемого с ключом, который вы даете, составляет 128 (он может увеличиться, если вы дадите ему больший ключ). К сожалению, реализация Python, с которой я связался, кодирует только один блок в одно время. Я создал функции python, которые имитируют шифрование (для тестирования) и дешифрование на Python

import rijndael
import base64

KEY_SIZE = 16
BLOCK_SIZE = 32

def encrypt(key, plaintext):
    padded_key = key.ljust(KEY_SIZE, '\0')
    padded_text = plaintext + (BLOCK_SIZE - len(plaintext) % BLOCK_SIZE) * '\0'

    # could also be one of
    #if len(plaintext) % BLOCK_SIZE != 0:
    #    padded_text = plaintext.ljust((len(plaintext) / BLOCK_SIZE) + 1 * BLOCKSIZE), '\0')
    # -OR-
    #padded_text = plaintext.ljust((len(plaintext) + (BLOCK_SIZE - len(plaintext) % BLOCK_SIZE)), '\0')

    r = rijndael.rijndael(padded_key, BLOCK_SIZE)

    ciphertext = ''
    for start in range(0, len(padded_text), BLOCK_SIZE):
        ciphertext += r.encrypt(padded_text[start:start+BLOCK_SIZE])

    encoded = base64.b64encode(ciphertext)

    return encoded


def decrypt(key, encoded):
    padded_key = key.ljust(KEY_SIZE, '\0')

    ciphertext = base64.b64decode(encoded)

    r = rijndael.rijndael(padded_key, BLOCK_SIZE)

    padded_text = ''
    for start in range(0, len(ciphertext), BLOCK_SIZE):
        padded_text += r.decrypt(ciphertext[start:start+BLOCK_SIZE])

    plaintext = padded_text.split('\x00', 1)[0]

    return plaintext

Это можно использовать следующим образом:

key = 'MyKey'
text = 'test'

encoded = encrypt(key, text)
print repr(encoded)
# prints 'I+KlvwIK2e690lPLDQMMUf5kfZmdZRIexYJp1SLWRJY='

decoded = decrypt(key, encoded)
print repr(decoded)
# prints 'test'

Для сравнения, вот вывод из PHP с тем же текстом:

$ php -a
Interactive shell

php > $key = 'MyKey';
php > $text = 'test';
php > $output = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB);
php > $encoded = base64_encode($output);
php > echo $encoded;
I+KlvwIK2e690lPLDQMMUf5kfZmdZRIexYJp1SLWRJY=
 16
Author: 101100, 2011-11-24 17:05:03

Если вы хотите использовать MCRYPT_RIJNDAEL_128 вместо 256 на стороне PHP, это так же просто, как:

from Crypto.Cipher import AES
import base64
key="MyKey"

def decrypt(text)
    cipher=AES.new(key)
    return cipher.decrypt(base64.b64decode(text))
 4
Author: Adam McKenna, 2015-02-07 07:29:17

Хотя ответ от @101100 в то время был хорошим, он больше не жизнеспособен. Ссылка теперь является неработающей ссылкой, и код будет выполняться только на старых питонах (

Вместо этого проект pprp, похоже, прекрасно заполняет пустоту. На Python 2 или Python 3 просто pip install pprp, затем:

import pprp
import base64

KEY_SIZE = 16
BLOCK_SIZE = 32


def encrypt(key, plaintext):
    key = key.encode('ascii')
    plaintext = plaintext.encode('utf-8')
    padded_key = key.ljust(KEY_SIZE, b'\0')

    sg = pprp.data_source_gen(plaintext, block_size=BLOCK_SIZE)
    eg = pprp.rjindael_encrypt_gen(padded_key, sg, block_size=BLOCK_SIZE)

    ciphertext = pprp.encrypt_sink(eg)

    encoded = base64.b64encode(ciphertext)

    return encoded.decode('ascii')


def decrypt(key, encoded):
    key = key.encode('ascii')
    padded_key = key.ljust(KEY_SIZE, b'\0')

    ciphertext = base64.b64decode(encoded.encode('ascii'))

    sg = pprp.data_source_gen(ciphertext, block_size=BLOCK_SIZE)
    dg = pprp.rjindael_decrypt_gen(padded_key, sg, block_size=BLOCK_SIZE)

    return pprp.decrypt_sink(dg).decode('utf-8')


key = 'MyKey'
text = 'test'

encoded = encrypt(key, text)
print(repr(encoded))
# prints 'ju0pt5Y63Vj4qiViL4VL83Wjgirq4QsGDkj+tDcNcrw='

decoded = decrypt(key, encoded)
print(repr(decoded))
# prints 'test'

Я немного встревожен тем, что зашифрованный текст отличается от того, что вы видите в ответе 101100. Однако я использовал этот метод для успешной расшифровки данных зашифровано на PHP, как описано в OP.

 2
Author: Jason R. Coombs, 2017-08-12 18:44:10