Skip to content

Commit

Permalink
Adjusted to only allow use of fallback if PHP version is incompatible…
Browse files Browse the repository at this point in the history
… with OpenSSL, or OpenSSL does not support RC4. Uses setasign implementation of RC4
  • Loading branch information
artulloss committed Oct 9, 2023
1 parent 8f7abc6 commit 008ca16
Showing 1 changed file with 42 additions and 76 deletions.
118 changes: 42 additions & 76 deletions src/FpdiProtection.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ class FpdiProtection extends \setasign\Fpdi\Fpdi
/**
* @var bool
*/
protected $bad_openssl;
protected $useArcfourFallback = false;

/**
* FpdiProtection constructor.
Expand All @@ -205,19 +205,24 @@ class FpdiProtection extends \setasign\Fpdi\Fpdi
* @param string $unit
* @param string $size
*/
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4', $bad_openssl = false)
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4', $useArcfourFallback = false)
{
parent::__construct($orientation, $unit, $size);
$this->bad_openssl = $bad_openssl;

$randomBytes = function_exists('random_bytes') ? \random_bytes(32) : \mt_rand();
$this->fileIdentifier = md5(__FILE__ . PHP_SAPI . PHP_VERSION . $randomBytes, true);

if (!$bad_openssl && !function_exists('openssl_encrypt') || !in_array('rc4-40', openssl_get_cipher_methods(), true)) {
if ($useArcfourFallback && extension_loaded('openssl')) {
$supportsRc4 = in_array('rc4-40', openssl_get_cipher_methods(), true);
$this->useArcfourFallback = ((OPENSSL_VERSION_NUMBER >= 0x10100000) && PHP_VERSION_ID < 80000) || !$supportsRc4;
if($this->useArcfourFallback) return;
}

if (!function_exists('openssl_encrypt') || !in_array('rc4-40', openssl_get_cipher_methods(), true)) {
throw new \RuntimeException(
'OpenSSL with RC4 supported is required. In case you use OpenSSL 3 make sure that ' .
'legacy providers are loaded (see https://wiki.openssl.org/index.php/OpenSSL_3.0#Providers).' .
'Pass $bad_openssl as true to fallback on a pure PHP implementation.'
'If '
);
}
}
Expand Down Expand Up @@ -516,10 +521,39 @@ protected function computeUValue($encryptionKey)
*/
protected function arcfour($key, $data)
{
if($this->bad_openssl) {
return $this->rc4($key, $data);
if (!$this->useArcfourFallback) {
return openssl_encrypt($data, 'rc4-40', $key, OPENSSL_RAW_DATA, '');
}

static $_lastRc4Key = null, $_lastRc4KeyValue = null;

if ($_lastRc4Key !== $key) {
$k = str_repeat($key, (int)(256 / strlen($key) + 1));
$rc4 = range(0, 255);
$j = 0;
for ($i = 0; $i < 256; $i++) {
$rc4[$i] = $rc4[$j = ($j + ($t = $rc4[$i]) + ord($k[$i])) % 256];
$rc4[$j] = $t;
}
$_lastRc4Key = $key;
$_lastRc4KeyValue = $rc4;

} else {
$rc4 = $_lastRc4KeyValue;
}
return openssl_encrypt($data, 'RC4-40', $key, OPENSSL_RAW_DATA, '');

$len = strlen($data);
$newData = '';
$a = 0;
$b = 0;
for ($i = 0; $i < $len; $i++) {
$b = ($b + ($t = $rc4[$a = ($a + 1) % 256])) % 256;
$rc4[$a] = $rc4[$b];
$rc4[$b] = $t;
$newData .= chr(ord($data[$i]) ^ $rc4[($rc4[$a] + $rc4[$b]) % 256]);
}

return $newData;
}

/**
Expand Down Expand Up @@ -656,72 +690,4 @@ protected function _puttrailer()
$this->_put('/ID [<' . $fileIdentifier . '><' . $fileIdentifier . '>]');
}
}

/*
* Copyright 2011 Michael Cutler <m@cotdp.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* A PHP implementation of RC4 based on the original C code from
* the 1994 usenet post:
*
* http://groups.google.com/groups?selm=sternCvKL4B.Hyy@netcom.com
*
* @param string $key_str the key as a binary string
* @param string $data_str the data to decrypt/encrypt as a binary string
* @return string the result of the RC4 as a binary string
* @author Michael Cutler <m@cotdp.com>
*/
private function rc4($key_str, $data_str)
{
// convert input string(s) to array(s)
$key = array();
$data = array();
for ($i = 0; $i < strlen($key_str); $i++) {
$key[] = ord($key_str[$i]);
}
for ($i = 0; $i < strlen($data_str); $i++) {
$data[] = ord($data_str[$i]);
}
// prepare key
$state = range(0, 255);
$len = count($key);
$index1 = $index2 = 0;
for ($counter = 0; $counter < 256; $counter++) {
$index2 = ($key[$index1] + $state[$counter] + $index2) % 256;
$tmp = $state[$counter];
$state[$counter] = $state[$index2];
$state[$index2] = $tmp;
$index1 = ($index1 + 1) % $len;
}
// rc4
$len = count($data);
$x = $y = 0;
for ($counter = 0; $counter < $len; $counter++) {
$x = ($x + 1) % 256;
$y = ($state[$x] + $y) % 256;
$tmp = $state[$x];
$state[$x] = $state[$y];
$state[$y] = $tmp;
$data[$counter] ^= $state[($state[$x] + $state[$y]) % 256];
}
// convert output back to a string
$data_str = "";
for ($i = 0; $i < $len; $i++) {
$data_str .= chr($data[$i]);
}
return $data_str;
}
}

0 comments on commit 008ca16

Please sign in to comment.