简体   繁体   中英

PHP Encrypting Larger Files

I'm trying to encrypt all files being uploaded to the server, and my method of doing it works; but I've noticed DECRYPTING files over 100kb just returns null, and I'm confused why encrypting works on these files, but decrypting doesn't. Is there something wrong with my code, or is there another approach to this? There is nothing wrong with the allowed upload sizes in php.ini, the upload.php page works perfectly fine, and uploads the files to the server. The only issue is with files over 100kb. I have a feeling it has something to do with the max variable length in PHP, but I'm not sure.

// Encrypt Function
public static function mc_encrypt($encrypt, $key)
{
    $encrypt = serialize($encrypt);
    $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_DEV_URANDOM);
    $key = pack('H*', $key);
    $mac = hash_hmac('sha256', $encrypt, substr(bin2hex($key), -32));
    $passcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $encrypt.$mac, MCRYPT_MODE_CBC, $iv);
    $encoded = base64_encode($passcrypt).'|'.base64_encode($iv);
    return $encoded;
}

// Decrypt Function
public static function mc_decrypt($decrypt, $key)
{
    $decrypt = explode('|', $decrypt.'|');
    $decoded = base64_decode($decrypt[0]);
    $iv = base64_decode($decrypt[1]);
    if(strlen($iv)!==mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC)){ return false; }
    $key = pack('H*', $key);
    $decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $decoded, MCRYPT_MODE_CBC, $iv));
    $mac = substr($decrypted, -64);
    $decrypted = substr($decrypted, 0, -64);
    $calcmac = hash_hmac('sha256', $decrypted, substr(bin2hex($key), -32));
    if($calcmac!==$mac){ return false; }
    $decrypted = unserialize($decrypted);
    return $decrypted;
}

Where it should be decrypted:

try
    {
        $server = $db->prepare("SELECT * FROM `servers` WHERE `ServerIP` = :ip LIMIT 1");
        $server->execute([ ":ip" => $ip ]);
        $server = $server->fetch();
        $sftp = new SFTPConnection($server['ServerIP'], intval($server['ServerPort']));
        $sftp->login($server['ServerUser'], $server['ServerPassword']);
        $fileData = $sftp->receiveFile($path);

        //print $fileData;

        header('Content-type: text/plain');
        $fileName = $file['FileName'];
        header("Content-Disposition: attachment; filename=$fileName");

        //print $fileData; (returns the encrypted version)
        $fileData = Encryption::mc_decrypt($fileData, $file['EncryptionKey']);

        print $fileData; // (returns null on larger files)
    }
    catch (Exception $e)
    {
        echo $e->getMessage() . "\n";
    }

I'm not sure what the issue is, but I do know a solution. First of all, you probably want to read in the file in chucks. You don't want to store eg an entire movie in RAM. So what you can do is to treat the SFTP connection as stream:

According to the sample code here:

$connection = ssh2_connect('shell.example.com', 22);
ssh2_auth_password($connection, 'username', 'password');
$sftp = ssh2_sftp($connection);
$stream = fopen("ssh2.sftp://$sftp/path/to/file", 'rb');

Note that I used 'rb' to force binary mode.

So now you can read in chunks from the stream, the only thing you need to do is to encrypt/decrypt the stream. Mcrypt does actually provide this functionality using a filter implementation .

As for the HMAC, you can stream that as well . You may want to create a filter for it - I could not find one.

So now that you can stream everything, go ahead and implement it.


Security notes:

  • mcrypt is an old library that should not be used anymore;
  • use MCRYPT_RIJNDAEL_128 instead of using MCRYPT_RIJNDAEL_256 if you want to use AES (the 256 is the block size, not the key size, the key size is determined by - wait for it - the size of the provided key);
  • HMAC is secure, but it should be performed over the ciphertext and the IV;
  • this is not a full transport protocol - but that doesn't matter much if you send the file over sftp.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM