Skip to content

Commit bc02c50

Browse files
committed
Merge branch '1.0' into 2.0
2 parents 6505669 + 8c338db commit bc02c50

File tree

5 files changed

+274
-3
lines changed

5 files changed

+274
-3
lines changed

.github/workflows/ci.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
name: CI
3+
on: [push, pull_request]
4+
5+
permissions:
6+
contents: read # to fetch code (actions/checkout)
7+
8+
jobs:
9+
tests:
10+
name: Tests
11+
timeout-minutes: 10
12+
runs-on: ${{ matrix.os }}
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v3
16+
- name: Setup PHP
17+
uses: shivammathur/setup-php@v2
18+
with:
19+
php-version: ${{ matrix.php-version }}
20+
- name: Composer Install
21+
run: composer install --no-interaction --no-cache
22+
- name: Make Tests Compatiable With PHPUnit 9+
23+
if: contains(fromJSON('["7.3", "7.4", "8.0", "8.1", "8.2", "8.3"]'), matrix.php-version)
24+
run: php tests/make_compatible_with_phpunit9.php
25+
- name: PHPUnit
26+
run: vendor/bin/phpunit
27+
strategy:
28+
fail-fast: false
29+
matrix:
30+
os: [ubuntu-latest, windows-latest, macos-latest]
31+
php-version: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3']

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# mcrypt_compat
22

