PHPackages                             vasiliy-rubtsov/test-task - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. vasiliy-rubtsov/test-task

ActiveLibrary

vasiliy-rubtsov/test-task
=========================

Тестовое задание для php-разработчика

00[1 issues](https://github.com/vasiliy-rubtsov/test-task/issues)PHP

Since Jul 15Pushed 10mo agoCompare

[ Source](https://github.com/vasiliy-rubtsov/test-task)[ Packagist](https://packagist.org/packages/vasiliy-rubtsov/test-task)[ RSS](/packages/vasiliy-rubtsov-test-task/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

Тестовое задание для PHP-разработчика
=====================================

[](#тестовое-задание-для-php-разработчика)

Требуется реализовать декораторы для [PSR-7 потоков](https://github.com/php-fig/http-message/blob/14b9b813c5e36af4498ef38ef97938bf7090fd52/src/StreamInterface.php), которые будут зашифровывать и расшифровывать их по алгоритмам, используемым WhatsApp. Текстовые описания алгоритмов можно будет найти ниже.

Код необходимо оформить в виде пакета для composer. От реализации ожидается промышленное качество кода.

Тестовые файлы можно найти в папке `samples`:

- `*.original` - оригинальный файл;
- `*.key` - ключ для шифрования (дешифрования) - `mediaKey`;
- `*.encrypted` - зашифрованный файл;
- `*.sidecar` - информация для стриминга.

В качестве задания со звёздочкой можно реализовать генерацию информации для стриминга. Эта генерация не должна делать дополнительных чтений из потока-исходника.

Шифрование
----------

[](#шифрование)

1. Generate your own `mediaKey`, which needs to be 32 bytes, or use an existing one when available.
2. Expand it to 112 bytes using HKDF with SHA-256 and type-specific application info (see below). Call this value `mediaKeyExpanded`.
3. Split `mediaKeyExpanded` into:
    - `iv`: `mediaKeyExpanded[:16]`
    - `cipherKey`: `mediaKeyExpanded[16:48]`
    - `macKey`: `mediaKeyExpanded[48:80]`
    - `refKey`: `mediaKeyExpanded[80:]` (not used)
4. Encrypt the file with AES-CBC using `cipherKey` and `iv`, pad it and call it `enc`.
5. Sign `iv + enc` with `macKey` using HMAC SHA-256 and store the first 10 bytes of the hash as `mac`.
6. Append `mac` to the `enc` to obtain the result.

Дешифрование
------------

[](#дешифрование)

1. Obtain `mediaKey`.
2. Expand it to 112 bytes using HKDF with SHA-256 and type-specific application info (see below). Call this value `mediaKeyExpanded`.
3. Split `mediaKeyExpanded` into:
    - `iv`: `mediaKeyExpanded[:16]`
    - `cipherKey`: `mediaKeyExpanded[16:48]`
    - `macKey`: `mediaKeyExpanded[48:80]`
    - `refKey`: `mediaKeyExpanded[80:]` (not used)
4. Obtain encrypted media data and split it into:
    - `file`: `mediaData[:-10]`
    - `mac`: `mediaData[-10:]`
5. Validate media data with HMAC by signing `iv + file` with `macKey` using SHA-256. Take in mind that `mac` is truncated to 10 bytes, so you should compare only the first 10 bytes.
6. Decrypt `file` with AES-CBC using `cipherKey` and `iv`, and unpad it to obtain the result.

Информационные строки для HKDF
------------------------------

[](#информационные-строки-для-hkdf)

HKDF позволяет указывать информационные строки, специфичные для контекста/приложения. В данном случае контекстом является тип файла, для каждого из которых своя информационная строка:

Media TypeApplication InfoIMAGE`WhatsApp Image Keys`VIDEO`WhatsApp Video Keys`AUDIO`WhatsApp Audio Keys`DOCUMENT`WhatsApp Document Keys`Информация для стриминга
------------------------

[](#информация-для-стриминга)

This step is required only for streamable media, e.g. video and audio. As CBC mode allows to decrypt a data from random offset (block-size aligned), it is possible to play and seek the media without the need to fully download it. That said, we have to generate a `sidecar`.

Do it by signing every `[n*64K, (n+1)*64K+16]` chunk with `macKey`, truncating the result to the first 10 bytes. Then combine everything in one piece.

Полезные пакеты
---------------

[](#полезные-пакеты)

- [jsq/psr7-stream-encryption](https://github.com/jeskew/php-encrypted-streams) - декораторы для шифрования, дешифрования и хеширования;
- [guzzlehttp/psr7](https://github.com/guzzle/psr7) - одна из реализаций PSR-7.

###  Health Score

15

—

LowBetter than 3% of packages

Maintenance40

Moderate activity, may be stable

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity14

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/6055718398721253203bfd3cd00e885db39af8de5934000ca733ea8d531d03eb?d=identicon)[vasiliy-rubtsov](/maintainers/vasiliy-rubtsov)

---

Top Contributors

[![vasiliy-rubtsov](https://avatars.githubusercontent.com/u/177783088?v=4)](https://github.com/vasiliy-rubtsov "vasiliy-rubtsov (1 commits)")

### Embed Badge

![Health badge](/badges/vasiliy-rubtsov-test-task/health.svg)

```
[![Health](https://phpackages.com/badges/vasiliy-rubtsov-test-task/health.svg)](https://phpackages.com/packages/vasiliy-rubtsov-test-task)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
