{"record":{"id":"151ddb2df9e75982","repo":"yiisoft/yii2","slug":"failed-to-generate-hmac-with-hash-algorithm","errorCode":null,"errorMessage":"Failed to generate HMAC with hash algorithm: ","messagePattern":"Failed to generate HMAC with hash algorithm: ","errorType":"exception","errorClass":"InvalidConfigException","httpStatus":null,"severity":"error","filePath":"framework/base/Security.php","lineNumber":378,"sourceCode":"     * Validates if the given data is tampered.\n     * @param string $data the data to be validated. The data must be previously\n     * generated by [[hashData()]].\n     * @param string $key the secret key that was previously used to generate the hash for the data in [[hashData()]].\n     * function to see the supported hashing algorithms on your system. This must be the same\n     * as the value passed to [[hashData()]] when generating the hash for the data.\n     * @param bool $rawHash this should take the same value as when you generate the data using [[hashData()]].\n     * It indicates whether the hash value in the data is in binary format. If false, it means the hash value consists\n     * of lowercase hex digits only.\n     * hex digits will be generated.\n     * @return string|false the real data with the hash stripped off. False if the data is tampered.\n     * @throws InvalidConfigException when HMAC generation fails.\n     * @see hashData()\n     */\n    public function validateData($data, $key, $rawHash = false)\n    {\n        $test = @hash_hmac($this->macHash, '', '', $rawHash);\n        if (!$test) {\n            throw new InvalidConfigException('Failed to generate HMAC with hash algorithm: ' . $this->macHash);\n        }\n        $hashLength = StringHelper::byteLength($test);\n        if (StringHelper::byteLength($data) >= $hashLength) {\n            $hash = StringHelper::byteSubstr($data, 0, $hashLength);\n            $pureData = StringHelper::byteSubstr($data, $hashLength, null);\n\n            $calculatedHash = hash_hmac($this->macHash, $pureData, $key, $rawHash);\n\n            if ($this->compareString($hash, $calculatedHash)) {\n                return $pureData;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Generates specified number of random bytes.","sourceCodeStart":360,"sourceCodeEnd":396,"githubUrl":"https://github.com/yiisoft/yii2/blob/66f00d18a29b520f85e8e8f1e32d1e7e7b556cac/framework/base/Security.php#L360-L396","documentation":"Security::validateData() first computes a probe HMAC of the empty string with the configured macHash purely to learn the digest length; if that probe fails the method cannot even parse the payload and throws InvalidConfigException before any comparison. The triggers are identical to hashData(): a macHash unknown to the hash extension. Tampered data or data signed under a different macHash does not raise this — those cases return false.","triggerScenarios":"Reading hashData-signed cookies or tokens with a Security component whose macHash was changed to a misspelled or unavailable algorithm; environments drifted so only the validating side has the bad value; deploying a macHash change before re-issuing signed data is a related but distinct failure (returns false, not this exception).","commonSituations":"Signed cookie validation after security config changes; API token verification across services with separately managed configs; staging vs production hash availability differences.","solutions":["Fix macHash to the default 'sha-256' or a name listed by hash_hmac_algos() in the validating runtime","Assert macHash validity at bootstrap in every environment that signs or validates","Keep signer and validator components configured identically for shared data","Treat a false return (not this exception) as the signal for re-signing data after legitimate algorithm changes"],"exampleFix":"// before (config only on the validating side)\n'components' => [\n    'security' => ['macHash' => 'sha3512'], // typo → probe HMAC fails → exception\n],\n\n// after\n'components' => [\n    'security' => ['macHash' => 'sha-256'],\n],\n$pureData = Yii::$app->security->validateData($signed, $key);\nif ($pureData === false) {\n    // tampered or signed under a different key/macHash — handle as invalid\n}","handlingStrategy":"validation","validationCode":"if (!in_array(Yii::$app->security->macHash, hash_hmac_algos(), true)) {\n    throw new \\RuntimeException('macHash not supported: ' . Yii::$app->security->macHash);\n}\n$pureData = Yii::$app->security->validateData($signed, $key);\nif ($pureData === false) {\n    // tampered or signed under a different key/macHash\n}","typeGuard":null,"tryCatchPattern":"try {\n    $pureData = Yii::$app->security->validateData($signed, $key);\n} catch (\\yii\\base\\InvalidConfigException $e) {\n    // probe HMAC failed: macHash unsupported — config fix required before any data can validate\n}","preventionTips":["Validate macHash at bootstrap in every service that signs or validates data","Keep signer and validator Security configs identical for shared cookies/tokens","Treat false (not this exception) as the re-sign signal after legitimate algorithm changes"],"tags":["php","yii2","security","hmac","hash","tamper-check"],"backgroundTag":"unsupported-hash-algorithm","analyzedSha":"66f00d18a29b520f85e8e8f1e32d1e7e7b556cac","analyzedAt":"2026-08-17T05:17:23.470Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}