Question :
I have a function in PHP that encrypts text as follows:
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))));
}
How do I decrypt these values in Python?
Answer #1:
To decrypt this form of encryption, you will need to get a version of Rijndael. One can be found here. Then you will need to simulate the key and text padding used in the PHP Mcrypt module. They add ' '
to pad out the text and key to the correct size. They are using a 256 bit block size and the key size used with the key you give is 128 (it may increase if you give it a bigger key). Unfortunately, the Python implementation I’ve linked to only encodes a single block at a time. I’ve created python functions which simulate the encryption (for testing) and decryption in Python
import rijndael
import base64
KEY_SIZE = 16
BLOCK_SIZE = 32
def encrypt(key, plaintext):
padded_key = key.ljust(KEY_SIZE, ' ')
padded_text = plaintext + (BLOCK_SIZE - len(plaintext) % BLOCK_SIZE) * ' '
# could also be one of
#if len(plaintext) % BLOCK_SIZE != 0:
# padded_text = plaintext.ljust((len(plaintext) / BLOCK_SIZE) + 1 * BLOCKSIZE), ' ')
# -OR-
#padded_text = plaintext.ljust((len(plaintext) + (BLOCK_SIZE - len(plaintext) % BLOCK_SIZE)), ' ')
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, ' ')
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
This can be used as follows:
key = 'MyKey'
text = 'test'
encoded = encrypt(key, text)
print repr(encoded)
# prints 'I+KlvwIK2e690lPLDQMMUf5kfZmdZRIexYJp1SLWRJY='
decoded = decrypt(key, encoded)
print repr(decoded)
# prints 'test'
For comparison, here is the output from PHP with the same text:
$ 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=
Answer #2:
If you’re willing to use MCRYPT_RIJNDAEL_128 rather than 256 on the PHP side, this is as simple as:
from Crypto.Cipher import AES
import base64
key="MyKey"
def decrypt(text)
cipher=AES.new(key)
return cipher.decrypt(base64.b64decode(text))
Answer #3:
Although the answer from @101100 was a good one at the time, it’s no longer viable. The reference is now a broken link, and the code would only run on older Pythons (<3).
Instead, the pprp project seems to fill the void nicely. On Python 2 or Python 3, just pip install pprp
, then:
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' ')
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' ')
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'
I’m a little dismayed that the ciphertext comes out different than what you see with 101100’s answer. I have, however, used this technique to successfully decrypt data encrypted in PHP as described in the OP.