3-
[![Build Status](https://travis-ci.org/phpseclib/mcrypt_compat.svg?branch=master)](https://app.travis-ci.com/github/phpseclib/mcrypt_compat)
3+
[![CI Status](https://github.com/phpseclib/mcrypt_compat/actions/workflows/ci.yml/badge.svg?branch=1.0&event=push "CI Status")](https://github.com/phpseclib/mcrypt_compat/actions/workflows/ci.yml?query=branch%3A1.0)
44

55
PHP 5.x-8.x polyfill for mcrypt extension.
66

lib/mcrypt.php

Lines changed: 169 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,22 @@ function phpseclib_mdecrypt_generic(Base $td, $data)
761761
return phpseclib_mcrypt_generic_helper($td, $data, 'decrypt');
762762
}
763763

764+
/**
765+
* This function terminates encryption
766+
*
767+
* Alias of mcrypt_generic_deinit()
768+
*
769+
* @param Base $td
770+
* @return bool
771+
* @access public
772+
*/
773+
function phpseclib_mcrypt_generic_end(Base $td)
774+
{
775+
// https://web.archive.org/web/20180106174656/https://www.php.net/manual/en/function.mcrypt-generic-end.php
776+
777+
return phpseclib_mcrypt_generic_deinit($td);
778+
}
779+
764780
/**
765781
* This function deinitializes an encryption module
766782
*
@@ -953,6 +969,47 @@ function phpseclib_mcrypt_module_self_test($algorithm, $lib_dir = '')
953969
return in_array($algorithm, phpseclib_mcrypt_list_algorithms());
954970
}
955971

972+
/**
973+
* Encrypt / decrypt data using pre PHP 5.6.0 behavior
974+
*
975+
* Performs checks common to both mcrypt_encrypt and mcrypt_decrypt
976+
*
977+
* @param string $cipher
978+
* @param string $key
979+
* @param string $data
980+
* @param string $mode
981+
* @param string $iv
982+
* @param string $op
983+
* @return string|bool
984+
* @access private
985+
*/
986+
function phpseclib_mcrypt_helper_old($cipher, $key, $data, $mode, $iv, $op)
987+
{
988+
$td = @phpseclib_mcrypt_module_open($cipher, '', $mode, '');
989+
phpseclib_set_key($td, $key);
990+
991+
$iv_size = phpseclib_mcrypt_enc_get_iv_size($td);
992+
if ($iv_size && phpseclib_mcrypt_module_is_iv_mode($mode)) {
993+
if (!isset($iv)) {
994+
trigger_error(
995+
'mcrypt_' . $op . '(): Attempt to use an empty IV, which is NOT recommended',
996+
E_USER_WARNING
997+
);
998+
$iv = str_repeat("\0", $iv_size);
999+
} elseif (strlen($iv) != $iv_size) {
1000+
trigger_error(
1001+
'mcrypt_' . $op . '(): The IV parameter must be as long as the blocksize',
1002+
E_USER_WARNING
1003+
);
1004+
$iv = str_repeat("\0", $iv_size);
1005+
}
1006+
} else {
1007+
$iv = null;
1008+
}
1009+
phpseclib_mcrypt_generic_init($td, $key, $iv);
1010+
return $op == 'encrypt' ? phpseclib_mcrypt_generic($td, $data) : phpseclib_mdecrypt_generic($td, $data);
1011+
}
1012+
9561013
/**
9571014
* Encrypt / decrypt data
9581015
*
@@ -1018,6 +1075,85 @@ function phpseclib_mcrypt_helper($cipher, $key, $data, $mode, $iv, $op)
10181075
return $op == 'encrypt' ? phpseclib_mcrypt_generic($td, $data) : phpseclib_mdecrypt_generic($td, $data);
10191076
}
10201077

1078+
/**
1079+
* Encrypts/decrypts data in CFB mode
1080+
*
1081+
* @param string $cipher
1082+
* @param string $key
1083+
* @param string $data
1084+
* @param int $mode
1085+
* @param string $iv optional
1086+
* @return string|bool
1087+
* @access public
1088+
*/
1089+
function phpseclib_mcrypt_cfb($cipher, $key, $data, $mode, $iv = null)
1090+
{
1091+
// https://web.archive.org/web/20180106174656/https://www.php.net/manual/en/function.mcrypt-cfb.php
1092+
return $mode == MCRYPT_ENCRYPT ?
1093+
phpseclib_mcrypt_encrypt($cipher, $key, $data, MCRYPT_MODE_CFB, $iv) :
1094+
phpseclib_mcrypt_decrypt($cipher, $key, $data, MCRYPT_MODE_CFB, $iv);
1095+
}
1096+
1097+
/**
1098+
* Encrypts/decrypts data in OFB mode
1099+
*
1100+
* @param string $cipher
1101+
* @param string $key
1102+
* @param string $data
1103+
* @param int $mode
1104+
* @param string $iv optional
1105+
* @return string|bool
1106+
* @access public
1107+
*/
1108+
function phpseclib_mcrypt_ofb($cipher, $key, $data, $mode, $iv = null)
1109+
{
1110+
// https://web.archive.org/web/20180106174656/https://www.php.net/manual/en/function.mcrypt-ofb.php
1111+
return $mode == MCRYPT_ENCRYPT ?
1112+
phpseclib_mcrypt_encrypt($cipher, $key, $data, MCRYPT_MODE_OFB, $iv) :
1113+
phpseclib_mcrypt_decrypt($cipher, $key, $data, MCRYPT_MODE_OFB, $iv);
1114+
}
1115+
1116+
/**
1117+
* Encrypts/decrypts data in CBC mode
1118+
*
1119+
* @param string $cipher
1120+
* @param string $key
1121+
* @param string $data
1122+
* @param int $mode
1123+
* @param string $iv optional
1124+
* @return string|bool
1125+
* @access public
1126+
*/
1127+
function phpseclib_mcrypt_cbc($cipher, $key, $data, $mode, $iv = null)
1128+
{
1129+
// https://web.archive.org/web/20180106174656/https://www.php.net/manual/en/function.mcrypt-cbc.php
1130+
return $mode == MCRYPT_ENCRYPT ?
1131+
phpseclib_mcrypt_encrypt($cipher, $key, $data, MCRYPT_MODE_CBC, $iv) :
1132+
phpseclib_mcrypt_decrypt($cipher, $key, $data, MCRYPT_MODE_CBC, $iv);
1133+
}
1134+
1135+
/**
1136+
* Encrypts/decrypts data in ECB mode
1137+
*
1138+
* @param string $cipher
1139+
* @param string $key
1140+
* @param string $data
1141+
* @param int $mode
1142+
* @param string $iv optional
1143+
* @return string|bool
1144+
* @access public
1145+
*/
1146+
function phpseclib_mcrypt_ecb($cipher, $key, $data, $mode, $iv = null)
1147+
{
1148+
// idk why mcrypt_ecb had an $iv parameter when ECB mode doesn't use an IV
1149+
// but whatever
1150+
1151+
// https://web.archive.org/web/20180106174656/https://www.php.net/manual/en/function.mcrypt-ecb.php
1152+
return $mode == MCRYPT_ENCRYPT ?
1153+
phpseclib_mcrypt_encrypt($cipher, $key, $data, MCRYPT_MODE_ECB, $iv) :
1154+
phpseclib_mcrypt_decrypt($cipher, $key, $data, MCRYPT_MODE_ECB, $iv);
1155+
}
1156+
10211157
/**
10221158
* Encrypts plaintext with given parameters
10231159
*
@@ -1033,7 +1169,9 @@ function phpseclib_mcrypt_helper($cipher, $key, $data, $mode, $iv, $op)
10331169
*/
10341170
function phpseclib_mcrypt_encrypt($cipher, $key, $data, $mode, $iv = null)
10351171
{
1036-
return phpseclib_mcrypt_helper($cipher, $key, $data, $mode, $iv, 'encrypt');
1172+
return !defined('PHPSECLIB_MCRYPT_TARGET_VERSION') || version_compare(PHPSECLIB_MCRYPT_TARGET_VERSION, '5.6.0', '>=') ?
1173+
phpseclib_mcrypt_helper($cipher, $key, $data, $mode, $iv, 'encrypt') :
1174+
phpseclib_mcrypt_helper_old($cipher, $key, $data, $mode, $iv, 'encrypt');
10371175
}
10381176

10391177
/**
@@ -1051,7 +1189,9 @@ function phpseclib_mcrypt_encrypt($cipher, $key, $data, $mode, $iv = null)
10511189
*/
10521190
function phpseclib_mcrypt_decrypt($cipher, $key, $data, $mode, $iv = null)
10531191
{
1054-
return phpseclib_mcrypt_helper($cipher, $key, $data, $mode, $iv, 'decrypt');
1192+
return !defined('PHPSECLIB_MCRYPT_TARGET_VERSION') || version_compare(PHPSECLIB_MCRYPT_TARGET_VERSION, '5.6.0', '>=') ?
1193+
phpseclib_mcrypt_helper($cipher, $key, $data, $mode, $iv, 'decrypt') :
1194+
phpseclib_mcrypt_helper_old($cipher, $key, $data, $mode, $iv, 'decrypt');
10551195
}
10561196

10571197
/**
@@ -1257,6 +1397,33 @@ public function onClose()
12571397

12581398
// define
12591399
if (!function_exists('mcrypt_list_algorithms')) {
1400+
if (defined('PHPSECLIB_MCRYPT_TARGET_VERSION') && version_compare(PHPSECLIB_MCRYPT_TARGET_VERSION, '7.0.0', '<')) {
1401+
function mcrypt_generic_end($td)
1402+
{
1403+
return phpseclib_mcrypt_generic_end($td);
1404+
}
1405+
1406+
function mcrypt_ecb($cipher, $key, $data, $mode, $iv = null)
1407+
{
1408+
return phpseclib_mcrypt_ecb($cipher, $key, $data, $mode, $iv);
1409+
}
1410+
1411+
function mcrypt_cbc($cipher, $key, $data, $mode, $iv = null)
1412+
{
1413+
return phpseclib_mcrypt_cbc($cipher, $key, $data, $mode, $iv);
1414+
}
1415+
1416+
function mcrypt_cfb($cipher, $key, $data, $mode, $iv = null)
1417+
{
1418+
return phpseclib_mcrypt_cfb($cipher, $key, $data, $mode, $iv);
1419+
}
1420+
1421+
function mcrypt_ofb($cipher, $key, $data, $mode, $iv = null)
1422+
{
1423+
return phpseclib_mcrypt_ofb($cipher, $key, $data, $mode, $iv);
1424+
}
1425+
}
1426+
12601427
function mcrypt_list_algorithms($lib_dir = '')
12611428
{
12621429
return phpseclib_mcrypt_list_algorithms($lib_dir);

tests/MCryptCompatTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,53 @@ public function testMcryptGenericWithTwoParamsPHPPost71()
835835
phpseclib_mcrypt_generic_init($td, 'xxx');
836836
}
837837

838+
public function testOldMcryptNoIVWarning()
839+
{
840+
$key = 'key';
841+
$data = 'data';
842+
$iv = null;
843+
844+
$this->setExpectedException('PHPUnit_Framework_Error_Warning', 'mcrypt_encrypt(): Attempt to use an empty IV, which is NOT recommended');
845+
846+
phpseclib_mcrypt_helper_old('rijndael-128', $key, $data, 'cbc', $iv, 'encrypt');
847+
}
848+
849+
public function testOldMcryptShortIVWarning()
850+
{
851+
$key = 'key';
852+
$data = 'data';
853+
$iv = 'iv';
854+
855+
$this->setExpectedException('PHPUnit_Framework_Error_Warning', 'mcrypt_encrypt(): The IV parameter must be as long as the blocksize');
856+
857+
phpseclib_mcrypt_helper_old('rijndael-128', $key, $data, 'cbc', $iv, 'encrypt');
858+
}
859+
860+
public function testOldMcryptShortIV()
861+
{
862+
$key = 'key';
863+
$data = 'data';
864+
$iv = 'iv';
865+
866+
$result = @phpseclib_mcrypt_helper_old('rijndael-128', $key, $data, 'cbc', $iv, 'encrypt');
867+
868+
$this->assertEquals('69c48f0bce2c81abd64bbab839080574', bin2hex($result));
869+
}
870+
871+
public function testOldMcryptNoIV()
872+
{
873+
$key = str_pad('key', 16, "\0");
874+
$data = 'data';
875+
$iv = null;
876+
877+
$result = @phpseclib_mcrypt_helper_old('rijndael-128', $key, $data, 'cbc', $iv, 'encrypt');
878+
879+
// this yields the same result that testOldMcryptShortIV() yields. when the IV is invalid it's assumed to be all null bytes,
880+
// whilst a key that's not the right length is either null padded or truncated as appropriate
881+
882+
$this->assertEquals('69c48f0bce2c81abd64bbab839080574', bin2hex($result));
883+
}
884+
838885
public function providerForIVSizeChecks()
839886
{
840887
$tests = [
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
/** @var iterable<SplFileInfo> $files */
4+
$files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(__DIR__));
5+
foreach ($files as $file) {
6+
if ($file->getExtension() === 'php' && $file->getPathname() !== __FILE__) {
7+
$fileContents = file_get_contents($file->getPathname());
8+
if ($fileContents === false) {
9+
throw new \RuntimeException('file_get_contents() failed: ' . $file->getPathname());
10+
}
11+
$patternToReplacementMap = array(
12+
'~(n assertIsArray\([^,\)]*,)([^,\)]*\))~' => '$1 string $2: void',
13+
'~(n assertIsArray\([^,\)]*\))~' => '$1: void',
14+
'~(n assertIsString\([^\)]*\))~' => '$1: void',
15+
'~(n assertStringContainsString\([^\)]*\))~' => '$1: void'
16+
);
17+
$updatedFileContents = preg_replace(
18+
array_keys($patternToReplacementMap),
19+
array_values($patternToReplacementMap),
20+
$fileContents
21+
);
22+
if (file_put_contents($file->getPathname(), $updatedFileContents) === false) {
23+
throw new \RuntimeException('file_put_contents() failed: ' . $file->getPathname());
24+
}
25+
}
26+
}

0 commit comments

Comments
 (0)