Bug #51146 [Com]: mcrypt doesn't do OFB mode correctly

From: Date: Tue, 10 Jan 2017 12:06:26 +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-206459@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: php at haravikk dot me Reported by: zelnaga at gmail dot com Summary: mcrypt doesn't do OFB mode correctly Status: Wont fix Type: Bug Package: mcrypt related Operating System: Windows XP PHP Version: 5.3.1 Assigned To: leigh Block user comment: N Private report: N New Comment: I'm sorry but I believe this has been closed prematurely; as I have pointed out, mcrypt is in fact operating correctly, the issue here is that the behaviour of its CFB and OFB modes is misleading as it is per-byte, rather than per-state size block. The solution is to use the MCRYPT_MODE_NOFB constant, or to request ncfb mode via string, as the n signifies that these are scaled to the size of the state/key, so 128, 192 or 256 bits. As I stated in my earlier comment, the problem is in fact on the PHP side in so far as there is no MCRYPT_MODE_NCFB constant, and that the documentation for the CFB and OFB constants do not clarify that these are per-byte modes of operation. I believe that these are therefore issues with PHP's libmcrypt wrapper, not libmcrypt itself, and should be resolvable (especially after nearly seven years!) Previous Comments: ------------------------------------------------------------------------ [2016-12-14 23:47:59] leigh@php.net Closing because it's not PHP implementing the encryption modes, it's libmcrypt which is unmaintained. The assumption that encrypting in OFB and decrypting in ECB should yield the IV at the start of the plaintext (where the original plaintext is entirely null bytes) is correct. If mcrypt does not do this, it is a problem with the third party library, the PHP module is just a wrapper. ------------------------------------------------------------------------ [2013-11-25 19:38:06] ywarnier at beeznest dot org Sorry, I forgot to mention (if that has any incidence on this report) I use PHP 5.5.3 (mod_php5) with the mcrypt module for 5.4.6. How is that even possible, I don't know, but that's what my dear Ubuntu is telling me... moving back to Debian soon, I swear :-p ------------------------------------------------------------------------ [2013-11-25 19:30:44] ywarnier at beeznest dot org 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. ------------------------------------------------------------------------ [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! ------------------------------------------------------------------------ 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

« previous php.bugs (#206459) next »