Skip to content

Commit f43b508

Browse files
committed
add stream filter
1 parent 9b6397f commit f43b508

File tree

2 files changed

+169
-0
lines changed

2 files changed

+169
-0
lines changed

lib/mcrypt.php

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,119 @@ function phpseclib_mcrypt_decrypt($cipher, $key, $data, $mode, $iv = NULL)
828828
{
829829
return phpseclib_mcrypt_helper($cipher, $key, $data, $mode, $iv, 'decrypt');
830830
}
831+
832+
/**
833+
* mcrypt_compat stream filter
834+
*
835+
* @author Jim Wigginton <terrafrost@php.net>
836+
* @access public
837+
*/
838+
class phpseclib_mcrypt_filter extends php_user_filter
839+
{
840+
/**
841+
* The Cipher Object
842+
*
843+
* @var object
844+
* @access private
845+
*/
846+
private $cipher;
847+
848+
/**
849+
* To encrypt or decrypt
850+
*
851+
* @var boolean
852+
* @access private
853+
*/
854+
private $op;
855+
856+
/**
857+
* Called when applying the filter
858+
*
859+
* This method is called whenever data is read from or written to the attached stream
860+
* (such as with fread() or fwrite()).
861+
*
862+
* @param resource $in
863+
* @param resource $out
864+
* @param int $consumed
865+
* @param bool $closing
866+
* @link http://php.net/manual/en/php-user-filter.filter.php
867+
* @return int
868+
* @access public
869+
*/
870+
function filter($in, $out, &$consumed, $closing)
871+
{
872+
while ($bucket = stream_bucket_make_writeable($in)) {
873+
$bucket->data = $this->opt ?
874+
$this->cipher->encrypt($bucket->data) :
875+
$this->cipher->decrypt($bucket->data);
876+
$consumed+= $bucket->datalen;
877+
stream_bucket_append($out, $bucket);
878+
}
879+
880+
// can also return PSFS_FEED_ME and PSFS_ERR_FATAL
881+
return PSFS_PASS_ON;
882+
}
883+
884+
/**
885+
* Called when creating the filter
886+
*
887+
* This method is called during instantiation of the filter class object.
888+
* If your filter allocates or initializes any other resources (such as a buffer),
889+
* this is the place to do it.
890+
*
891+
* @link http://php.net/manual/en/php-user-filter.oncreate.php
892+
* @return bool
893+
* @access public
894+
*/
895+
function onCreate()
896+
{
897+
if (!isset($this->params) || !is_array($this->params)) {
898+
user_error('stream_filter_append(): Filter parameters for ' . $this->filtername . ' must be an array');
899+
return false;
900+
}
901+
if (!isset($this->params['iv']) || !is_string($this->params['iv'])) {
902+
user_error('stream_filter_append(): Filter parameter[iv] not provided or not of type: string');
903+
return false;
904+
}
905+
if (!isset($this->params['key']) || !is_string($this->params['key'])) {
906+
user_error('stream_filter_append(): key not specified or is not a string');
907+
return false;
908+
}
909+
$filtername = substr($this->filtername, 0, 10) == 'phpseclib.' ?
910+
substr($this->filtername, 10) :
911+
$this->filtername;
912+
$parts = explode('.', $filtername);
913+
if ($parts != 2) {
914+
user_error('stream_filter_append(): Could not open encryption module');
915+
return false;
916+
}
917+
switch ($parts[0]) {
918+
case 'mcrypt':
919+
case 'mdecrypt':
920+
break;
921+
default:
922+
user_error('stream_filter_append(): Could not open encryption module');
923+
return false;
924+
}
925+
$mode = isset($this->params['mode']) ? $this->params['mode'] : 'cbc';
926+
$cipher = @phpseclib_mcrypt_module_open($parts[1], '', $mode, '');
927+
if ($cipher === false) {
928+
user_error('stream_filter_append(): Could not open encryption module');
929+
return false;
930+
}
931+
932+
$cipher->setKey($key);
933+
$cipher->setIV($iv);
934+
935+
$this->op = $parts[0] == 'mcrypt';
936+
$this->cipher = $cipher;
937+
938+
return true;
939+
}
940+
}
941+
942+
stream_filter_register('phpseclib.mcrypt.*', 'phpseclib_mcrypt_filter');
943+
stream_filter_register('phpseclib.mdecrypt.*', 'phpseclib_mcrypt_filter');
831944
}
832945

833946
// define
@@ -966,4 +1079,9 @@ function mcrypt_decrypt($cipher, $key, $data, $mode, $iv = NULL)
9661079
{
9671080
return phpseclib_mcrypt_decrypt($cipher, $key, $data, $mode, $iv);
9681081
}
1082+
1083+
//if (!in_array('mcrypt.*', stream_get_filters()) {
1084+
stream_filter_register('mcrypt.*', 'phpseclib_mcrypt_filter');
1085+
stream_filter_register('mdecrypt.*', 'phpseclib_mcrypt_filter');
1086+
//}
9691087
}

tests/MCryptCompatTest.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,28 @@ public function testListAlgorithms()
1111
$this->assertInternalType('array', phpseclib_mcrypt_list_algorithms());
1212
}
1313

14+
public function testAESBasicSuccess()
15+
{
16+
$key = str_repeat('z', 16);
17+
$iv = str_repeat('z', 16);
18+
19+
// a plaintext / ciphertext of length 1 is of an insufficient length for cbc mode
20+
$plaintext = str_repeat('a', 16);
21+
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);
25+
26+
$ciphertext = $mcrypt;
27+
28+
$mcrypt = bin2hex(mcrypt_decrypt('rijndael-128', $key, $ciphertext, 'cbc', $iv);
29+
$compat = bin2hex(phpseclib_mcrypt_decrypt('rijndael-128', $key, $ciphertext, 'cbc', $iv);
30+
$this->assertEquals($mcrypt, $compat);
31+
32+
$decrypted = $mcrypt;
33+
$this->assertEquals($plaintext, $decrypted);
34+
}
35+
1436
/**
1537
* @expectedException PHPUnit_Framework_Error_Warning
1638
*/
@@ -83,4 +105,33 @@ public function testNullPadding()
83105
$compat = bin2hex(phpseclib_mcrypt_decrypt('rijndael-128', $key, $ciphertext, 'cbc', $iv));
84106
$this->assertEquals($mcrypt, $compat);
85107
}
108+
109+
/**
110+
* adapted from the example at http://php.net/manual/en/filters.encryption.php
111+
*/
112+
public function testStream()
113+
{
114+
$passphrase = 'My secret';
115+
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);
120+
121+
$fp = fopen('php://memory', 'wb+');
122+
stream_filter_append($fp, 'mcrypt.tripledes', STREAM_FILTER_WRITE, $opts);
123+
fwrite($fp, 'Secret secret secret data');
124+
rewind($fp);
125+
$mcrypt = bin2hex(fread($fp, 1024));
126+
fclose($fp);
127+
128+
$fp = fopen('php://memory', 'wb+');
129+
stream_filter_append($fp, 'phpseclib.mcrypt.tripledes', STREAM_FILTER_WRITE, $opts);
130+
fwrite($fp, 'Secret secret secret data');
131+
rewind($fp);
132+
$compat = bin2hex(fread($fp, 1024));
133+
fclose($fp);
134+
135+
$this->assertEquals($mcrypt, $compat);
136+
}
86137
}

0 commit comments

Comments
 (0)