pusher / pusher-http-php

PHP library for interacting with the Pusher Channels HTTP API
https://pusher.com/docs/server_api_guide
1.4k stars 306 forks source link

Support multiple encrypted channels for a single event #386

Open paragonie-security opened 3 months ago

paragonie-security commented 3 months ago

Note: This assumes all channels have the same master secret.

If you're interested in an E2EE design that doesn't have this requirement, crypto_box_seal only requires the recipient's public key.


To encrypt a message against multiple channels, two things are needed:

  1. A method of encoding which channels are included in the key derivation that's order-independent.
  2. A method of deriving a shared secret for multiple channels.

This implements both and integrates it into the pusher workflow.

A message encrypted to multiple recipients encodes the channel metadata into an encrypted header.

For example:

private-encrypted-multi-00000000000000207b2263223a5b22626172222c22626c61222c22666f6f225d2c2272223a22227d:{"nonce":"MyNLvxXvz3nJ\/lMv+oRtK991TXW\/00Kx","ciphertext":"+nkcgt+SUDY42NqKCsxB5DgfGz1uhbNgx\/DJkHeL4ffH0JAkbUGgSpd+AzXGx9C6uQ=="}

This hex string is encoded as strlen(data) + data. It encodes two pieces of information:

  1. A list of suffixes for the encrypted channel names.
  2. Optional additional randomness for key derivation.

The suffixes can be used at runtime to re-assemble the channel names.

Given a list of channel names, one can additionally derive a shared secret for the message that all channels should be able to decrypt.

The algorithm it uses is HMAC-SHA256 with an input that consists of lengths of segments followed by the segments' raw data. This design was inspired by PAE from PASETO and TupleHash from the NIST standard.

https://www.nist.gov/publications/sha-3-derived-functions-cshake-kmac-tuplehash-and-parallelhash

Each segment in calculating the shared secret is that channel's shared secret.

The first commit does not update the documentation or guidance around limitations. A congruent change would need to land in every other Pusher implementation before it could be updated.

Description

Fixes #383