Skip to content

Commit

Permalink
Merge branch '2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
terrafrost committed Feb 23, 2024
2 parents 260874a + f61ab08 commit 94d5444
Show file tree
Hide file tree
Showing 5 changed files with 274 additions and 3 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

name: CI
on: [push, pull_request]

permissions:
contents: read # to fetch code (actions/checkout)

jobs:
tests:
name: Tests
timeout-minutes: 10
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
- name: Composer Install
run: composer install --no-interaction --no-cache
- name: Make Tests Compatiable With PHPUnit 9+
if: contains(fromJSON('["7.3", "7.4", "8.0", "8.1", "8.2", "8.3"]'), matrix.php-version)
run: php tests/make_compatible_with_phpunit9.php
- name: PHPUnit
run: vendor/bin/phpunit
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
php-version: ['7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3']
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# mcrypt_compat

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

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

Expand Down
171 changes: 169 additions & 2 deletions lib/mcrypt.php
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,22 @@ function phpseclib_mdecrypt_generic(Base $td, $data)
return phpseclib_mcrypt_generic_helper($td, $data, 'decrypt');
}

/**
* This function terminates encryption
*
* Alias of mcrypt_generic_deinit()
*
* @param Base $td
* @return bool
* @access public
*/
function phpseclib_mcrypt_generic_end(Base $td)
{
// https://web.archive.org/web/20180106174656/https://www.php.net/manual/en/function.mcrypt-generic-end.php

return phpseclib_mcrypt_generic_deinit($td);
}

/**
* This function deinitializes an encryption module
*
Expand Down Expand Up @@ -953,6 +969,47 @@ function phpseclib_mcrypt_module_self_test($algorithm, $lib_dir = '')
return in_array($algorithm, phpseclib_mcrypt_list_algorithms());
}

/**
* Encrypt / decrypt data using pre PHP 5.6.0 behavior
*
* Performs checks common to both mcrypt_encrypt and mcrypt_decrypt
*
* @param string $cipher
* @param string $key
* @param string $data
* @param string $mode
* @param string $iv
* @param string $op
* @return string|bool
* @access private
*/
function phpseclib_mcrypt_helper_old($cipher, $key, $data, $mode, $iv, $op)
{
$td = @phpseclib_mcrypt_module_open($cipher, '', $mode, '');
phpseclib_set_key($td, $key);

$iv_size = phpseclib_mcrypt_enc_get_iv_size($td);
if ($iv_size && phpseclib_mcrypt_module_is_iv_mode($mode)) {
if (!isset($iv)) {
trigger_error(
'mcrypt_' . $op . '(): Attempt to use an empty IV, which is NOT recommended',
E_USER_WARNING
);
$iv = str_repeat("\0", $iv_size);
} elseif (strlen($iv) != $iv_size) {
trigger_error(
'mcrypt_' . $op . '(): The IV parameter must be as long as the blocksize',
E_USER_WARNING
);
$iv = str_repeat("\0", $iv_size);
}
} else {
$iv = null;
}
phpseclib_mcrypt_generic_init($td, $key, $iv);
return $op == 'encrypt' ? phpseclib_mcrypt_generic($td, $data) : phpseclib_mdecrypt_generic($td, $data);
}

/**
* Encrypt / decrypt data
*
Expand Down Expand Up @@ -1018,6 +1075,85 @@ function phpseclib_mcrypt_helper($cipher, $key, $data, $mode, $iv, $op)
return $op == 'encrypt' ? phpseclib_mcrypt_generic($td, $data) : phpseclib_mdecrypt_generic($td, $data);
}

/**
* Encrypts/decrypts data in CFB mode
*
* @param string $cipher
* @param string $key
* @param string $data
* @param int $mode
* @param string $iv optional
* @return string|bool
* @access public
*/
function phpseclib_mcrypt_cfb($cipher, $key, $data, $mode, $iv = null)
{
// https://web.archive.org/web/20180106174656/https://www.php.net/manual/en/function.mcrypt-cfb.php
return $mode == MCRYPT_ENCRYPT ?
phpseclib_mcrypt_encrypt($cipher, $key, $data, MCRYPT_MODE_CFB, $iv) :
phpseclib_mcrypt_decrypt($cipher, $key, $data, MCRYPT_MODE_CFB, $iv);
}

