在Python中解密PHP中使用MCRYPT_RIJNDAEL_256加密的字符串


Decrypting strings in Python that were encrypted with MCRYPT_RIJNDAEL_256 in 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中解密这些值?

要解密这种形式的加密,您需要获得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=

如果您愿意在PHP端使用MCRYPT_RIJNDAEL_128而不是256,这很简单:

from Crypto.Cipher import AES
import base64
key="MyKey"
def decrypt(text)
    cipher=AES.new(key)
    return cipher.decrypt(base64.b64decode(text))

虽然@101100的答案在当时是一个很好的答案,但它不再可行。该引用现在是一个断开的链接,并且代码只能在较旧的python (<3)上运行。

相反,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.

所述。