Skip to content

Commit

Permalink
✨ PHP 7.2: New sniff to detect usage of non-cryptographic hashes
Browse files Browse the repository at this point in the history
> "The hash_hmac(), hash_hmac_file(), hash_pbkdf2(), and hash_init() (with HASH_HMAC) functions no longer accept non-cryptographic hashes."

Refs:
* http://php.net/manual/en/migration72.incompatible.php#migration72.incompatible.hash-functions

Fixes 559
  • Loading branch information
jrfnl committed Jun 10, 2018
1 parent 2362a4e commit 5050cca
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 0 deletions.
113 changes: 113 additions & 0 deletions PHPCompatibility/Sniffs/FunctionParameters/NonCryptoHashSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php
/**
* \PHPCompatibility\Sniffs\FunctionParameters\NonCryptoHashSniff.
*
* PHP version 7.2
*
* @category PHP
* @package PHPCompatibility\FunctionParameters
* @author Juliette Reinders Folmer <phpcompatibility_nospam@adviesenzo.nl>
*/

namespace PHPCompatibility\Sniffs\FunctionParameters;

use PHPCompatibility\AbstractFunctionCallParameterSniff;

/**
* \PHPCompatibility\Sniffs\FunctionParameters\NonCryptoHashSniff.
*
* Detect: "The hash_hmac(), hash_hmac_file(), hash_pbkdf2(), and hash_init()
* (with HASH_HMAC) functions no longer accept non-cryptographic hashes."
*
* PHP version 7.2
*
* @category PHP
* @package PHPCompatibility\FunctionParameters
* @author Juliette Reinders Folmer <phpcompatibility_nospam@adviesenzo.nl>
*/
class NonCryptoHashSniff extends AbstractFunctionCallParameterSniff
{

/**
* Functions to check for.
*
* @var array
*/
protected $targetFunctions = array(
'hash_hmac' => true,
'hash_hmac_file' => true,
'hash_init' => true,
'hash_pbkdf2' => true,
);

/**
* List of the non-cryptographic hashes.
*
* @var array
*/
protected $disabledCryptos = array(
'adler32' => true,
'crc32' => true,
'crc32b' => true,
'fnv132' => true,
'fnv1a32' => true,
'fnv164' => true,
'fnv1a64' => true,
'joaat' => true,
);


/**
* Do a version check to determine if this sniff needs to run at all.
*
* @return bool
*/
protected function bowOutEarly()
{
return ($this->supportsAbove('7.2') === false);
}


/**
* Process the parameters of a matched function.
*
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token in the stack.
* @param string $functionName The token content (function name) which was matched.
* @param array $parameters Array with information about the parameters.
*
* @return int|void Integer stack pointer to skip forward or void to continue
* normal file processing.
*/
public function processParameters(\PHP_CodeSniffer_File $phpcsFile, $stackPtr, $functionName, $parameters)
{
if (isset($parameters[1]) === false) {
return;
}

$targetParam = $parameters[1];

if (isset($this->disabledCryptos[$this->stripQuotes($targetParam['raw'])]) === false) {
return;
}

if (strtolower($functionName) === 'hash_init'
&& (isset($parameters[2]) === false
|| ($parameters[2]['raw'] !== 'HASH_HMAC'
&& $parameters[2]['raw'] !== (string) HASH_HMAC))
) {
// For hash_init(), these hashes are only disabled with HASH_HMAC set.
return;
}

$phpcsFile->addError(
'Non-cryptographic hashes are no longer accepted by function %s() since PHP 7.2. Found: %s',
$targetParam['start'],
$this->stringToErrorCode($functionName),
array(
$functionName,
$targetParam['raw'],
)
);
}
}//end class
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php
/**
* Use of non-cryptographic hashes sniff test file.
*
* @package PHPCompatibility
*/

namespace PHPCompatibility\Tests\Sniffs\FunctionParameters;

use PHPCompatibility\Tests\BaseSniffTest;

/**
* Use of non-cryptographic hashes sniff tests.
*
* @group nonCryptoHash
* @group functionParameterValues
*
* @covers \PHPCompatibility\Sniffs\FunctionParameters\NonCryptoHashSniff
*
* @uses \PHPCompatibility\Tests\BaseSniffTest
* @package PHPCompatibility\FunctionParameters
* @author Juliette Reinders Folmer <phpcompatibility_nospam@adviesenzo.nl>
*/
class NonCryptoHashSniffTest extends BaseSniffTest
{

const TEST_FILE = 'Sniffs/FunctionParameters/NonCryptoHashTestCases.inc';

/**
* testNonCryptoHash
*
* @dataProvider dataNonCryptoHash
*
* @param int $line Line number where the error should occur.
* @param string $functionName The name of the function which was called.
*
* @return void
*/
public function testNonCryptoHash($line, $functionName)
{
$file = $this->sniffFile(self::TEST_FILE, '7.2');
$this->assertError($file, $line, "Non-cryptographic hashes are no longer accepted by function {$functionName}() since PHP 7.2.");
}

/**
* dataNonCryptoHash
*
* @see testNonCryptoHash()
*
* @return array
*/
public function dataNonCryptoHash()
{
return array(
array(12, 'hash_hmac'),
array(13, 'hash_hmac_file'),
array(14, 'hash_pbkdf2'),
array(15, 'hash_init'),
array(16, 'hash_hmac'),
array(17, 'hash_hmac_file'),
array(18, 'hash_pbkdf2'),
array(19, 'hash_init'),
);
}


/**
* testNoFalsePositives
*
* @return void
*/
public function testNoFalsePositives()
{
$file = $this->sniffFile(self::TEST_FILE, '7.2');

// No errors expected on the first 10 lines.
for ($line = 1; $line <= 10; $line++) {
$this->assertNoViolation($file, $line);
}
}


/**
* Verify no notices are thrown at all.
*
* @return void
*/
public function testNoViolationsInFileOnValidVersion()
{
$file = $this->sniffFile(self::TEST_FILE, '7.1');
$this->assertNoViolation($file);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php
/*
* Test hash functions PHP 7.2 change in accepted values.
*/

// OK.
hash_init( 'fnv132');
hash_init( 'sha1', HASH_HMAC);
hash_init( 'gost-crypto', 1);

// Not OK.
hash_hmac('adler32');
hash_hmac_file("crc32");
hash_pbkdf2('crc32b');
hash_init( 'fnv132', HASH_HMAC);
hash_hmac('fnv1a32');
hash_hmac_file("fnv164");
hash_pbkdf2('fnv1a64');
hash_init( 'joaat', 1);

0 comments on commit 5050cca

Please sign in to comment.