/**
* Encrypts/decrypts data in OFB mode
*
* @param string $cipher
* @param string $key
* @param string $data
* @param int $mode
* @param string $iv optional
* @return string|bool
* @access public
*/
function phpseclib_mcrypt_ofb($cipher, $key, $data, $mode, $iv = null)
{
// https://web.archive.org/web/20180106174656/https://www.php.net/manual/en/function.mcrypt-ofb.php
return $mode == MCRYPT_ENCRYPT ?
phpseclib_mcrypt_encrypt($cipher, $key, $data, MCRYPT_MODE_OFB, $iv) :
phpseclib_mcrypt_decrypt($cipher, $key, $data, MCRYPT_MODE_OFB, $iv);
}

/**
* Encrypts/decrypts data in CBC mode
*
* @param string $cipher
* @param string $key
* @param string $data
* @param int $mode
* @param string $iv optional
* @return string|bool
* @access public
*/
function phpseclib_mcrypt_cbc($cipher, $key, $data, $mode, $iv = null)
{
// https://web.archive.org/web/20180106174656/https://www.php.net/manual/en/function.mcrypt-cbc.php
return $mode == MCRYPT_ENCRYPT ?
phpseclib_mcrypt_encrypt($cipher, $key, $data, MCRYPT_MODE_CBC, $iv) :
phpseclib_mcrypt_decrypt($cipher, $key, $data, MCRYPT_MODE_CBC, $iv);
}

/**
* Encrypts/decrypts data in ECB mode
*
* @param string $cipher
* @param string $key
* @param string $data
* @param int $mode
* @param string $iv optional
* @return string|bool
* @access public
*/
function phpseclib_mcrypt_ecb($cipher, $key, $data, $mode, $iv = null)
{
// idk why mcrypt_ecb had an $iv parameter when ECB mode doesn't use an IV
// but whatever

// https://web.archive.org/web/20180106174656/https://www.php.net/manual/en/function.mcrypt-ecb.php
return $mode == MCRYPT_ENCRYPT ?
phpseclib_mcrypt_encrypt($cipher, $key, $data, MCRYPT_MODE_ECB, $iv) :
phpseclib_mcrypt_decrypt($cipher, $key, $data, MCRYPT_MODE_ECB, $iv);
}

/**
* Encrypts plaintext with given parameters
*
Expand All @@ -1033,7 +1169,9 @@ function phpseclib_mcrypt_helper($cipher, $key, $data, $mode, $iv, $op)
*/
function phpseclib_mcrypt_encrypt($cipher, $key, $data, $mode, $iv = null)
{
return phpseclib_mcrypt_helper($cipher, $key, $data, $mode, $iv, 'encrypt');
return !defined('PHPSECLIB_MCRYPT_TARGET_VERSION') || version_compare(PHPSECLIB_MCRYPT_TARGET_VERSION, '5.6.0', '>=') ?
phpseclib_mcrypt_helper($cipher, $key, $data, $mode, $iv, 'encrypt') :
phpseclib_mcrypt_helper_old($cipher, $key, $data, $mode, $iv, 'encrypt');
}

/**
Expand All @@ -1051,7 +1189,9 @@ function phpseclib_mcrypt_encrypt($cipher, $key, $data, $mode, $iv = null)
*/
function phpseclib_mcrypt_decrypt($cipher, $key, $data, $mode, $iv = null)
{
return phpseclib_mcrypt_helper($cipher, $key, $data, $mode, $iv, 'decrypt');
return !defined('PHPSECLIB_MCRYPT_TARGET_VERSION') || version_compare(PHPSECLIB_MCRYPT_TARGET_VERSION, '5.6.0', '>=') ?
phpseclib_mcrypt_helper($cipher, $key, $data, $mode, $iv, 'decrypt') :
phpseclib_mcrypt_helper_old($cipher, $key, $data, $mode, $iv, 'decrypt');
}

