How to decrypt a Mastodon Web Push notification in PHP

128 views Asked by At

I'm building a PHP Web Push notification Listener for Mastodon. I successfully created a subscription by sending the following post data to the Mastodon subscription API URL:

$post_data = array(
        "subscription" => array(
            "endpoint" => $env["endpoint"], // URL of endpoint where PHP script is
            "keys" => array(
                "p256dh" => $env["vapid_public"], // Public key
                "auth" => $env["vapid_private"] // Private key
            )
        ),
        "data" => array(
            "alerts" => array(
                "mention" => true // receive notifications for mentions
            )
        )
    );

When I mention or send a DM to the account the subscription is set up for, the PHP script receives a POST request with the Web Push notification. The notification payload is picked up by using file_get_contents("php://input"). This is binary data.

My question now is how do I decrypt this binary data. I have tried converting the payload to hex first, and then feeding it to openssl_decrypt() but I'm not sure what keys to use and so I'm kinda in the dark here. Any help is appreciated.

Here's a copy of the POST headers received by the Web Push Notification from Mastodon The actual values of the keys is replaced with some words, because of security. Dots [.], identifiers [xx=] and semicolons[;] are left in place.

    [Authorization] => WebPush some_key_1.some_key_2.some_key_3 // This is the JSON Web Token https://web.dev/articles/push-notifications-web-push-protocol#json_web_token
    [Crypto-Key] => dh=crypto_key_1;p256ecdsa=crypto_key_2
    [Encryption] => salt=salt_key
    [Content-Encoding] => aesgcm
    [Urgency] => normal
    [Ttl] => 172800
    [Content-Type] => application/octet-stream
    [Digest] => SHA-256=digest_key
    [Accept-Encoding] => gzip
    [Date] => Wed, 22 Nov 2023 16:02:27 GMT
    [User-Agent] => http.rb/5.1.1 (Mastodon/4.2.1; +https://hidden_url.com/)
    [Content-Length] => 334
    [Connection] => close
    [Host] => other_hidden_url.com
    [X-Real-Port] => xxxxx
    [X-Port] => 443
    [X-Https] => on
    [X-Real-Ip] => hidden_ip
    [X-Forwarded-By] => other_hidden_ip

openssl_decrypt() uses the following parameters:

function openssl_decrypt(
    string $data,
    string $cipher_algo,
    string $passphrase,
    int $options = 0,
    string $iv = "",
    string|null $tag = null,
    string $aad = ""
): string|false 

I guess the challenge now is to map the keys from the headers and the keys I used for creating the subscription to these parameters. I have tried different combinations, but no success yet.

Documentation used:

0

There are 0 answers