шифрование — Как зашифровать и расшифровать строки длиннее 65535 символов с переполнением стека

Вот моя проблема,

Я хочу зашифровать файлы JSON, которые в некоторых случаях могут быть очень длинными. (Иногда содержит изображения в формате Base64).

На следующих тестовых серверах все работает:

  • Raspberry Pi 3
  • Dell Poweredge T110
  • IIS в Windows 10
  • Synology DS1815 +

С другой стороны, на следующих серверах (которые предназначены для использования ..) шифрование не работает с более чем 65535 символами, сервер, похоже, дает сбой.

  • Synology RS212
  • Synology DS112 +

Есть ли ограничение на процессор?

Может ли параметр php.ini повлиять?

Я протестировал один и тот же код на нескольких серверах, и на обоих упомянутых Synology он не работает …

Вот мой класс шифрования / дешифрования:

class PHP_AES_Cipher {

private static $OPENSSL_CIPHER_NAME = "AES-256-CBC"; //Name of OpenSSL Cipher
private static $CIPHER_KEY_LEN = 32;

static function encrypt($key, $iv, $data) {
if (strlen($key) < PHP_AES_Cipher::$CIPHER_KEY_LEN) {
$key = str_pad("$key", PHP_AES_Cipher::$CIPHER_KEY_LEN, "0");
} else if (strlen($key) > PHP_AES_Cipher::$CIPHER_KEY_LEN) {
$key = substr($str, 0, PHP_AES_Cipher::$CIPHER_KEY_LEN);
}

$encodedEncryptedData = base64_encode(openssl_encrypt($data, PHP_AES_Cipher::$OPENSSL_CIPHER_NAME, $key, OPENSSL_RAW_DATA, $iv));
$encodedIV = base64_encode($iv);
$encryptedPayload = $encodedEncryptedData.":".$encodedIV;

return $encryptedPayload;

}


static function decrypt($key, $data) {
if (strlen($key) < PHP_AES_Cipher::$CIPHER_KEY_LEN) {
$key = str_pad("$key", PHP_AES_Cipher::$CIPHER_KEY_LEN, "0");
} else if (strlen($key) > PHP_AES_Cipher::$CIPHER_KEY_LEN) {
$key = substr($str, 0, PHP_AES_Cipher::$CIPHER_KEY_LEN);
}

$parts = explode(':', $data); //Separate Encrypted data from iv.
$decryptedData = openssl_decrypt(base64_decode($parts[0]), PHP_AES_Cipher::$OPENSSL_CIPHER_NAME, $key, OPENSSL_RAW_DATA, base64_decode($parts[1]));

return $decryptedData;
}
}

Я использую это так:

$data = PHP_AES_Cipher::encrypt($key, $iv, $data);

а также

$data = PHP_AES_Cipher::decrypt($key, $iv, $data);

Предполагая, что все работает на некоторых серверах, я думаю, что код не имеет проблем. Я уже проверил журналы Apache и PHP, ничего не сообщать.

Я искал несколько дней, не понимая причину проблемы.

В надежде, что кто-то может мне помочь 🙂

0

Решение

Кусок это,

Это то, что я делаю (использует PHPSecLib2)

/**
* AES encrypt large files using streams and chunking
*
* @param resource $stream
* @param resource $outputStream
* @param string $key
* @throws SecExecption
*/
function streamSymEncode($stream, &$outputStream, $key, $chunkSize = 10240){
if(!is_resource($stream)) throw new Execption('Resource expected[input]');
rewind($stream); //make sure the stream is rewound

if(!is_resource($outputStream)) throw new Execption('Resource expected[output]');

$Cipher = new AES(AES::MODE_CBC);
$Cipher->setKey($key);
//create the IV
$iv = Random::string($Cipher->getBlockLength() >> 3);
$Cipher->setIV($iv);

if(strlen($iv_base64 = rtrim(base64_encode($iv), '=')) != 22) throw new Execption('IV lenght check fail');

fwrite($outputStream, $iv_base64.'$'); //add the IV for later use when we decrypt

while(!feof($stream)){
$chunk = fread($stream, $chunkSize);
fwrite($outputStream, rtrim(base64_encode($Cipher->encrypt($chunk)),'=').':');
}

$stat = fstat($outputStream);

ftruncate($outputStream, $stat['size'] - 1);    //trim off the last character, hanging ':'
}

/**
* AES decrypt large files that were previously encrypted using streams and chunking
*
* @param resource $stream
* @param resource $outputStream
* @param string $key
* @throws SecExecption
*/
function streamSymDecode($stream, &$outputStream, $key){
if(!is_resource($stream)) throw new Execption('Resource expected[input]');
rewind($stream); //make sure the stream is rewound

if(!is_resource($outputStream)) throw new Execption('Resource expected[output]');

$Cipher = new AES(AES::MODE_CBC);
$Cipher->setKey($key);

$iv = base64_decode(fread($stream, 22) . '==');
$Cipher->setIV($iv);

fread($stream, 1); //advance 1 for the $

$readLine = function(&$stream){
$line = '';
while(false !== ($char = fgetc($stream))){
if($char == ':') break;
$line .= $char;
}
return $line;
};

while(!feof($stream)){
$chunk = $readLine($stream);

$decrypted = $Cipher->decrypt(base64_decode($chunk.'=='));
if(!$decrypted) throw new Execption('Failed to decode!');

fwrite($outputStream, $decrypted);
}
}

Требуется два потока файловых файлов, как то, что вы получаете от fopen и ключ. Затем он использует то же самое шифрование, но разбивает файл на $chunkSize разделяет их с : и когда он декодирует, он разделяет его на куски и собирает все заново.

Вот так (например)

  IV$firstChunk:secondChunk:thirdChunk

Таким образом, вам не хватает памяти, пытаясь зашифровать большие файлы.

Обратите внимание, что это было частью класса лагера, который я использую, поэтому мне пришлось урезать некоторые вещи и внести некоторые изменения, которые я не проверял.

https://github.com/phpseclib/phpseclib

Приветствия.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]