/**
Expand Down Expand Up @@ -1257,6 +1397,33 @@ public function onClose()

// define
if (!function_exists('mcrypt_list_algorithms')) {
if (defined('PHPSECLIB_MCRYPT_TARGET_VERSION') && version_compare(PHPSECLIB_MCRYPT_TARGET_VERSION, '7.0.0', '<')) {
function mcrypt_generic_end($td)
{
return phpseclib_mcrypt_generic_end($td);
}

function mcrypt_ecb($cipher, $key, $data, $mode, $iv = null)
{
return phpseclib_mcrypt_ecb($cipher, $key, $data, $mode, $iv);
}

function mcrypt_cbc($cipher, $key, $data, $mode, $iv = null)
{
return phpseclib_mcrypt_cbc($cipher, $key, $data, $mode, $iv);
}

function mcrypt_cfb($cipher, $key, $data, $mode, $iv = null)
{
return phpseclib_mcrypt_cfb($cipher, $key, $data, $mode, $iv);
}

function mcrypt_ofb($cipher, $key, $data, $mode, $iv = null)
{
return phpseclib_mcrypt_ofb($cipher, $key, $data, $mode, $iv);
}
}

function mcrypt_list_algorithms($lib_dir = '')
{
return phpseclib_mcrypt_list_algorithms($lib_dir);
Expand Down
47 changes: 47 additions & 0 deletions tests/MCryptCompatTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,53 @@ public function testMcryptGenericWithTwoParamsPHPPost71()
phpseclib_mcrypt_generic_init($td, 'xxx');
}

public function testOldMcryptNoIVWarning()
{
$key = 'key';
$data = 'data';
$iv = null;

$this->setExpectedException('PHPUnit_Framework_Error_Warning', 'mcrypt_encrypt(): Attempt to use an empty IV, which is NOT recommended');

phpseclib_mcrypt_helper_old('rijndael-128', $key, $data, 'cbc', $iv, 'encrypt');
}

public function testOldMcryptShortIVWarning()
{
$key = 'key';
$data = 'data';
$iv = 'iv';

$this->setExpectedException('PHPUnit_Framework_Error_Warning', 'mcrypt_encrypt(): The IV parameter must be as long as the blocksize');

phpseclib_mcrypt_helper_old('rijndael-128', $key, $data, 'cbc', $iv, 'encrypt');
}

public function testOldMcryptShortIV()
{
$key = 'key';
$data = 'data';
$iv = 'iv';

$result = @phpseclib_mcrypt_helper_old('rijndael-128', $key, $data, 'cbc', $iv, 'encrypt');

$this->assertEquals('69c48f0bce2c81abd64bbab839080574', bin2hex($result));
}

public function testOldMcryptNoIV()
{
$key = str_pad('key', 16, "\0");
$data = 'data';
$iv = null;

$result = @phpseclib_mcrypt_helper_old('rijndael-128', $key, $data, 'cbc', $iv, 'encrypt');

// this yields the same result that testOldMcryptShortIV() yields. when the IV is invalid it's assumed to be all null bytes,
// whilst a key that's not the right length is either null padded or truncated as appropriate

$this->assertEquals('69c48f0bce2c81abd64bbab839080574', bin2hex($result));
}

public function providerForIVSizeChecks()
{
$tests = [
Expand Down
26 changes: 26 additions & 0 deletions tests/make_compatible_with_phpunit9.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

/** @var iterable<SplFileInfo> $files */
$files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(__DIR__));
foreach ($files as $file) {
if ($file->getExtension() === 'php' && $file->getPathname() !== __FILE__) {
$fileContents = file_get_contents($file->getPathname());
if ($fileContents === false) {
throw new \RuntimeException('file_get_contents() failed: ' . $file->getPathname());
}
$patternToReplacementMap = array(
'~(n assertIsArray\([^,\)]*,)([^,\)]*\))~' => '$1 string $2: void',
'~(n assertIsArray\([^,\)]*\))~' => '$1: void',
'~(n assertIsString\([^\)]*\))~' => '$1: void',
'~(n assertStringContainsString\([^\)]*\))~' => '$1: void'
);
$updatedFileContents = preg_replace(
array_keys($patternToReplacementMap),
array_values($patternToReplacementMap),
$fileContents
);
if (file_put_contents($file->getPathname(), $updatedFileContents) === false) {
throw new \RuntimeException('file_put_contents() failed: ' . $file->getPathname());
}
}
}

0 comments on commit 94d5444

Please sign in to comment.