Skip to content

Commit

Permalink
Added support for IGE
Browse files Browse the repository at this point in the history
  • Loading branch information
danog committed Feb 10, 2017
1 parent ab1da5a commit dcf5614
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 7 deletions.
159 changes: 154 additions & 5 deletions phpseclib/Crypt/Common/SymmetricKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ abstract class SymmetricKey
* Encrypt / decrypt using streaming mode.
*/
const MODE_STREAM = 5;
/**
* Encrypt / decrypt using the Infinite Garble Extension mode.
*/
const MODE_IGE = 6;
/**#@-*/

/**#@+
Expand Down Expand Up @@ -452,6 +456,8 @@ abstract class SymmetricKey
*
* - self::MODE_OFB
*
* - self::MODE_IGE
*
* @param int $mode
* @access public
* @throws \InvalidArgumentException if an invalid / unsupported mode is provided
Expand All @@ -468,6 +474,7 @@ public function __construct($mode)
case self::MODE_CFB:
case self::MODE_OFB:
case self::MODE_STREAM:
case self::MODE_IGE:
$this->paddable = false;
break;
default:
Expand All @@ -494,13 +501,16 @@ public function setIV($iv)
throw new \InvalidArgumentException('This mode does not require an IV.');
}

if ($this->mode === self::MODE_IGE && strlen($iv) != $this->block_size*2) {
throw new \LengthException('Received initialization vector of size ' . strlen($iv) . ', but size ' . $this->block_size*2 . ' is required');
} else if ($this->mode !== self::MODE_IGE && strlen($iv) != $this->block_size) {
throw new \LengthException('Received initialization vector of size ' . strlen($iv) . ', but size ' . $this->block_size . ' is required');
}

if (!$this->usesIV()) {
throw new \InvalidArgumentException('This algorithm does not use an IV.');
}

if (strlen($iv) != $this->block_size) {
throw new \LengthException('Received initialization vector of size ' . strlen($iv) . ', but size ' . $this->block_size . ' is required');
}

$this->iv = $iv;
$this->changed = true;
Expand Down Expand Up @@ -840,6 +850,21 @@ public function encrypt($plaintext)
return $result;
case self::MODE_CTR:
return $this->openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer);
case self::MODE_IGE:
$ciphertext = '';
$iv_part_1 = substr($this->encryptIV, 0, $this->block_size);
$iv_part_2 = substr($this->encryptIV, $this->block_size);
for ($i = 0; $i < strlen($plaintext); $i += $this->block_size) {
$indata = substr($plaintext, $i, $this->block_size);
$outdata = openssl_encrypt($indata ^ $iv_part_1, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING) ^ $iv_part_2;
$iv_part_1 = $outdata;
$iv_part_2 = $indata;
$ciphertext .= $outdata;
}
if ($this->continuousBuffer) {
$this->encryptIV = $iv_part_1.$iv_part_2;
}
return $ciphertext;
case self::MODE_CFB:
// cfb loosely routines inspired by openssl's:
// {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
Expand Down Expand Up @@ -958,7 +983,22 @@ public function encrypt($plaintext)

return $ciphertext;
}

if ($this->mode === self::MODE_IGE) {
$ciphertext = '';
$iv_part_1 = substr($this->encryptIV, 0, $this->block_size);
$iv_part_2 = substr($this->encryptIV, $this->block_size);
for ($i = 0; $i < strlen($plaintext); $i += $this->block_size) {
$indata = substr($plaintext, $i, $this->block_size);
$outdata = @mcrypt_generic($this->enmcrypt, $indata ^ $iv_part_1) ^ $iv_part_2;
$iv_part_1 = $outdata;
$iv_part_2 = $indata;
$ciphertext .= $outdata;
}
if ($this->continuousBuffer) {
$this->encryptIV = $iv_part_1.$iv_part_2;
}
return $ciphertext;
}
$ciphertext = @mcrypt_generic($this->enmcrypt, $plaintext);

if (!$this->continuousBuffer) {
Expand Down Expand Up @@ -986,6 +1026,20 @@ public function encrypt($plaintext)
$ciphertext.= $this->encryptBlock(substr($plaintext, $i, $block_size));
}
break;
case self::MODE_IGE:
$iv_part_1 = substr($this->encryptIV, 0, $this->block_size);
$iv_part_2 = substr($this->encryptIV, $this->block_size);
for ($i = 0; $i < strlen($plaintext); $i += $this->block_size) {
$indata = substr($plaintext, $i, $this->block_size);
$outdata = $this->encryptBlock($indata ^ $iv_part_1) ^ $iv_part_2;
$iv_part_1 = $outdata;
$iv_part_2 = $indata;
$ciphertext .= $outdata;
}
if ($this->continuousBuffer) {
$this->encryptIV = $iv_part_1.$iv_part_2;
}
break;
case self::MODE_CBC:
$xor = $this->encryptIV;
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
Expand Down Expand Up @@ -1139,9 +1193,26 @@ public function decrypt($ciphertext)
$this->decryptIV = substr($ciphertext, -$offset, $this->block_size);
}
break;
case self::MODE_IGE:
$plaintext = '';
$iv_part_1 = substr($this->decryptIV, 0, $this->block_size);
$iv_part_2 = substr($this->decryptIV, $this->block_size);
for ($i = 0; $i < strlen($ciphertext); $i += $this->block_size) {
$indata = substr($ciphertext, $i, $this->block_size);
$outdata = openssl_decrypt($indata ^ $iv_part_2, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING) ^ $iv_part_1;
$iv_part_1 = $indata;
$iv_part_2 = $outdata;
$plaintext .= $outdata;
}
if ($this->continuousBuffer) {
$this->decryptIV = $iv_part_1.$iv_part_2;
}
break;

case self::MODE_CTR:
$plaintext = $this->openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer);
break;

case self::MODE_CFB:
// cfb loosely routines inspired by openssl's:
// {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
Expand Down Expand Up @@ -1242,6 +1313,22 @@ public function decrypt($ciphertext)

return $plaintext;
}
if ($this->mode === self::MODE_IGE) {
$plaintext = '';
$iv_part_1 = substr($this->decryptIV, 0, $this->block_size);
$iv_part_2 = substr($this->decryptIV, $this->block_size);
for ($i = 0; $i < strlen($ciphertext); $i += $this->block_size) {
$indata = substr($ciphertext, $i, $this->block_size);
$outdata = @mcrypt_generic($this->demcrypt, $indata ^ $iv_part_2) ^ $iv_part_1;
$iv_part_1 = $indata;
$iv_part_2 = $outdata;
$plaintext .= $outdata;
}
if ($this->continuousBuffer) {
$this->decryptIV = $iv_part_1.$iv_part_2;
}
return $plaintext;
}

$plaintext = @mdecrypt_generic($this->demcrypt, $ciphertext);

Expand Down Expand Up @@ -1282,6 +1369,20 @@ public function decrypt($ciphertext)
$this->decryptIV = $xor;
}
break;
case self::MODE_IGE:
$iv_part_1 = substr($this->decryptIV, 0, $this->block_size);
$iv_part_2 = substr($this->decryptIV, $this->block_size);
for ($i = 0; $i < strlen($ciphertext); $i += $this->block_size) {
$indata = substr($ciphertext, $i, $this->block_size);
$outdata = $this->decryptBlock($indata ^ $iv_part_2) ^ $iv_part_1;
$iv_part_1 = $indata;
$iv_part_2 = $outdata;
$plaintext .= $outdata;
}
if ($this->continuousBuffer) {
$this->decryptIV = $iv_part_1.$iv_part_2;
}
break;
case self::MODE_CTR:
$xor = $this->decryptIV;
if (strlen($buffer['ciphertext'])) {
Expand Down Expand Up @@ -1553,6 +1654,7 @@ protected function openssl_translate_mode()
{
switch ($this->mode) {
case self::MODE_ECB:
case self::MODE_IGE:
return 'ecb';
case self::MODE_CBC:
return 'cbc';
Expand Down Expand Up @@ -1906,6 +2008,7 @@ private function setupMcrypt()
if (!isset($this->enmcrypt)) {
static $mcrypt_modes = [
self::MODE_CTR => 'ctr',
self::MODE_IGE => MCRYPT_MODE_ECB,
self::MODE_ECB => MCRYPT_MODE_ECB,
self::MODE_CBC => MCRYPT_MODE_CBC,
self::MODE_CFB => 'ncfb',
Expand All @@ -1919,7 +2022,7 @@ private function setupMcrypt()
// we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer()
// to workaround mcrypt's broken ncfb implementation in buffered mode
// see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
if ($this->mode == self::MODE_CFB) {
if ($this->mode === self::MODE_CFB) {
$this->ecb = @mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
}
} // else should mcrypt_generic_deinit be called?
Expand Down Expand Up @@ -2520,6 +2623,52 @@ protected function createInlineCryptFunction($cipher_code)
$decrypt = $init_decrypt . '
$_plaintext = "";
'.$decrypt_block.'
return $_plaintext;
';
break;
case self::MODE_IGE:
$encrypt = $init_encrypt . '
$_ciphertext = "";
$_plaintext_len = strlen($_text);
$_iv_part_1 = substr($this->encryptIV, 0, '.$block_size.');
$_iv_part_2 = substr($this->encryptIV, '.$block_size.');
for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
$in = ($indata = substr($_text, $_i, '.$block_size.')) ^ $_iv_part_1;
'.$encrypt_block.'
$outdata = $in ^ $_iv_part_2;
$_iv_part_1 = $outdata;
$_iv_part_2 = $indata;
$_ciphertext .= $outdata;
}
if ($this->continuousBuffer) {
$this->encryptIV = $_iv_part_1.$_iv_part_2;
}
return $_ciphertext;
';

$decrypt = $init_decrypt . '
$_plaintext = "";
$_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
$_ciphertext_len = strlen($_text);
$_iv_part_1 = substr($this->decryptIV, 0, '.$block_size.');
$_iv_part_2 = substr($this->decryptIV, '.$block_size.');
for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
$in = ($indata = substr($_text, $_i, '.$block_size.')) ^ $_iv_part_2;
'.$decrypt_block.'
$outdata = $in ^ $_iv_part_1;
$_iv_part_1 = $indata;
$_iv_part_2 = $outdata;
$_plaintext .= $outdata;
}
if ($this->continuousBuffer) {
$this->decryptIV = $_iv_part_1.$_iv_part_2;
}
return $_plaintext;
';
break;
Expand Down
7 changes: 5 additions & 2 deletions tests/Unit/Crypt/AES/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public function continuousBufferCombos()
BlockCipher::MODE_CTR,
BlockCipher::MODE_OFB,
BlockCipher::MODE_CFB,
BlockCipher::MODE_IGE,
);
$plaintexts = array(
'',
Expand All @@ -61,6 +62,7 @@ public function continuousBufferCombos()
foreach ($modes as $mode) {
foreach ($plaintexts as $plaintext) {
foreach ($ivs as $iv) {
if ($mode === BlockCipher::MODE_IGE) $iv .= strrev($iv);
foreach ($keys as $key) {
$result[] = array($mode, $plaintext, $iv, $key);
}
Expand Down Expand Up @@ -139,6 +141,7 @@ public function continuousBufferBatteryCombos()
BlockCipher::MODE_CTR,
BlockCipher::MODE_OFB,
BlockCipher::MODE_CFB,
BlockCipher::MODE_IGE,
);

$combos = array(
Expand Down Expand Up @@ -176,7 +179,7 @@ public function continuousBufferBatteryCombos()
*/
public function testContinuousBufferBattery($op, $mode, $test)
{
$iv = str_repeat('x', 16);
$iv = str_repeat('x', 16*($mode === BlockCipher::MODE_IGE ? 2 : 1));
$key = str_repeat('a', 16);

$aes = new AES($mode);
Expand Down Expand Up @@ -227,7 +230,7 @@ public function testNonContinuousBufferBattery($op, $mode, $test)
return;
}

$iv = str_repeat('x', 16);
$iv = str_repeat('x', 16*($mode === BlockCipher::MODE_IGE ? 2 : 1));
$key = str_repeat('a', 16);

$aes = new AES($mode);
Expand Down

0 comments on commit dcf5614

Please sign in to comment.