Files
service_wopi/lib/Host/ProofValidator.php
T
2026-09-07 21:58:35 -04:00

39 lines
1.6 KiB
PHP

<?php
declare(strict_types=1);
namespace KTXM\ServiceWopi\Host;
use phpseclib3\Crypt\RSA;
use phpseclib3\Math\BigInteger;
class ProofValidator
{
public function valid(array $keys, string $token, string $url, string $timestamp, string $proof, string $oldProof, int $now): bool
{
if (!preg_match('/^[0-9]{1,18}$/D', $timestamp)) { return false; }
$ticks = (int) $timestamp;
// .NET ticks: 100 ns since 0001-01-01. Bound both stale and future requests.
$seconds = intdiv($ticks, 10000000) - 62135596800;
if (abs($seconds - $now) > 1200) { return false; }
$url = strtoupper($url);
$data = pack('N', strlen($token)) . $token . pack('N', strlen($url)) . $url
. pack('N', 8) . pack('J', $ticks);
return $this->verify($keys, '', $proof, $data)
|| $this->verify($keys, '', $oldProof, $data)
|| $this->verify($keys, 'old', $proof, $data);
}
private function verify(array $keys, string $prefix, string $signature, string $data): bool
{
$signature = base64_decode($signature, true);
$modulus = base64_decode($keys[$prefix . 'modulus'] ?? '', true);
$exponent = base64_decode($keys[$prefix . 'exponent'] ?? '', true);
if (!$signature || !$modulus || !$exponent || strlen($modulus) > 1024 || strlen($exponent) > 8) { return false; }
try {
$key = RSA::loadPublicKey(['n' => new BigInteger($modulus, 256), 'e' => new BigInteger($exponent, 256)]);
return $key->withPadding(RSA::SIGNATURE_PKCS1)->withHash('sha256')->verify($data, $signature);
} catch (\Throwable) {
return false;
}
}
}