mirror of
https://github.com/phpseclib/phpseclib.git
synced 2024-11-18 11:15:12 +00:00
AES: Fix broken CFB and disableContinuousBuffer()
Related to: https://github.com/phpseclib/phpseclib/pull/45
This commit is contained in:
parent
46baf1815f
commit
20461866ef
@ -293,7 +293,6 @@ class Crypt_AES extends Crypt_Rijndael {
|
|||||||
function encrypt($plaintext)
|
function encrypt($plaintext)
|
||||||
{
|
{
|
||||||
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
|
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
|
||||||
$changed = $this->changed;
|
|
||||||
$this->_mcryptSetup();
|
$this->_mcryptSetup();
|
||||||
/*
|
/*
|
||||||
if ($this->mode == CRYPT_AES_MODE_CTR) {
|
if ($this->mode == CRYPT_AES_MODE_CTR) {
|
||||||
@ -310,36 +309,43 @@ class Crypt_AES extends Crypt_Rijndael {
|
|||||||
// using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
|
// using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
|
||||||
// rewritten CFB implementation the above outputs the same thing twice.
|
// rewritten CFB implementation the above outputs the same thing twice.
|
||||||
if ($this->mode == 'ncfb' && $this->continuousBuffer) {
|
if ($this->mode == 'ncfb' && $this->continuousBuffer) {
|
||||||
if ($changed) {
|
$iv = &$this->encryptIV;
|
||||||
$this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
|
$pos = &$this->enbuffer['pos'];
|
||||||
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
|
$len = strlen($plaintext);
|
||||||
}
|
|
||||||
|
|
||||||
$buffer = &$this->enbuffer['encrypted'];
|
|
||||||
|
|
||||||
if (strlen($buffer)) {
|
|
||||||
$ciphertext = $plaintext ^ substr($this->encryptIV, strlen($buffer));
|
|
||||||
$buffer.= $ciphertext;
|
|
||||||
if (strlen($buffer) == 16) {
|
|
||||||
$this->encryptIV = $buffer;
|
|
||||||
$buffer = '';
|
|
||||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
|
||||||
}
|
|
||||||
$plaintext = substr($plaintext, strlen($ciphertext));
|
|
||||||
} else {
|
|
||||||
$ciphertext = '';
|
$ciphertext = '';
|
||||||
|
$i = 0;
|
||||||
|
if ($pos) {
|
||||||
|
$orig_pos = $pos;
|
||||||
|
$max = 16 - $pos;
|
||||||
|
if ($len >= $max) {
|
||||||
|
$i = $max;
|
||||||
|
$len-= $max;
|
||||||
|
$pos = 0;
|
||||||
|
} else {
|
||||||
|
$i = $len;
|
||||||
|
$pos+= $len;
|
||||||
|
$len = 0;
|
||||||
}
|
}
|
||||||
|
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
|
||||||
$last_pos = strlen($plaintext) & 0xFFFFFFF0;
|
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
|
||||||
if ($last_pos) {
|
$this->enbuffer['enmcrypt_init'] = true;
|
||||||
$ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos));
|
|
||||||
$this->encryptIV = substr($ciphertext, -16);
|
|
||||||
}
|
}
|
||||||
|
if ($len >= 16) {
|
||||||
if (strlen($plaintext) & 0xF) {
|
if ($this->enbuffer['enmcrypt_init'] === true) {
|
||||||
$this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV);
|
mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
|
||||||
$buffer = substr($plaintext, $last_pos) ^ $this->encryptIV;
|
$this->enbuffer['enmcrypt_init'] = false;
|
||||||
$ciphertext.= $buffer;
|
}
|
||||||
|
$ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 16));
|
||||||
|
$iv = substr($ciphertext, -16);
|
||||||
|
$i = strlen($ciphertext);
|
||||||
|
$len%= 16;
|
||||||
|
}
|
||||||
|
if ($len) {
|
||||||
|
$iv = mcrypt_generic($this->ecb, $iv);
|
||||||
|
$block = substr($iv, $pos) ^ substr($plaintext, $i);
|
||||||
|
$iv = substr_replace($iv, $block, $pos, $len);
|
||||||
|
$ciphertext.= $block;
|
||||||
|
$pos = $len;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $ciphertext;
|
return $ciphertext;
|
||||||
@ -373,7 +379,6 @@ class Crypt_AES extends Crypt_Rijndael {
|
|||||||
function decrypt($ciphertext)
|
function decrypt($ciphertext)
|
||||||
{
|
{
|
||||||
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
|
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
|
||||||
$changed = $this->changed;
|
|
||||||
$this->_mcryptSetup();
|
$this->_mcryptSetup();
|
||||||
/*
|
/*
|
||||||
if ($this->mode == CRYPT_AES_MODE_CTR) {
|
if ($this->mode == CRYPT_AES_MODE_CTR) {
|
||||||
@ -387,37 +392,44 @@ class Crypt_AES extends Crypt_Rijndael {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if ($this->mode == 'ncfb' && $this->continuousBuffer) {
|
if ($this->mode == 'ncfb' && $this->continuousBuffer) {
|
||||||
if ($changed) {
|
$iv = &$this->decryptIV;
|
||||||
$this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
|
$pos = &$this->debuffer['pos'];
|
||||||
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
|
$len = strlen($ciphertext);
|
||||||
}
|
|
||||||
|
|
||||||
$buffer = &$this->debuffer['ciphertext'];
|
|
||||||
|
|
||||||
if (strlen($buffer)) {
|
|
||||||
$plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer));
|
|
||||||
|
|
||||||
$buffer.= substr($ciphertext, 0, strlen($plaintext));
|
|
||||||
if (strlen($buffer) == 16) {
|
|
||||||
$this->decryptIV = $buffer;
|
|
||||||
$buffer = '';
|
|
||||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
|
||||||
}
|
|
||||||
$ciphertext = substr($ciphertext, strlen($plaintext));
|
|
||||||
} else {
|
|
||||||
$plaintext = '';
|
$plaintext = '';
|
||||||
|
$i = 0;
|
||||||
|
if ($pos) {
|
||||||
|
$orig_pos = $pos;
|
||||||
|
$max = 16 - $pos;
|
||||||
|
if ($len >= $max) {
|
||||||
|
$i = $max;
|
||||||
|
$len-= $max;
|
||||||
|
$pos = 0;
|
||||||
|
} else {
|
||||||
|
$i = $len;
|
||||||
|
$pos+= $len;
|
||||||
|
$len = 0;
|
||||||
}
|
}
|
||||||
|
// ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
|
||||||
$last_pos = strlen($ciphertext) & 0xFFFFFFF0;
|
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
|
||||||
if ($last_pos) {
|
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
|
||||||
$plaintext = mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos));
|
$this->debuffer['demcrypt_init'] = true;
|
||||||
$this->decryptIV = substr($ciphertext, $last_pos - 16, 16);
|
|
||||||
$this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV);
|
|
||||||
}
|
}
|
||||||
|
if ($len >= 16) {
|
||||||
if (strlen($ciphertext) & 0xF) {
|
if ($this->debuffer['demcrypt_init'] === true) {
|
||||||
$buffer = substr($ciphertext, $last_pos);
|
mcrypt_generic_init($this->demcrypt, $this->key, $iv);
|
||||||
$plaintext.= $buffer ^ $this->decryptIV;
|
$this->debuffer['demcrypt_init'] = false;
|
||||||
|
}
|
||||||
|
$cb = substr($ciphertext, $i, $len - $len % 16);
|
||||||
|
$plaintext.= mdecrypt_generic($this->demcrypt, $cb);
|
||||||
|
$iv = substr($cb, -16);
|
||||||
|
$i = strlen($plaintext);
|
||||||
|
$len%= 16;
|
||||||
|
}
|
||||||
|
if ($len) {
|
||||||
|
$iv = mcrypt_generic($this->ecb, $iv);
|
||||||
|
$plaintext.= substr($iv, $pos) ^ substr($ciphertext, $i);
|
||||||
|
$iv = substr_replace($iv, substr($ciphertext, $i, $len), $pos, $len);
|
||||||
|
$pos = $len;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $plaintext;
|
return $plaintext;
|
||||||
@ -488,11 +500,20 @@ class Crypt_AES extends Crypt_Rijndael {
|
|||||||
|
|
||||||
$this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
|
$this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
|
||||||
$this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
|
$this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
|
||||||
|
|
||||||
|
if ($mode == 'ncfb') {
|
||||||
|
$this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
|
||||||
|
}
|
||||||
|
|
||||||
} // else should mcrypt_generic_deinit be called?
|
} // else should mcrypt_generic_deinit be called?
|
||||||
|
|
||||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
|
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
|
||||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
|
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
|
||||||
|
|
||||||
|
if ($this->mode == 'ncfb') {
|
||||||
|
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
|
||||||
|
}
|
||||||
|
|
||||||
$this->changed = false;
|
$this->changed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -608,6 +629,24 @@ class Crypt_AES extends Crypt_Rijndael {
|
|||||||
return pack('N*', $state[0], $state[1], $state[2], $state[3]);
|
return pack('N*', $state[0], $state[1], $state[2], $state[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Treat consecutive "packets" as if they are a continuous buffer.
|
||||||
|
*
|
||||||
|
* The default behavior.
|
||||||
|
*
|
||||||
|
* @see Crypt_Rijndael::disableContinuousBuffer()
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
function enableContinuousBuffer()
|
||||||
|
{
|
||||||
|
parent::enableContinuousBuffer();
|
||||||
|
|
||||||
|
if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) {
|
||||||
|
$this->enbuffer['enmcrypt_init'] = true;
|
||||||
|
$this->debuffer['demcrypt_init'] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Treat consecutive packets as if they are a discontinuous buffer.
|
* Treat consecutive packets as if they are a discontinuous buffer.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user