Merge pull request #453 from terrafrost/aes-fix

Rijndael, AES: adjustments to what key sizes are and aren't allowed

* terrafrost/aes-fix:
  AES: don't do mcrypt unit tests if mcrypt extension is not available
  AES: a few final changes
  AES: set CRYPT_RIJNDAEL_MODE as well in unit tests
  AES: CS changes to unit tests
  AES: more unit test fixes
  AES: unit test updates
  AES: more unit test fixes
  AES: add new lines to end of unit tests
  AES: CS adjustments to unit tests
  AES: first attempt at unit tests for key padding
  Rijndael, AES: adjustments to what key sizes are and aren't allowed
This commit is contained in:
Andreas Fischer 2014-08-15 16:27:31 +02:00
commit 0d7e9199ef
6 changed files with 184 additions and 80 deletions

View File

@ -152,4 +152,56 @@ class Crypt_AES extends Crypt_Rijndael
{
return;
}
/**
* Sets the key length
*
* Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
*
* @see Crypt_Rijndael:setKeyLength()
* @access public
* @param Integer $length
*/
function setKeyLength($length)
{
switch ($length) {
case 160:
$length = 192;
break;
case 224:
$length = 256;
}
parent::setKeyLength($length);
}
/**
* Sets the key.
*
* Rijndael supports five different key lengths, AES only supports three.
*
* @see Crypt_Rijndael:setKey()
* @see setKeyLength()
* @access public
* @param String $key
*/
function setKey($key)
{
parent::setKey($key);
if (!$this->explicit_key_length) {
$length = strlen($key);
switch (true) {
case $length <= 16:
$this->key_size = 16;
break;
case $length <= 24:
$this->key_size = 24;
break;
default:
$this->key_size = 32;
}
$this->_setupEngine();
}
}
}

View File

@ -702,9 +702,15 @@ class Crypt_Rijndael extends Crypt_Base
case $length <= 16:
$this->key_size = 16;
break;
case $length <= 20:
$this->key_size = 20;
break;
case $length <= 24:
$this->key_size = 24;
break;
case $length <= 28:
$this->key_size = 28;
break;
default:
$this->key_size = 32;
}

View File

@ -1,72 +0,0 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright MMXIII Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
class Unit_Crypt_AES_ContinuousBufferTest extends Unit_Crypt_AES_TestCase
{
// String intented
protected $modes = array(
'CRYPT_AES_MODE_CTR',
'CRYPT_AES_MODE_OFB',
'CRYPT_AES_MODE_CFB',
);
protected $plaintexts = array(
'',
'12345678901234567', // https://github.com/phpseclib/phpseclib/issues/39
"\xDE\xAD\xBE\xAF",
':-):-):-):-):-):-)', // https://github.com/phpseclib/phpseclib/pull/43
);
protected $ivs = array(
'',
'test123',
);
protected $keys = array(
'',
':-8', // https://github.com/phpseclib/phpseclib/pull/43
'FOOBARZ',
);
/**
* Produces all combinations of test values.
*
* @return array
*/
public function allCombinations()
{
$result = array();
// @codingStandardsIgnoreStart
foreach ($this->modes as $mode)
foreach ($this->plaintexts as $plaintext)
foreach ($this->ivs as $iv)
foreach ($this->keys as $key)
$result[] = array($mode, $plaintext, $iv, $key);
// @codingStandardsIgnoreEnd
return $result;
}
/**
* @dataProvider allCombinations
*/
public function testEncryptDecrypt($mode, $plaintext, $iv, $key)
{
$aes = new Crypt_AES(constant($mode));
$aes->enableContinuousBuffer();
$aes->setIV($iv);
$aes->setKey($key);
$actual = '';
for ($i = 0, $strlen = strlen($plaintext); $i < $strlen; ++$i) {
$actual .= $aes->decrypt($aes->encrypt($plaintext[$i]));
}
$this->assertEquals($plaintext, $actual);
}
}

View File

@ -0,0 +1,17 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright MMXIII Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
class Unit_Crypt_AES_InternalTest extends Unit_Crypt_AES_TestCase
{
static public function setUpBeforeClass()
{
parent::setUpBeforeClass();
self::ensureConstant('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL);
self::ensureConstant('CRYPT_RIJNDAEL_MODE', CRYPT_RIJNDAEL_MODE_INTERNAL);
}
}

View File

@ -0,0 +1,21 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright MMXIII Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
class Unit_Crypt_AES_McryptTest extends Unit_Crypt_AES_TestCase
{
static public function setUpBeforeClass()
{
if (!extension_loaded('mcrypt')) {
self::markTestSkipped('mcrypt extension is not available.');
}
parent::setUpBeforeClass();
self::ensureConstant('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT);
self::ensureConstant('CRYPT_RIJNDAEL_MODE', CRYPT_RIJNDAEL_MODE_MCRYPT);
}
}

View File

@ -11,17 +11,97 @@ abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
{
static public function setUpBeforeClass()
{
if (!defined('CRYPT_AES_MODE')) {
define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL);
}
parent::setUpBeforeClass();
self::reRequireFile('Crypt/Rijndael.php');
self::reRequireFile('Crypt/AES.php');
}
public function setUp()
/**
* Produces all combinations of test values.
*
* @return array
*/
public function continuousBufferCombos()
{
if (defined('CRYPT_AES_MODE') && CRYPT_AES_MODE !== CRYPT_AES_MODE_INTERNAL) {
$this->markTestSkipped(
'Skipping test because CRYPT_AES_MODE is not defined as CRYPT_AES_MODE_INTERNAL.'
);
$modes = array(
'CRYPT_AES_MODE_CTR',
'CRYPT_AES_MODE_OFB',
'CRYPT_AES_MODE_CFB',
);
$plaintexts = array(
'',
'12345678901234567', // https://github.com/phpseclib/phpseclib/issues/39
"\xDE\xAD\xBE\xAF",
':-):-):-):-):-):-)', // https://github.com/phpseclib/phpseclib/pull/43
);
$ivs = array(
'',
'test123',
);
$keys = array(
'',
':-8', // https://github.com/phpseclib/phpseclib/pull/43
'FOOBARZ',
);
$result = array();
// @codingStandardsIgnoreStart
foreach ($modes as $mode)
foreach ($plaintexts as $plaintext)
foreach ($ivs as $iv)
foreach ($keys as $key)
$result[] = array($mode, $plaintext, $iv, $key);
// @codingStandardsIgnoreEnd
return $result;
}
/**
* @dataProvider continuousBufferCombos
*/
public function testEncryptDecryptWithContinuousBuffer($mode, $plaintext, $iv, $key)
{
$aes = new Crypt_AES(constant($mode));
$aes->enableContinuousBuffer();
$aes->setIV($iv);
$aes->setKey($key);
$actual = '';
for ($i = 0, $strlen = strlen($plaintext); $i < $strlen; ++$i) {
$actual .= $aes->decrypt($aes->encrypt($plaintext[$i]));
}
$this->assertEquals($plaintext, $actual);
}
/**
* @group github451
*/
public function testKeyPaddingRijndael()
{
// this test case is from the following URL:
// https://web.archive.org/web/20070209120224/http://fp.gladman.plus.com/cryptography_technology/rijndael/aesdvec.zip
$aes = new Crypt_Rijndael();
$aes->disablePadding();
$aes->setKey(pack('H*', '2b7e151628aed2a6abf7158809cf4f3c762e7160')); // 160-bit key. Valid in Rijndael.
$ciphertext = $aes->encrypt(pack('H*', '3243f6a8885a308d313198a2e0370734'));
$this->assertEquals($ciphertext, pack('H*', '231d844639b31b412211cfe93712b880'));
}
/**
* @group github451
*/
public function testKeyPaddingAES()
{
// same as the above - just with a different ciphertext
$aes = new Crypt_AES();
$aes->disablePadding();
$aes->setKey(pack('H*', '2b7e151628aed2a6abf7158809cf4f3c762e7160')); // 160-bit key. AES should null pad to 192-bits
$ciphertext = $aes->encrypt(pack('H*', '3243f6a8885a308d313198a2e0370734'));
$this->assertEquals($ciphertext, pack('H*', 'c109292b173f841b88e0ee49f13db8c0'));
}
}