MCPcopy Create free account
hub / github.com/error311/FileRise / streamDecrypted

Method streamDecrypted

src/FileRise/Support/CryptoAtRest.php:354–424  ·  view source on GitHub ↗

* Stream-decrypt an encrypted file into an output stream resource. * * @param resource $out */

(string $path, $out)

Source from the content-addressed store, hash-verified

352 * @param resource $out
353 */
354 public static function streamDecrypted(string $path, $out): void
355 {
356 if (!self::isAvailable()) {
357 throw new \RuntimeException('libsodium secretstream is not available on this PHP build.');
358 }
359 $key = self::requireMasterKey();
360
361 $in = @fopen($path, 'rb');
362 if ($in === false) {
363 throw new \RuntimeException('Unable to open encrypted file.');
364 }
365
366 try {
367 $hdr = fread($in, self::HEADER_LEN);
368 if (!is_string($hdr) || strlen($hdr) !== self::HEADER_LEN) {
369 throw new \RuntimeException('Invalid encrypted file header.');
370 }
371 if (substr($hdr, 0, 4) !== self::MAGIC || ord($hdr[4]) !== self::VERSION) {
372 throw new \RuntimeException('Invalid encrypted file magic/version.');
373 }
374
375 $ssHeader = substr($hdr, 14, 24);
376 $state = sodium_crypto_secretstream_xchacha20poly1305_init_pull($ssHeader, $key);
377
378 $written = 0;
379
380 while (!feof($in)) {
381 $lenBytes = fread($in, 4);
382 if ($lenBytes === '' || $lenBytes === false) {
383 break;
384 }
385 if (strlen($lenBytes) !== 4) {
386 throw new \RuntimeException('Corrupt encrypted file framing.');
387 }
388 $u = unpack('Nlen', $lenBytes);
389 $len = (int)($u['len'] ?? 0);
390 if ($len <= 0 || $len > self::MAX_FRAME_BYTES) {
391 throw new \RuntimeException('Invalid encrypted frame length.');
392 }
393
394 $cipher = '';
395 $remaining = $len;
396 while ($remaining > 0 && !feof($in)) {
397 $buf = fread($in, min(65536, $remaining));
398 if ($buf === '' || $buf === false) {
399 break;
400 }
401 $cipher .= $buf;
402 $remaining -= strlen($buf);
403 }
404 if (strlen($cipher) !== $len) {
405 throw new \RuntimeException('Truncated encrypted frame.');
406 }
407
408 $res = sodium_crypto_secretstream_xchacha20poly1305_pull($state, $cipher, '');
409 $msg = $res[0] ?? '';
410 $tag = $res[2] ?? null;
411

Callers 2

decryptFileToPathMethod · 0.95

Calls 2

isAvailableMethod · 0.95
requireMasterKeyMethod · 0.95

Tested by

no test coverage detected