Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What can cause crypt to produce false validations?

Tags:

php

I encountered a problem with a portal I am building, and decided to investigate further with a small stress test. This test, produced 4,000/10,000/50,000 different salts for one specified password. The code follows:

$Incline = 0;
$Max = 4000;
    $Auth = new Authentication();
    $FalseCounter = 0;
    $TrueCounter = 0;
while ($Incline < $Max){
            $PasswordString = "1";
        $Encrypted_Pass = $Auth->Hash_Password($PasswordString);
        $Check = crypt($PasswordString,$Encrypted_Pass['Salt']);

        if ($Check === $Encrypted_Pass['Password']){
            $TrueCounter++;
        }else{
            $FalseCounter++;
        }
    if ($Incline === $Max){
        break;
    }
    $Incline++;
}

echo 'Of '.$Max.' Checks '.$FalseCounter.' False Returns & '.$TrueCounter.' True Returns';

With $Auth->Hash_Password being:

public $Salt = null;
public function SetSalt(){
    $ByteSize = mcrypt_get_iv_size(MCRYPT_CAST_256, MCRYPT_MODE_CFB);
    $Salt = mcrypt_create_iv($ByteSize, MCRYPT_DEV_RANDOM);
    $this->Salt = $Salt;
    if (!is_null($this->Salt)){
        return true;
    }
    return false;
}
public function Hash_Password($Password){
    $this->SetSalt();
    $Return_Array = array();
    $Return_Array['Salt'] = $this->Salt;
    $Return_Array['Password'] = crypt($Password,$this->Salt);
    return $Return_Array;
}

Now, after showing the code. My output is as follows (on multiple refreshes)

  1. Of 4000 Checks 22 False Returns & 3978 True Returns

  2. Of 4000 Checks 15 False Returns & 3985 True Returns

  3. Of 4000 Checks 15 False Returns & 3985 True Returns

  4. Of 4000 Checks 10 False Returns & 3990 True Returns

  5. Of 4000 Checks 6 False Returns & 3994 True Returns

  6. Of 10000 Checks 40 False Returns & 9960 True Returns

  7. Of 10000 Checks 43 False Returns & 9957 True Returns

  8. Of 50000 Checks 196 False Returns & 49804 True Returns

Despite being a minute fail rate. The problem is still there. Regarding password encryption, Should this not be 100% for all password comparisons?

So, overall question is: What could cause this type of affect? Could it possibly be my coding? Or a flaw within the completely flawless PHP?

like image 502
Daryl Gill Avatar asked Aug 22 '15 22:08

Daryl Gill


People also ask

How are crypto transactions validated?

For a public blockchain, the decision to add a transaction to the chain is made by consensus. This means that the majority of “nodes” (or computers in the network) must agree that the transaction is valid. The people who own the computers in the network are incentivised to verify transactions through rewards.

How does a miner validate a transaction?

Mining transactions are validated digitally on the bitcoin network you use and add to the blockchain ledger. It is done by solving complex cryptographic hash puzzles to verify blocks of transactions updated on the decentralized blockchain ledger.

What two things are used in a blockchain to provide a tamper evident ledger?

What makes this system theoretically tamperproof is two things: a cryptographic fingerprint unique to each block, and a “consensus protocol,” the process by which the nodes in the network agree on a shared history. The fingerprint, called a hash, takes a lot of computing time and energy to generate initially.

Are crypto miners validators?

Under PoS, block creators are called validators. A validator checks transactions, verifies activity, votes on outcomes, and maintains records. Under PoW, block creators are called miners. Miners work to solve for the hash, a cryptographic number, to verify transactions.


1 Answers

It seems crypt is affected by "null byte poisoning". All tests will pass, If you change your SetSalt method to this:

<?php
public function SetSalt()
{
    $ByteSize = mcrypt_get_iv_size(MCRYPT_CAST_256, MCRYPT_MODE_CFB);
    do {
        $Salt = mcrypt_create_iv($ByteSize, MCRYPT_DEV_RANDOM);

        // Remove null byte from salt
        $this->Salt = str_replace(chr(0), '', $Salt);

    } while ($this->Salt !== $Salt); // Retry until salt without null byte is generated

    if (!is_null($this->Salt)) {
        return true;
    }
    return false;
}

After that all tests pass:

$ php crypt_test.php
Of 4000 Checks 0 False Returns & 4000 True Returns

If you want to read more about null bytes you can start here: http://www.madirish.net/401

For better illustration, here is an example output of a failing test:

string(34) "$1$iyJhOmt2$23uOXEcjWr2GcjSMqKpHk0"
array(2) {
  'Salt' =>
  string(16) "\000g-Ŕ=(
                       ��A��n0"
  'Password' =>
  string(34) "$1$QCbFiEDR$g3RDS7LK3m88K7XPqjF5O."
}

You can see the null byte here: \0.

And for all lazy people out there, here is the complete (fixed) test script I used ;)

<?php

class Authentication
{
    public $Salt = null;

    public function SetSalt()
    {
        $ByteSize = mcrypt_get_iv_size(MCRYPT_CAST_256, MCRYPT_MODE_CFB);
        do {
            $Salt = mcrypt_create_iv($ByteSize, MCRYPT_DEV_RANDOM);

            // Remove null byte from salt
            $this->Salt = str_replace(chr(0), '', $Salt);
        } while ($this->Salt !== $Salt);

        if (!is_null($this->Salt)) {
            return true;
        }
        return false;
    }

    public function Hash_Password($Password)
    {
        $this->SetSalt();
        $Return_Array = array();
        $Return_Array['Salt'] = $this->Salt;
        $Return_Array['Password'] = crypt($Password, $this->Salt);
        return $Return_Array;
    }
}


$Incline = 0;
$Max = 4000;
$Auth = new Authentication();
$FalseCounter = 0;
$TrueCounter = 0;
while ($Incline < $Max) {
    $PasswordString = "1";
    $Encrypted_Pass = $Auth->Hash_Password($PasswordString);
    $Check = crypt($PasswordString, $Encrypted_Pass['Salt']);

    if ($Check === $Encrypted_Pass['Password']) {
        $TrueCounter++;
    } else {
        var_dump($Encrypted_Pass, $Check);
        $FalseCounter++;
    }
    if ($Incline === $Max) {
        break;
    }
    $Incline++;
}

echo 'Of ' . $Max . ' Checks ' . $FalseCounter . ' False Returns & ' . $TrueCounter . ' True Returns' . "\n";

Happy coding

like image 98
skroczek Avatar answered Sep 27 '22 23:09

skroczek