Вот моя проблема,
Я хочу зашифровать файлы JSON, которые в некоторых случаях могут быть очень длинными. (Иногда содержит изображения в формате Base64).
На следующих тестовых серверах все работает:
С другой стороны, на следующих серверах (которые предназначены для использования ..) шифрование не работает с более чем 65535 символами, сервер, похоже, дает сбой.
Есть ли ограничение на процессор?
Может ли параметр 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, ничего не сообщать.
Я искал несколько дней, не понимая причину проблемы.
В надежде, что кто-то может мне помочь 🙂
Кусок это,
Это то, что я делаю (использует 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
Приветствия.
Других решений пока нет …