/** * @param int $count * @return bool|string * @throws \OCA\Files_Encryption\Exception\EncryptionException */ public function stream_read($count) { $this->writeCache = ''; if ($count !== Crypt::BLOCKSIZE) { \OCP\Util::writeLog('Encryption library', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', \OCP\Util::FATAL); throw new EncryptionException('expected a block size of 8192 byte', EncryptionException::UNEXPECTED_BLOCK_SIZE); } // Get the data from the file handle $data = fread($this->handle, $count); // if this block contained the header we move on to the next block if (Crypt::isHeader($data)) { $data = fread($this->handle, $count); } $result = null; if (strlen($data)) { if (!$this->getKey()) { // Error! We don't have a key to decrypt the file with throw new \Exception('Encryption key not found for "' . $this->rawPath . '" during attempted read via stream'); } else { // Decrypt data $result = Crypt::symmetricDecryptFileContent($data, $this->plainKey, $this->cipher); } } return $result; }
/** * 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; }
/** * @medium */ public function testSymmetricEncryptFileContentAes128() { # TODO: search in keyfile for actual content as IV will ensure this test always passes $crypted = \OCA\Files_Encryption\Crypt::symmetricEncryptFileContent($this->dataShort, 'hat', 'AES-128-CFB'); $this->assertNotEquals($this->dataShort, $crypted); $decrypt = \OCA\Files_Encryption\Crypt::symmetricDecryptFileContent($crypted, 'hat', 'AES-128-CFB'); $this->assertEquals($this->dataShort, $decrypt); }