dongming0505
2017-06-16 21:14 阅读 54
已采纳

PHP加密更大的文件

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() . "
";
    }
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

1条回答 默认 最新

  • 已采纳
    duanrongpai9556 duanrongpai9556 2017-06-17 21:36

    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 e.g. 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.
    点赞 评论 复制链接分享

相关推荐