Merge pull request #926 from terrafrost/iv-or-exception

Crypt/Base: throw an exception if an IV is required but not defined
This commit is contained in:
terrafrost 2016-01-21 10:20:44 -06:00
commit e38cc4adb7
8 changed files with 25 additions and 8 deletions

View File

@ -150,7 +150,7 @@ abstract class Base
* @var string * @var string
* @access private * @access private
*/ */
var $iv; var $iv = false;
/** /**
* A "sliding" Initialization Vector * A "sliding" Initialization Vector
@ -500,10 +500,9 @@ abstract class Base
} }
/** /**
* Sets the initialization vector. (optional) * Sets the initialization vector.
* *
* SetIV is not required when self::MODE_ECB (or ie for AES: \phpseclib\Crypt\AES::MODE_ECB) is being used. If not explicitly set, it'll be assumed * setIV() is not required when self::MODE_ECB (or ie for AES: \phpseclib\Crypt\AES::MODE_ECB) is being used.
* to be all zero's.
* *
* @access public * @access public
* @param string $iv * @param string $iv
@ -511,8 +510,10 @@ abstract class Base
*/ */
function setIV($iv) function setIV($iv)
{ {
if ($this->mode == self::MODE_ECB) { switch ($this->mode) {
return; case self::MODE_ECB:
case self::MODE_STREAM:
return;
} }
$this->iv = $iv; $this->iv = $iv;
@ -1871,13 +1872,18 @@ abstract class Base
* after disableContinuousBuffer() or on cipher $engine (re)init * after disableContinuousBuffer() or on cipher $engine (re)init
* ie after setKey() or setIV() * ie after setKey() or setIV()
* *
* @access public * @access private
* @internal Could, but not must, extend by the child Crypt_* class * @internal Could, but not must, extend by the child Crypt_* class
* @throws \UnexpectedValueException when an IV is required but not defined
*/ */
function _clearBuffers() function _clearBuffers()
{ {
$this->enbuffer = $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); $this->enbuffer = $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
if ($this->iv === false && !in_array($this->mode, array(self::MODE_STREAM, self::MODE_ECB))) {
throw new \UnexpectedValueException('No IV has been defined');
}
// mcrypt's handling of invalid's $iv: // mcrypt's handling of invalid's $iv:
// $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size); // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size);
$this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0"); $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");

View File

@ -132,6 +132,7 @@ class PuTTY
if ($encryption != 'none') { if ($encryption != 'none') {
$crypto->setKey($symkey); $crypto->setKey($symkey);
$crypto->setIV(str_repeat("\0", $crypto->getBlockLength() >> 3));
$crypto->disablePadding(); $crypto->disablePadding();
$private = $crypto->decrypt($private); $private = $crypto->decrypt($private);
if ($private === false) { if ($private === false) {
@ -263,6 +264,7 @@ class PuTTY
$crypto = new AES(); $crypto = new AES();
$crypto->setKey(static::generateSymmetricKey($password, 32)); $crypto->setKey(static::generateSymmetricKey($password, 32));
$crypto->setIV(str_repeat("\0", $crypto->getBlockLength() >> 3));
$crypto->disablePadding(); $crypto->disablePadding();
$private = $crypto->encrypt($private); $private = $crypto->encrypt($private);
$hashkey = 'putty-private-key-file-mac-key' . $password; $hashkey = 'putty-private-key-file-mac-key' . $password;

View File

@ -104,6 +104,7 @@ abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
$aes->setPreferredEngine($this->engine); $aes->setPreferredEngine($this->engine);
$aes->disablePadding(); $aes->disablePadding();
$aes->setKey(pack('H*', '2b7e151628aed2a6abf7158809cf4f3c762e7160')); // 160-bit key. Valid in Rijndael. $aes->setKey(pack('H*', '2b7e151628aed2a6abf7158809cf4f3c762e7160')); // 160-bit key. Valid in Rijndael.
$aes->setIV(str_repeat("\0", 16));
//$this->_checkEngine($aes); // should only work in internal mode //$this->_checkEngine($aes); // should only work in internal mode
$ciphertext = $aes->encrypt(pack('H*', '3243f6a8885a308d313198a2e0370734')); $ciphertext = $aes->encrypt(pack('H*', '3243f6a8885a308d313198a2e0370734'));
$this->assertEquals($ciphertext, pack('H*', '231d844639b31b412211cfe93712b880')); $this->assertEquals($ciphertext, pack('H*', '231d844639b31b412211cfe93712b880'));
@ -120,6 +121,7 @@ abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
$aes->setPreferredEngine($this->engine); $aes->setPreferredEngine($this->engine);
$aes->disablePadding(); $aes->disablePadding();
$aes->setKey(pack('H*', '2b7e151628aed2a6abf7158809cf4f3c762e7160')); // 160-bit key. AES should null pad to 192-bits $aes->setKey(pack('H*', '2b7e151628aed2a6abf7158809cf4f3c762e7160')); // 160-bit key. AES should null pad to 192-bits
$aes->setIV(str_repeat("\0", 16));
$this->_checkEngine($aes); $this->_checkEngine($aes);
$ciphertext = $aes->encrypt(pack('H*', '3243f6a8885a308d313198a2e0370734')); $ciphertext = $aes->encrypt(pack('H*', '3243f6a8885a308d313198a2e0370734'));
$this->assertEquals($ciphertext, pack('H*', 'c109292b173f841b88e0ee49f13db8c0')); $this->assertEquals($ciphertext, pack('H*', 'c109292b173f841b88e0ee49f13db8c0'));
@ -355,6 +357,7 @@ abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
$aes = new AES(); $aes = new AES();
$aes->setKeyLength(128); $aes->setKeyLength(128);
$aes->setKey(str_repeat('a', 24)); $aes->setKey(str_repeat('a', 24));
$aes->setIV(str_repeat("\0", 16));
$this->assertSame($aes->getKeyLength(), 128); $this->assertSame($aes->getKeyLength(), 128);
$ciphertext = bin2hex($aes->encrypt('a')); $ciphertext = bin2hex($aes->encrypt('a'));
$this->assertSame($ciphertext, '82b7b068dfc60ed2a46893b69fecd6c2'); $this->assertSame($ciphertext, '82b7b068dfc60ed2a46893b69fecd6c2');
@ -366,6 +369,7 @@ abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
$aes = new AES(); $aes = new AES();
$aes->setKeyLength(256); $aes->setKeyLength(256);
$aes->setKey(str_repeat('a', 16)); $aes->setKey(str_repeat('a', 16));
$aes->setIV(str_repeat("\0", 16));
$this->assertSame($aes->getKeyLength(), 256); $this->assertSame($aes->getKeyLength(), 256);
$ciphertext = bin2hex($aes->encrypt('a')); $ciphertext = bin2hex($aes->encrypt('a'));
$this->assertSame($ciphertext, 'fd4250c0d234aa7e1aa592820aa8406b'); $this->assertSame($ciphertext, 'fd4250c0d234aa7e1aa592820aa8406b');

View File

@ -75,6 +75,7 @@ class Unit_Crypt_BlowfishTest extends PhpseclibTestCase
{ {
$bf = new Blowfish(); $bf = new Blowfish();
$bf->setKey($key); $bf->setKey($key);
$bf->setIV(str_repeat("\0", $bf->getBlockLength() >> 3));
if (!$bf->isValidEngine($engine)) { if (!$bf->isValidEngine($engine)) {
self::markTestSkipped('Unable to initialize ' . $engineName . ' engine'); self::markTestSkipped('Unable to initialize ' . $engineName . ' engine');
} }

View File

@ -51,7 +51,7 @@ class Unit_Crypt_DESTest extends PhpseclibTestCase
$des->disablePadding(); $des->disablePadding();
// when the key and iv are not specified they should be null padded // when the key and iv are not specified they should be null padded
//$des->setKey(); //$des->setKey();
//$des->setIV(); $des->setIV('');
$des->setPreferredEngine(Base::ENGINE_INTERNAL); $des->setPreferredEngine(Base::ENGINE_INTERNAL);
$internal = $des->decrypt('d'); $internal = $des->decrypt('d');

View File

@ -114,6 +114,7 @@ class Unit_Crypt_RC2Test extends PhpseclibTestCase
$rc2->disablePadding(); $rc2->disablePadding();
$rc2->setKeyLength($keyLen); $rc2->setKeyLength($keyLen);
$rc2->setKey(pack('H*', $key)); // could also do $rc2->setKey(pack('H*', $key), $keyLen) $rc2->setKey(pack('H*', $key)); // could also do $rc2->setKey(pack('H*', $key), $keyLen)
$rc2->setIV(str_repeat("\0", $rc2->getBlockLength() >> 3));
if (!$rc2->isValidEngine($engine)) { if (!$rc2->isValidEngine($engine)) {
self::markTestSkipped('Unable to initialize ' . $engineName . ' engine'); self::markTestSkipped('Unable to initialize ' . $engineName . ' engine');
} }

View File

@ -110,6 +110,7 @@ class Unit_Crypt_TripleDESTest extends PhpseclibTestCase
} }
$des->setPreferredEngine($engine); $des->setPreferredEngine($engine);
$des->setKey($key); $des->setKey($key);
$des->setIV(str_repeat("\0", $des->getBlockLength() >> 3));
$des->disablePadding(); $des->disablePadding();
$result = $des->encrypt($plaintext); $result = $des->encrypt($plaintext);
$plaintext = bin2hex($plaintext); $plaintext = bin2hex($plaintext);
@ -176,6 +177,7 @@ class Unit_Crypt_TripleDESTest extends PhpseclibTestCase
$des = new TripleDES(TripleDES::MODE_3CBC); $des = new TripleDES(TripleDES::MODE_3CBC);
$des->setKey('abcdefghijklmnopqrstuvwx'); $des->setKey('abcdefghijklmnopqrstuvwx');
$des->setIV(str_repeat("\0", $des->getBlockLength() >> 3));
foreach ($this->engines as $engine => $engineName) { foreach ($this->engines as $engine => $engineName) {
$des->setPreferredEngine($engine); $des->setPreferredEngine($engine);

View File

@ -20,6 +20,7 @@ class Unit_Crypt_TwofishTest extends PhpseclibTestCase
foreach ($engines as $engine => $name) { foreach ($engines as $engine => $name) {
$tf = new Twofish(); $tf = new Twofish();
$tf->setIV(str_repeat("\0", $tf->getBlockLength() >> 3));
$tf->disablePadding(); $tf->disablePadding();
// tests from https://www.schneier.com/code/ecb_ival.txt // tests from https://www.schneier.com/code/ecb_ival.txt