Bug #51146 [Com]: mcrypt doesn't do OFB mode correctly
| From: | ywarnier at beeznest dot org | Date: | Mon, 25 Nov 2013 19:30:46 +0000 |
| Subject: | Bug #51146 [Com]: mcrypt doesn't do OFB mode correctly | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-182928@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=51146&edit=1
ID: 51146
Comment by: ywarnier at beeznest dot org
Reported by: zelnaga at gmail dot com
Summary: mcrypt doesn't do OFB mode correctly
Status: Open
Type: Bug
Package: mcrypt related
Operating System: Windows XP
PHP Version: 5.3.1
Block user comment: N
Private report: N
New Comment:
This addition might come as very low quality as I am still trying to understand AES128 and CFB, but
I think it is important to have the additional information one can gather. I hope it helps.
I was stuck trying to get mcrypt to cipher a string with AES128 in CFB mode, to be used by the
corresponding code in ASP.NET. I first thought ASP was the erroneous part, but apparently not.
This is my code snippet (note that padding is made with PKCS7 method). I use an IV identical to my
key, which is OK considering the key is 16 bytes long:
$password = 'not ciphered';
$key = '-+*%$({..})$%*+-';
$blockSize = 16;
$padding = $blockSize - (strlen($password)%$blockSize);
$password .= str_repeat(chr($padding),$padding);
$cipher = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $password, MCRYPT_MODE_CFB, $key);
$arr = preg_split('//', $cipher, -1, PREG_SPLIT_NO_EMPTY);
foreach ($arr as $char) {
echo ord($char).',';
}
The generated $cipher is the following sequence of (16) bytes:
179,90,167,188,65,82,212,108,133,15,161,49,142,222,207,167
However, the correct sequence of bytes should be as defined below, and can easily be generated using
phpseclib:
$password = 'not ciphered';
$key = '-+*%$({..})$%*+-';
$blockSize = 16;
$padding = $blockSize - (strlen($password)%$blockSize);
$password .= str_repeat(chr($padding),$padding);
$cipher = new Crypt_AES(CRYPT_AES_MODE_CFB);
$cipher->setKeyLength(128);
$cipher->setKey($key);
$cipher->setIV($key);
$cipheredPass = $cipher->encrypt($password);
$arr = preg_split('//', $cipheredPass, -1, PREG_SPLIT_NO_EMPTY);
foreach ($arr as $char) {
echo ord($char).',';
}
This last code generates the following sequence of (16) bytes:
179,15,83,71,111,104,118,215,159,221,153,228,153,148,69,164
Now, as I said, I'm still wrapping my brains around the whole AES128 (and in particular CFB),
but this last result is also what you get in ASP (and apparently in C, C++, etc).
There's a guy who apparently understands the problem better and put me in the right direction
here: http://stackoverflow.com/a/4054017/1406662
I found a few other references linking to mcrypt, but not specifically with CFB (for some reason
people seen to try CBC and NOFB first).
Apparently, the problem comes down to the default "feedback" size, which would not be set
properly in either PHP or mcrypt.
Also, somehow, phpseclib got it right, and it's MIT-licensed, so maybe a source of inspiration?
http://phpseclib.sourceforge.net/index.html
The problem might effectively come from mcrypt, and I'd be happy to report there if confirmed
and if you point me in the right direction as to where that is done most efficiently.
Previous Comments:
------------------------------------------------------------------------
[2011-01-29 23:20:03] lemkemch at t-online dot de
I can't believe what I was reading about ncfb above. That was the solution to decrypt my
OpenOffice files. I had it working in Java, with openssl on the command line but I couldn't
get it to work with php no matter what I tried. I had no idea that such a mode exists. So please,
document this and define a constant for it.
------------------------------------------------------------------------
[2011-01-05 21:14:42] me at haravikk dot com
To answer your first question, performing the encryption per-byte is kind of odd, I haven't
done much
testing but I don't think it actually consumes the entire input vector, only the first byte,
just think of
it as running with an 8-bit wide state, rather than the more typical 128-bit wide state.
I've never had the time to confirm that this is the exact case, though, but I believe it's
compatible with
other cryptography solutions that can operate per-byte.
For your second point; sorry I should have pointed out that there is no predefined constant for
MCRYPT_MODE_NCFB, you can however just enter it manually as 'ncfb' like so:
mcrypt_module_open('rijndael-128', '', 'ncfb', '');
So if there's a failing on the PHP side it's that we need an MCRYPT_MODE_NCFB, and that
MCRYPT_MODE_CFB
and MCRYPT_MODE_OFB should be properly documented so people don't keep using them expecting
different
results!
------------------------------------------------------------------------
[2010-06-19 15:42:52] zelnaga at gmail dot com
Also, there's still the matter of CFB. So NOFB is what most everything else refers to as OFB
but CFB'a wrong, as well, and it has no NCFB counter part.
------------------------------------------------------------------------
[2010-06-19 15:40:10] zelnaga at gmail dot com
What does it even mean to do OFB at the byte-level? Per <http://en.wikipedia.org/wiki/File:Ofb_encryption.png>,
in OFB, you encrypt the IV with the key with the chosen block cipher algorithm and then XOR that
against the plaintext to get the ciphertext. How do you do that at the "byte level"? Do
you do substrings or something?
------------------------------------------------------------------------
[2010-06-01 12:22:07] me at haravikk dot com
You're using the wrong OFB mode, you need to use MCRYPT_MODE_NOFB.
MCRYPT_MODE_OFB is per-byte, while MCRYPT_MODE_NOFB is per-block and gives the
result you were expecting.
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=51146
--
Edit this bug report at https://bugs.php.net/bug.php?id=51146&edit=1