parseDigestArguments($this->arguments); if (empty($arguments['username'])) { throw new \InvalidArgumentException("A 'username' key is required to authenticate using Digest"); } $isSess = stripos($arguments['algorithm'] ?? "", "-SESS") !== false; $hashMethod = $this->getDigestAlgorithmHash($arguments); $arguments['nc'] = str_pad($arguments['nc'] ?? "1", 8, '0', STR_PAD_LEFT); $ha1 = $this->getSecretHash(); if ($isSess) { $ha1 = hash($hashMethod, implode(':', [ $ha1, $arguments['nonce'] , $arguments['cnonce'] ])); } switch($arguments['qop'] ?? 'auth') { case 'auth-int': $ha2 = hash($hashMethod, implode(':', [ strtoupper($request->getMethod()), $arguments['uri'], hash($hashMethod, $body ?? "") ])); break; case 'auth': default: $ha2 = hash($hashMethod, implode(':', [ strtoupper($request->getMethod()), $arguments['uri'] ])); break; } if (isset($arguments['qop'])) { $response = hash($hashMethod, implode(':', [ $ha1, $arguments['nonce'], $arguments['nc'], $arguments['cnonce'], $arguments['qop'], $ha2 ])); } else { $response = hash($hashMethod, implode(':', [ $ha1, $arguments['nonce'], $ha2 ])); } return $response === $arguments['response']; } protected function parseDigestArguments(string|array $arguments) : array { if (is_string($arguments)) { $keys = [ 'nonce', 'nc', 'cnonce', 'qop', 'username', 'uri', 'realm', 'response', 'opaque', 'algorithm' ]; # From https://www.php.net/manual/en/features.http-auth.php preg_match_all('@(' . implode('|', $keys) . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $arguments, $matches, PREG_SET_ORDER); $arguments = []; foreach ($matches as $match) { $arguments[$match[1]] = $match[3] ?: $match[4]; } } return $arguments; } protected function getDigestAlgorithmHash(array $arguments) : string { switch(strtoupper($arguments['algorithm'] ?? "")) { case "SHA-512-256": case "SHA-512-256-SESS": return "sha512/256"; case "SHA-256": case "SHA-256-SESS": return "sha256"; default: case 'MD5-SESS': case 'MD5': return "md5"; } } }