Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix mcrypt fatal - Removed on PHP 7.2 #159

Merged
merged 25 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a844294
Fix mcrypt fatal on data encryption
vaurdan Jul 5, 2021
e89712c
Fix error with unset `push_syndicate_settings`
vaurdan Jul 8, 2021
2997500
Add initial version of a test suite for the encryption functions.
vaurdan Jul 8, 2021
671576d
Make push_syndicate_decrypt return an array by default
vaurdan Jul 8, 2021
f3ad7a1
Use `is_string` if `assertIsString` is not available.
vaurdan Jul 8, 2021
4d5d0f4
Use `is_string` if `assertIsString` is not available.
vaurdan Jul 8, 2021
9927d42
Merge branch 'vip/deprecated-mcrypto' of github.com:Automattic/syndic…
vaurdan Jul 8, 2021
22ae798
Use `is_array` if `assertIsArray` is not available.
vaurdan Jul 8, 2021
ffa394f
Only test with `mcrypt` if the PHP version is < 7.1
vaurdan Jul 8, 2021
1f67318
Extend the PHP 7.1 validation to the encrypt and decrypt functions.
vaurdan Jul 8, 2021
5024eaa
Use yoast/wp-test-utils for compatibility with different phpunit vers…
vaurdan Jul 12, 2021
b1690a9
Refactor encryption to use Syndication_Encryption class
vaurdan Jul 19, 2021
02f0aa8
Fix tests failing on PHP 7.1
vaurdan Jul 19, 2021
8a4d2e7
Move imports and initialization to plugin root file
vaurdan Jul 20, 2021
6f09b04
Refactor tests to have individual tests for each encryptor
vaurdan Jul 20, 2021
1e6d373
Refactor tests to use a abstract test class for Encryptors
vaurdan Jul 20, 2021
8663284
Change Syndication_Encryptor to interface
vaurdan Jul 20, 2021
18fa88c
Remove leftover require_once
vaurdan Jul 20, 2021
fdb506a
Change Syndication_Encryption from a static class to an instantiable …
vaurdan Jul 21, 2021
d418b9c
Add extra validation for older PHP versions (<5.2.7), just in case.
vaurdan Jul 21, 2021
4e3873b
Remove encryptor strategy getters and setters
vaurdan Jul 23, 2021
16ec5b8
Address feedback on Encryption_Test
vaurdan Jul 23, 2021
c9f684e
Correction on the tests PHPDOC
vaurdan Jul 23, 2021
1f6b87c
Change EncryptionTest to test the `encrypt` and `decrypt` methods.
vaurdan Jul 28, 2021
9a3434d
Fix DocBlock
GaryJones Feb 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion includes/class-wp-push-syndication-server.php
Original file line number Diff line number Diff line change
Expand Up @@ -1225,7 +1225,7 @@ public function cron_add_pull_time_interval( $schedules ) {

// Adds the custom time interval to the existing schedules.
$schedules['syn_pull_time_interval'] = array(
'interval' => intval( $this->push_syndicate_settings['pull_time_interval'] ),
'interval' => isset( $this->push_syndicate_settings ) ? intval( $this->push_syndicate_settings['pull_time_interval'] ) : 0,
'display' => __( 'Pull Time Interval', 'push-syndication' )
);

Expand Down
70 changes: 62 additions & 8 deletions includes/push-syndicate-encryption.php
Original file line number Diff line number Diff line change
@@ -1,18 +1,72 @@
<?php

function push_syndicate_get_cipher() {
$cipher = 'aes-256-cbc';

if ( version_compare( PHP_VERSION, '7.1', '<' ) ) {
return MCRYPT_RIJNDAEL_256;
}
GaryJones marked this conversation as resolved.
Show resolved Hide resolved

if ( in_array( $cipher, openssl_get_cipher_methods(), true ) ) {
return array(
'cipher' => $cipher,
'iv' => substr( md5( md5( PUSH_SYNDICATE_KEY ) ), 0, 16 ),
'key' => md5( PUSH_SYNDICATE_KEY ),
);
}

return false; // @TODO: return another default cipher? return exception?
}

function push_syndicate_encrypt( $data ) {
vaurdan marked this conversation as resolved.
Show resolved Hide resolved
// @todo: replace mcrypt with openssl. problem: Rijndael AES is not available on openssl;s AES-256.
// Will most likely break backwards compatibility with older keys
// https://stackoverflow.com/questions/49997338/mcrypt-rijndael-256-to-openssl-aes-256-ecb-conversion

// Backwards compatibility with PHP < 7.1. Use mcrypt instead.
if ( version_compare( PHP_VERSION, '7.1', '<' ) ) {
// @codingStandardsIgnoreStart
$data = serialize( $data );
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5(PUSH_SYNDICATE_KEY), $data, MCRYPT_MODE_CBC, md5(md5(PUSH_SYNDICATE_KEY))));
// @codingStandardsIgnoreEnd
GaryJones marked this conversation as resolved.
Show resolved Hide resolved
}

$data = wp_json_encode( $data );
$cipher = push_syndicate_get_cipher();

$data = serialize( $data );
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5(PUSH_SYNDICATE_KEY), $data, MCRYPT_MODE_CBC, md5(md5(PUSH_SYNDICATE_KEY))));
if ( ! $cipher ) {
return $data;
}

$encrypted_data = openssl_encrypt( $data, $cipher['cipher'], $cipher['key'], 0, $cipher['iv'] );
return base64_encode( $encrypted_data ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode

}

