/** * get the file size of the unencrypted file * @param string $path absolute path * @return bool */ public function getFileSize($path) { $result = 0; // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; // split the path parts $pathParts = explode('/', $path); if (isset($pathParts[2]) && $pathParts[2] === 'files' && $this->view->file_exists($path) && $this->isEncryptedPath($path)) { $cipher = 'AES-128-CFB'; $realSize = 0; // get the size from filesystem $size = $this->view->filesize($path); // open stream $stream = $this->view->fopen($path, "r"); if (is_resource($stream)) { // if the file contains a encryption header we // we set the cipher // and we update the size if ($this->containHeader($path)) { $data = fread($stream, Crypt::BLOCKSIZE); $header = Crypt::parseHeader($data); $cipher = Crypt::getCipher($header); $size -= Crypt::BLOCKSIZE; } // fast path, else the calculation for $lastChunkNr is bogus if ($size === 0) { \OC_FileProxy::$enabled = $proxyStatus; return 0; } // calculate last chunk nr // next highest is end of chunks, one subtracted is last one // we have to read the last chunk, we can't just calculate it (because of padding etc) $lastChunkNr = ceil($size / Crypt::BLOCKSIZE) - 1; // calculate last chunk position $lastChunkPos = $lastChunkNr * Crypt::BLOCKSIZE; // get the content of the last chunk if (@fseek($stream, $lastChunkPos, SEEK_CUR) === 0) { $realSize += $lastChunkNr * 6126; } $lastChunkContentEncrypted = ''; $count = Crypt::BLOCKSIZE; while ($count > 0) { $data = fread($stream, Crypt::BLOCKSIZE); $count = strlen($data); $lastChunkContentEncrypted .= $data; if (strlen($lastChunkContentEncrypted) > Crypt::BLOCKSIZE) { $realSize += 6126; $lastChunkContentEncrypted = substr($lastChunkContentEncrypted, Crypt::BLOCKSIZE); } } fclose($stream); $relPath = Helper::stripUserFilesPath($path); $shareKey = Keymanager::getShareKey($this->view, $this->keyId, $this, $relPath); if ($shareKey === false) { \OC_FileProxy::$enabled = $proxyStatus; return $result; } $session = new Session($this->view); $privateKey = $session->getPrivateKey(); $plainKeyfile = $this->decryptKeyfile($relPath, $privateKey); $plainKey = Crypt::multiKeyDecrypt($plainKeyfile, $shareKey, $privateKey); $lastChunkContent = Crypt::symmetricDecryptFileContent($lastChunkContentEncrypted, $plainKey, $cipher); // calc the real file size with the size of the last chunk $realSize += strlen($lastChunkContent); // store file size $result = $realSize; } } \OC_FileProxy::$enabled = $proxyStatus; return $result; }
private function readHeader() { if ($this->isLocalTmpFile) { $handle = fopen($this->localTmpFile, 'r'); } else { $handle = $this->rootView->fopen($this->rawPath, 'r'); } if (is_resource($handle)) { $data = fread($handle, Crypt::BLOCKSIZE); $header = Crypt::parseHeader($data); $this->cipher = Crypt::getCipher($header); // remeber that we found a header if (!empty($header)) { $this->containHeader = true; } fclose($handle); } }