Reputation: 1307
DISCLAIMER: All the examples given here are not safe and are not remotely close to being good practice. The code used here is intended to be used in a CTF challenge and contains multiple vulnerabilities.
Here is my actual concern: The result from encrypting with the same key, iv, mode and padding using mcrypt_encrypt results in a different cipher than doing the same using Crypto.cipher AES in python 2.7, but only when using OFB mode. Here is my example:
$key = 'SUPER_SECRET_KEY';
$iv = '0000000000000000';
$data = "this is a test";
$padding = 16 - (strlen($data) % 16);
$data .= str_repeat(chr($padding), $padding);
echo base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_OFB, $iv));
The result is: k8Ss4ytOUNvcG96tr+rHdA==
Now the python example:
from Crypto.Cipher import AES
from base64 import b64encode
key = 'SUPER_SECRET_KEY'
iv = '0'*16
data = "this is a test"
padding = 16 - (len(data) % 16)
data += chr(padding)*padding
print(b64encode(AES.new(key, AES.MODE_OFB, iv).encrypt(data)))
The result is: kzFpEHCJB+2k2498DhyAMw==
It only happens in OFB mode. If I were to change the mode to CBC (and change nothing else), both results would be identical. Any idea what is going on?
EDIT: Using openssl_encrypt in PHP gives me the same results as the python code. This leads me to believe there is a bug in mcrypt_encrypt.
$key = "SUPER_SECRET_KEY";
$iv = "0000000000000000";
$data = "this is a test";
$padding = 16 - (strlen($data) % 16);
$data .= str_repeat(chr($padding), $padding);
$cipher = openssl_encrypt($data, "aes-128-ofb", $key, $options=OPENSSL_RAW_DATA, $iv);
echo base64_encode($cipher) ."\n";
Upvotes: 1
Views: 548
Reputation: 93948
I'm not sure why you are trying to do anything with mcrypt or OFB mode - both are blasts from a past most cryptographers are trying to forget. It is also unclear why you use padding for a streaming mode, unless you're working around the PyCrypto bug (see below).
To directly answer your question, from the documentation of PHP:
MCRYPT_MODE_OFB
(output feedback, in 8-bit mode) is a stream cipher mode comparable to CFB, but can be used in applications where error propagation cannot be tolerated. It is recommended to use NOFB mode rather than OFB mode.
you probably should be using:
MCRYPT_MODE_NOFB
(output feedback, in n-bit mode) is comparable to OFB mode, but operates on the full block size of the algorithm.
where the "N" before "OFB" is the block size of the mode of operation.
No such documentation exists for either PyCrypto, PyCryptoDome or OpenSSL. However, it seems that they process 128 bits at a time (according to a PyCrypto bug report) as it incorrectly requires to receive full plaintext blocks for some reason or other.
OFB will produce different ciphertext if used in 8 bit or 128 bit mode - except for the very first byte, which should be identical. 8 bit mode is as much as a blast from the past as mcrypt or OFB itself; it uses a full block encrypt per byte (!) to allow for reduced error propagation.
If you need a streaming mode, use CTR mode or, preferably, an authenticated cipher such as GCM (which uses CTR mode underneath). This will both be faster (than 8 bit OFB) and more secure.
Upvotes: 4