-
-
Notifications
You must be signed in to change notification settings - Fork 877
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added support for AES IGE #1095
base: master
Are you sure you want to change the base?
Changes from 1 commit
12dc23d
e2f91cc
200c2a9
6d714a6
52c068a
1a730d1
273ad17
4e367c9
0d9dc46
a74a5f7
27370df
3097d29
0aff25e
c85ddd3
2dc68c8
c62fc0c
2dc143a
5e7d391
f715b29
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
/**#@-*/ | ||
|
||
/**#@+ | ||
|
@@ -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 | ||
|
@@ -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: | ||
|
@@ -498,10 +505,12 @@ public function setIV($iv) | |
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'); | ||
if (strlen($iv) != $this->block_size*($this->mode === self::MODE_IGE ? 2 : 1)) { | ||
throw new \LengthException('Received initialization vector of size ' . strlen($iv) . ', but size ' . $this->block_size*($this->mode === self::MODE_IGE ? 2 : 1). ' is required'); | ||
} | ||
|
||
|
||
|
||
$this->iv = $iv; | ||
$this->changed = true; | ||
} | ||
|
@@ -840,6 +849,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 = ''; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This block seems to be (largely) duplicated a bunch of times below. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, but I wasn't sure whether it was a good idea to create a separate function just to avoid duplicating a few lines of code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, what about the problems in the native module? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. bump There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've been on the fence with this. My initial searches led me to conclude that this was a one off mode (and not even a very good one at that) used for only one app: https://www.mgp25.com/AESIGE/ Keeping that in mind, I don't really want to add every homegrown block cipher algorithm under the sun. If Joe Schmoe made his own shitty symmetric key algorithm that no one other than he used should I include that in phpseclib as well if he did a PR? No. There has to be some sort of bar for inclusion. That said, I did a Google search just now. I guess OpenSSL supports this mode: https://lists.gnupg.org/pipermail/gcrypt-devel/2015-September/003572.html So I guess that fact merits reconsideration of this PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with bantu's comment on the code duplication. Seems like you could just call a new method - function handleIGEEncrypt($plaintext) {
$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);
switch ($this->engine) {
self::ENGINE_OPENSSL:
$outdata = openssl_encrypt($indata ^ $iv_part_1, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING) ^ $iv_part_2;
break;
self::ENGINE_MCRYPT:
$outdata = @mcrypt_generic($this->enmcrypt, $indata ^ $iv_part_1) ^ $iv_part_2;
break;
self::ENGINE_INTERNAL:
$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;
}
return $ciphertext;
} I mean, I suppose it's somewhat hypocritical for me to criticize it here when phpseclib does it with CFB mode, but... I just pushed a commit, in a branch, aimed at reducing some of the duplication for CFB mode: https://github.com/terrafrost/phpseclib/tree/cfb-optimization Of course, in this case, I suppose the old addage applies: "if it ain't broke don't fix it". We'll see where that branch goes. |
||
$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} | ||
|
@@ -958,7 +982,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) { | ||
|
@@ -986,6 +1025,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) { | ||
|
@@ -1139,9 +1192,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} | ||
|
@@ -1242,6 +1312,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); | ||
|
||
|
@@ -1282,6 +1368,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'])) { | ||
|
@@ -1553,6 +1653,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'; | ||
|
@@ -1906,6 +2007,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', | ||
|
@@ -1919,7 +2021,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? | ||
|
@@ -2520,6 +2622,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; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,6 +39,7 @@ public function continuousBufferCombos() | |
BlockCipher::MODE_CTR, | ||
BlockCipher::MODE_OFB, | ||
BlockCipher::MODE_CFB, | ||
BlockCipher::MODE_IGE, | ||
); | ||
$plaintexts = array( | ||
'', | ||
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suppose it doesn't matter as much in a unit test but, technically, this is a violation of the PSR-2 coding standards. That should read more like this: if ($mode === BlockCipher::MODE_IGE) {
$iv.= strrev($iv);
} |
||
foreach ($keys as $key) { | ||
$result[] = array($mode, $plaintext, $iv, $key); | ||
} | ||
|
@@ -139,6 +141,7 @@ public function continuousBufferBatteryCombos() | |
BlockCipher::MODE_CTR, | ||
BlockCipher::MODE_OFB, | ||
BlockCipher::MODE_CFB, | ||
BlockCipher::MODE_IGE, | ||
); | ||
|
||
$combos = array( | ||
|
@@ -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); | ||
|
@@ -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); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's introduce a new variable: expected_iv_length
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!