Skip to content

Commit 4a31f43

Browse files
committed
lots of updates to stream filter + expanded unit tests
1 parent bf79277 commit 4a31f43

File tree

2 files changed

+78
-15
lines changed

2 files changed

+78
-15
lines changed

lib/mcrypt.php

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,22 @@ class phpseclib_mcrypt_filter extends php_user_filter
853853
*/
854854
private $op;
855855

856+
/**
857+
* Buffer for ECB / CBC
858+
*
859+
* @var string
860+
* @access private
861+
*/
862+
private $buffer = '';
863+
864+
/**
865+
* Cipher block length
866+
*
867+
* @var int
868+
* @access private
869+
*/
870+
private $block_length = '';
871+
856872
/**
857873
* Called when applying the filter
858874
*
@@ -869,16 +885,28 @@ class phpseclib_mcrypt_filter extends php_user_filter
869885
*/
870886
function filter($in, $out, &$consumed, $closing)
871887
{
888+
$newlen = 0;
889+
$block_mode = $this->cipher->mode == Base::MODE_CBC || $this->cipher->mode == Base::MODE_ECB;
872890
while ($bucket = stream_bucket_make_writeable($in)) {
873-
$bucket->data = $this->opt ?
891+
if ($block_mode) {
892+
$bucket->data = $this->buffer . $bucket->data;
893+
$extra = strlen($bucket->data) % $this->block_length;
894+
if ($extra) {
895+
$this->buffer = substr($bucket->data, -$extra);
896+
$bucket->data = substr($bucket->data, 0, -$extra);
897+
}
898+
}
899+
900+
$bucket->data = $this->op ?
874901
$this->cipher->encrypt($bucket->data) :
875902
$this->cipher->decrypt($bucket->data);
903+
$newlen+= strlen($bucket->data);
876904
$consumed+= $bucket->datalen;
905+
877906
stream_bucket_append($out, $bucket);
878907
}
879908

880-
// can also return PSFS_FEED_ME and PSFS_ERR_FATAL
881-
return PSFS_PASS_ON;
909+
return $block_mode && $newlen < $this->block_length ? PSFS_FEED_ME : PSFS_PASS_ON;
882910
}
883911

884912
/**
@@ -910,7 +938,7 @@ function onCreate()
910938
substr($this->filtername, 10) :
911939
$this->filtername;
912940
$parts = explode('.', $filtername);
913-
if ($parts != 2) {
941+
if (count($parts) != 2) {
914942
user_error('stream_filter_append(): Could not open encryption module');
915943
return false;
916944
}
@@ -929,11 +957,13 @@ function onCreate()
929957
return false;
930958
}
931959

932-
$cipher->setKey($key);
933-
$cipher->setIV($iv);
960+
$cipher->enableContinuousBuffer();
961+
$cipher->setKey($this->params['key']);
962+
$cipher->setIV($this->params['iv']);
934963

935964
$this->op = $parts[0] == 'mcrypt';
936965
$this->cipher = $cipher;
966+
$this->block_length = phpseclib_mcrypt_enc_get_iv_size($cipher);
937967

938968
return true;
939969
}

tests/MCryptCompatTest.php

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ public function testAESBasicSuccess()
1919
// a plaintext / ciphertext of length 1 is of an insufficient length for cbc mode
2020
$plaintext = str_repeat('a', 16);
2121

22-
$mcrypt = bin2hex(mcrypt_encrypt('rijndael-128', $key, $plaintext, 'cbc', $iv));
23-
$compat = bin2hex(phpseclib_mcrypt_encrypt('rijndael-128', $key, $plaintext, 'cbc', $iv));
24-
$this->assertEquals($mcrypt, $compat);
22+
$mcrypt = mcrypt_encrypt('rijndael-128', $key, $plaintext, 'cbc', $iv);
23+
$compat = phpseclib_mcrypt_encrypt('rijndael-128', $key, $plaintext, 'cbc', $iv);
24+
$this->assertEquals(bin2hex($mcrypt), bin2hex($compat));
2525

2626
$ciphertext = $mcrypt;
2727

@@ -112,26 +112,59 @@ public function testNullPadding()
112112
public function testStream()
113113
{
114114
$passphrase = 'My secret';
115+
$plaintext = 'Secret secret secret data';
116+
117+
$iv = substr(md5('iv' . $passphrase, true), 0, 8);
118+
$key = substr(md5('pass1' . $passphrase, true) .
119+
md5('pass2' . $passphrase, true), 0, 24);
120+
$opts = array('iv' => $iv, 'key' => $key);
115121

116-
$iv = substr(md5('iv'.$passphrase, true), 0, 8);
117-
$key = substr(md5('pass1'.$passphrase, true) .
118-
md5('pass2'.$passphrase, true), 0, 24);
119-
$opts = array('iv'=>$iv, 'key'=>$key);
122+
$expected = substr($plaintext . $plaintext, 0, 48);
120123

121124
$fp = fopen('php://memory', 'wb+');
122125
stream_filter_append($fp, 'mcrypt.tripledes', STREAM_FILTER_WRITE, $opts);
123-
fwrite($fp, 'Secret secret secret data');
126+
fwrite($fp, $plaintext . $plaintext);
127+
rewind($fp);
128+
$reference = bin2hex(fread($fp, 1024));
129+
fclose($fp);
130+
131+
$fp = fopen('php://memory', 'wb+');
132+
stream_filter_append($fp, 'mcrypt.tripledes', STREAM_FILTER_WRITE, $opts);
133+
fwrite($fp, $plaintext);
134+
fwrite($fp, $plaintext);
124135
rewind($fp);
125136
$mcrypt = bin2hex(fread($fp, 1024));
137+
stream_filter_append($fp, 'mdecrypt.tripledes', STREAM_FILTER_READ, $opts);
138+
rewind($fp);
139+
$decrypted = fread($fp, 1024);
126140
fclose($fp);
127141

142+
// this demonstrates that streams operate in continuous mode
143+
$this->assertEquals($reference, $mcrypt);
144+
145+
// this demonstrates how to decrypt encrypted data
146+
$this->assertEquals($expected, $decrypted);
147+
128148
$fp = fopen('php://memory', 'wb+');
129149
stream_filter_append($fp, 'phpseclib.mcrypt.tripledes', STREAM_FILTER_WRITE, $opts);
130-
fwrite($fp, 'Secret secret secret data');
150+
fwrite($fp, $plaintext);
151+
fwrite($fp, $plaintext);
131152
rewind($fp);
132153
$compat = bin2hex(fread($fp, 1024));
154+
stream_filter_append($fp, 'phpseclib.mdecrypt.tripledes', STREAM_FILTER_READ, $opts);
155+
rewind($fp);
156+
$decrypted = fread($fp, 1024);
133157
fclose($fp);
134158

159+
// this demonstrates that mcrypt's stream and phpseclib's stream's have identical output
135160
$this->assertEquals($mcrypt, $compat);
161+
162+
// this demonstrates that phpseclib's stream successfully decrypts the encrypted string
163+
// since both mcrypt and phpseclib successfully decrypt to the same thing the outputs can be assumed to be matching
164+
$this->assertEquals($expected, $decrypted);
165+
166+
// in the case of cbc the length is a multiple of the block size. extra characters are added
167+
// when enough are present for another block to be added
168+
$this->assertNotEquals(strlen($mcrypt), strlen($plaintext) * 2);
136169
}
137170
}

0 commit comments

Comments
 (0)