function push_syndicate_decrypt( $data ) {
function push_syndicate_decrypt( $data, $associative = true ) {

$data = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5(PUSH_SYNDICATE_KEY), base64_decode($data), MCRYPT_MODE_CBC, md5(md5(PUSH_SYNDICATE_KEY))), "\0");
if ( !$data )
return false;
// Backwards compatibility with PHP < 7.1. Use mcrypt instead.
if ( version_compare( PHP_VERSION, '7.1', '<' ) ) {
// @codingStandardsIgnoreStart
$data = rtrim( mcrypt_decrypt( MCRYPT_RIJNDAEL_256, md5( PUSH_SYNDICATE_KEY ), base64_decode( $data ), MCRYPT_MODE_CBC, md5( md5( PUSH_SYNDICATE_KEY ) ) ), "\0" );
if ( ! $data ) {
return false;
}
return @unserialize( $data );
// @codingStandardsIgnoreEnd
}

$cipher = push_syndicate_get_cipher();

if ( ! $cipher ) {
return $data;
}

return @unserialize( $data );
$data = openssl_decrypt( base64_decode( $data ), $cipher['cipher'], $cipher['key'], 0, $cipher['iv'] ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode

}
if ( ! $data ) {
return false;
}

return json_decode( $data, $associative );
}
121 changes: 121 additions & 0 deletions tests/test-encryption.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

/**
* Class EncryptionTest
*/
class EncryptionTest extends WP_UnitTestCase {
private $simple_string;
private $complex_array;

/**
* Runs before the test, set-up.
*/
public function setUp() {
$this->simple_string = 'this is a simple string!';
$this->complex_array = array(
'element' => 'this is a element',
'group' => array(
'another',
'sub',
'array',
'info' => 'test',
),
'',
145,
1 => 20.04,
3 => true,
);
}

/**
* Runs after the test, clean-up
*/
public function tearDown() {
// Nothing yet.
}
vaurdan marked this conversation as resolved.
Show resolved Hide resolved

/**
* Tests if the cipher is available on PHP < 7.1 and if the function is returning the correct cipher.
*
* If using a PHP version older than 7.1, it will expect a mcrypt cipher.
*
* @requires PHP < 7.1
*/
public function test_cypher_pre_72() {
// phpcs:ignore PHPCompatibility.Constants.RemovedConstants.mcrypt_rijndael_256DeprecatedRemoved
$expected_cipher = MCRYPT_RIJNDAEL_256;

// Test the cipher.
$cipher = push_syndicate_get_cipher();
$this->assertSame( $expected_cipher, $cipher );
}

/**
* Tests if the cipher is available on PHP >= 7.1 and if the function is returning the correct cipher.
*
* If using a PHP 7.1 or later, it should use openssl instead of mcrypt.
*
* @requires PHP >= 7.1
*/
public function test_cypher() {
// Test the cipher.
$cipher_data = push_syndicate_get_cipher();

// Test if is an array.
$this->assertIsArray( $cipher_data, 'assert if the cipher data is array' );
$this->assertCount( 3, $cipher_data, 'assert if cipher data have three elements' );

$cipher = $cipher_data['cipher'];
$iv = $cipher_data['iv'];
$key = $cipher_data['key'];

// test cipher.
$expected_cipher = 'aes-256-cbc';
$this->assertEquals( $expected_cipher, $cipher, 'assert if cipher is available' );

// test key.
$this->assertEquals( $key, md5( PUSH_SYNDICATE_KEY ), 'assert if the key is generated as expected' );

// test iv.
$this->assertEquals( 16, strlen( $iv ), 'assert iv size (must be 16)' );
$generated_iv = substr( md5( md5( PUSH_SYNDICATE_KEY ) ), 0, 16 );
$this->assertEquals( $generated_iv, $iv, 'assert if generated iv is as expected' );
}

/**
* Tests the encryption and decryption methods.
*/
public function test_encryption() {
$encrypted_simple = push_syndicate_encrypt( $this->simple_string );
$encrypted_simple_different = push_syndicate_encrypt( $this->simple_string . '1' );
$encrypted_complex = push_syndicate_encrypt( $this->complex_array );

// Because older WP versions might use older phpunit versions, assertIsString() might not be available.
if ( method_exists( $this, 'assertIsString' ) ) {
GaryJones marked this conversation as resolved.
Show resolved Hide resolved
$this->assertIsString( $encrypted_simple, 'assert if the string is encrypted' );
$this->assertIsString( $encrypted_complex, 'assert if the array is encrypted' );
} else {
$this->assertTrue( is_string( $encrypted_simple ), 'assert if the string is encrypted (is_string)' );
$this->assertTrue( is_string( $encrypted_complex ), 'assert if the array is encrypted (is_string)' );
}

$this->assertNotEquals( $encrypted_simple, $encrypted_complex, 'assert that the two different objects have different results' );
$this->assertNotEquals( $encrypted_simple, $encrypted_simple_different, 'assert that the two different strings have different results' );

$decrypted_simple = push_syndicate_decrypt( $encrypted_simple );
$decrypted_complex_array = push_syndicate_decrypt( $encrypted_complex );

$this->assertEquals( $this->simple_string, $decrypted_simple, 'asserts if the decrypted string is the same as the original' );

// Because older WP versions might use older phpunit versions, assertIsArray() might not be available.
if ( method_exists( $this, 'assertIsArray' ) ) {
$this->assertIsArray( $decrypted_complex_array, 'asserts if the decrypted complex data was decrypted as an array' );
} else {
$this->assertTrue( is_array( $decrypted_complex_array ), 'asserts if the decrypted complex data was decrypted as an array (is_array)' );
}

$this->assertEquals( $this->complex_array, $decrypted_complex_array, 'check if the decrypted array is the same as the original' );
}


}