eto-pesets / whatsapp-encrypted-streams
Library contains PSR-7 stream decorators for processing Whatsapp media
Package info
github.com/eto-pesets/whatsapp-encrypted-streams
pkg:composer/eto-pesets/whatsapp-encrypted-streams
1.0.0
2026-03-28 12:41 UTC
Requires
- php: ^8.0
- ext-openssl: *
- guzzlehttp/psr7: ^2.9
- psr/http-message: ^2.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.94
- phpunit/phpunit: ^13.0
This package is auto-updated.
Last update: 2026-03-28 13:12:36 UTC
README
Библиотека содержит декораторы PSR-7 потоков для обработки файлов, зашифрованных по алгоритму Whatsapp.
Возможности:
- Шифрование файлов;
- Подпись файлов;
- Генерация sidecar для потокового скачивания;
- Расшифровка файлов;
- Скачивание целиком + сверка подписи файла;
- Потоковое скачивание (streaming) + сверка sidecar;
Установка:
composer require eto-pesets/whatsapp-encrypted-streams
Примеры использования:
Используются заведомо корректные данные из папки /samples:
$data = [ 'key' => file_get_contents(__DIR__ . '/samples/VIDEO.key'), 'info' => Whatsapp::TYPE_INFO['VIDEO'], 'original' => __DIR__ . '/samples/VIDEO.original', 'encrypted' => __DIR__ . '/samples/VIDEO.encrypted', 'sidecar' => __DIR__ . '/samples/VIDEO.sidecar', ];
Оба потока могут скачивать файл целиком:
$result = $stream->readWhole($buffer_size = 8192);
1. Чтение зашифрованного файла целиком (проверяется только финальная MAC-подпись)
<?php use Psts\Streams\Whatsapp\DecryptionStream; use Psts\Streams\Whatsapp\MediaKey; use Psts\Streams\Whatsapp\Whatsapp; use GuzzleHttp\Psr7; // Инициализация ключа (ключ 32 байт и информационная строка) $mediaKey = new MediaKey($data['key'], $data['info']); // Открытие потока - любой PSR-7 поток $file_stream = Psr7\Utils::streamFor(fopen($data['encrypted'], 'r')); // Подключение потока к декоратору $stream = new DecryptionStream($file_stream, $mediaKey); // Чтение расшифрованного файла $result = ''; while (!$stream->eof()) { $result .= $stream->read(1024); } assert($result === file_get_contents($data['original']), 'Decrypted OK');
2. Чтение зашифрованного файла в режиме потока (проверяется только sidecar)
<?php use Psts\Streams\Whatsapp\DecryptionStream; use Psts\Streams\Whatsapp\MediaKey; use Psts\Streams\Whatsapp\Whatsapp; use GuzzleHttp\Psr7; // Инициализация ключа (ключ 32 байт и информационная строка) $mediaKey = new MediaKey($data['key'], $data['info']); // Открытие потока - любой PSR-7 поток $file_stream = Psr7\Utils::streamFor(fopen($data['encrypted'], 'r')); // Чтение sidecar $sidecar = file_get_contents($data['sidecar']); // Подключение потока к декоратору $stream = new DecryptionStream($file_stream, $mediaKey, $sidecar); // Чтение расшифрованного потока $result = ''; while (!$stream->eof()) { $result .= $stream->read(1024); } assert($result === file_get_contents($data['original']), 'Decrypted OK');
3. Шифрование файла
Sidecar и финальная подпись формируются автоматически и лениво (после накопления буфера либо при достижении конца потока);
Получить sidecar можно только при достижении конца потока.
<?php use Psts\Streams\Whatsapp\EncryptionStream; use Psts\Streams\Whatsapp\MediaKey; use Psts\Streams\Whatsapp\Whatsapp; use GuzzleHttp\Psr7; // Инициализация ключа (ключ 32 байт и информационная строка) $mediaKey = new MediaKey($data['key'], $data['info']); // Открытие потока - любой PSR-7 поток $file_stream = Psr7\Utils::streamFor(fopen($data['original'], 'r')); $sidecar = $data['sidecar']; /* При $sidecar = null поток работает в режиме скачивания: - seek при $offset > 0 недоступен (можно только перезапустить поток); - проверяется финальная MAC-подпись, выбрасывается IntegrityException при несовпадении вычисленной и фактической подписи. При установке $sidecar переходит в режим streaming: - seek доступен, но только кратно Whatsapp::SIZE_STREAM_BLOCK (64KB), округляется вниз автоматически; - каждый чанк подписывается, подпись сверяется с $sidecar, выбрасывается IntegrityException при несовпадении. */ // подключение потока к декоратору $stream = new EncryptionStream($file_stream, $mediaKey, $sidecar); // Чтение зашифрованного потока $result = ''; while (!$stream->eof()) $result .= $stream->read(1024); // Получение sidecar $sidecar = $stream->getSidecar(); assert($result === file_get_contents($data['encrypted']), 'Encrypted matches sample'); assert($sidecar === file_get_contents($data['sidecar']), 'Sidecar matches sample');