On another page of the documentation (X-HUAWEI-CALLBACK-ID
), I've found a similar description:
Base64-encoded string that has been HMAC-SHA256 encrypted using the callback key. The string before encryption consists of the value of timestamp, value of nonce, and callback user name, without plus signs.
And here it's being described how to send push.hcm.upstream
messages on Android. Sending an upstream message might be the best chance to obtain the payload, in order to validate a signature. The server-side procedure upon send as following:
When receiving the uplink message, the Push Kit server will:
- Combine the receiving timestamp, colon (:), and uplink message into a character array to be encrypted (for example,
123456789:your_data
).
- Encrypt the character array in HMAC-SHA256 mode using an HMAC signature verification key, and encode the encrypted result in Base64 to generate a signature.
- Transfer the signature and timestamp information to your app server through the
X-HW-SIGNATURE
and X-HW-TIMESTAMP
fields in the HTTPS request header.
Your app server needs to use the HTTPS request header and HMAC signature verification key to verify the validity of the uplink message.
Whatever "an HMAC signature verification key" may be; placeholder your_data
sounds alike, as if (likely not yet base64 encoded) $payload->data
would have been used to generate the signature:
/** Concatenate the input string, generate HMAC hash with SHA256 algorithm, then encode as base64. */
private function generate_signature( int $timestamp, string $nonce, string $data_str, string $secret_key): string {
$input = $timestamp.$nonce.$data_str;
$hmac = hash_hmac( 'sha256', $input, $secret_key );
return base64_encode( $hmac );
}
/** Convert the received signature string to object. */
private function to_object( string $signature ): stdClass {
$input = str_getcsv( $signature, '; ' );
$data = new stdClass();
$data->timestamp = (int) str_replace('timestamp=', '', $input[0]);
$data->nonce = (string) str_replace( ' nonce=', '', $input[1]);
$data->value = (string) str_replace( ' value=', '', $input[2]);
return $data;
}
public function hmac_verify( string $raw_body, string $secret_key, string $signature ): bool {
/* Extract data-string from the raw body. */
$payload = json_decode( $raw_body );
$data_str = base64_decode( $payload->data );
/* Convert the received signature string to object. */
$signature = $this->to_object( $signature );
/* Generate a signature which to compare to. */
$generated = $this->generate_signature( $signature->timestamp, $signature->nonce, $data_str, $secret_key);
/* Compare the generated with the received signature. */
return $generated === $signature->value;
}
Need to test this once with an actual $_POST
...
The "HMAC signature verification key" (per web-hook) can be obtained from the PushKit console:
