2017-01-26 12 views
0

Я пытаюсь реализовать алгоритм хэширования MD5 в PHP, и я подготовил код ниже. Однако, когда я запускаю функцию с тестовым вводом «test», она выдает строку «21aa63b9882532cd590623dbd8f2fa225350d682» в отличие от ожидаемого «098f6bcd4621d373cade4e832627b4f6».PHP MD5 Реализация не приводит к правильному результату

Я полностью исчерпал идеи относительно того, почему это возвращает ошибку, и был бы чрезвычайно благодарен, если бы кто-то помог мне.

Редактировать: Я не использую это в производстве, а скорее в школьном проекте.

Мой код:

<?php 

/** 
* Created by PhpStorm. 
* User: Sam Gunner 
* Date: 25/01/2017 
* Time: 18:37 
*/ 
class md5 
{ 
    private $k; 
    private $s; 

    //Constants as defined by the specification 
    private $a0 = 0x67452301; 
    private $b0 = 0xefcdab89; 
    private $c0 = 0x98badcfe; 
    private $d0 = 0x10325476; 

    //Convert a character to its binary representation using ASCII 
    private function convertCharToByteString($char) { 
     $charNum = ord($char); 
     $charNumString = decbin($charNum); 
     $charNumString = str_pad($charNumString, 8, '0', STR_PAD_LEFT); 
     return $charNumString; 
    } 

    //Takes in a number of zeroes and the string, and then adds that number of zeroes to the end of the string 
    private function padZeroRight($str, $amount) { 
     for ($i = 0; $i < $amount; $i++) { 
      $str .= '0'; 
     } 

     return $str; 
    } 

    //Splits up a string into several pieces 
    private function getCharChunks($original, $length) { 
     $chunks = Array(); 
     $currentChunk = null; 
     $currentStart = null; 
     $numberOfParts = ceil(strlen($original)/$length); //Get the number of chunks 

     for ($i = 0; $i < $numberOfParts; $i++) { 
      $currentStart = ($i * $length) - ($length - 1); //Get the starting position of the substring 
      $currentChunk = substr($original, $currentStart, $length); 
      $chunks[$i] = $currentChunk; 
     } 

     return $chunks; 
    } 

    //Easy way of converting multiple binary integers to array of decimal integers 
    private function convertChunkArrayToIntegers($chunkArray) { 
     $finalChunks = Array(); 
     for ($i = 0; $i < count($chunkArray); $i++) { 
      $finalChunks[$i] = decbin($chunkArray[$i]); 
     } 

     return $finalChunks; 
    } 

    //Begin MD5-specific functions 
    private function F($B, $C, $D) { 
     return ($B & $C) | ((~$B) & $D); 
    } 

    private function G($B, $C, $D) { 
     return ($B & $D) | ($C & (~$D)); 
    } 

    private function H($B, $C, $D) { 
     return ($B^$C^$D); 
    } 

    private function I($B, $C, $D) { 
     return ($C^($B | (~$D))); 
    } 

    private function rotate($decimal, $bits) { //returns hex 
     return (($decimal << $bits) | ($decimal >> (32 - $bits))) & 0xffffffff; 
    } 

    public function __construct() { 
     $this->s = Array(
      7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 
      5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 
      4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 
      6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 
     ); 

     for ($i = 0; $i < 64; $i++) { //Generate the constants that are defined in the specification 
      $this->k[$i] = floor(abs(sin($i + 1)) * pow(2, 32)); 
     } 
    } 

    //Returns the MD5 hash of a message in string form 
    public function hash($message) { 
     $finalStr = ''; 
     $subChunks = null; 
     $A = null; 
     $B = null; 
     $C = null; 
     $D = null; 
     $F = null; 
     $g = null; 
     $DTemp = null; 

     for ($i = 0; $i < strlen($message); $i++) { //Change the string representation of the message into a series of bits, which we can manipulate 
      $finalStr .= $this->convertCharToByteString(substr($finalStr, $i, 1)); 
     } 

     $finalStr .= '1'; //Append 1, as the specification says to 

     $messageLen = strlen($finalStr); 
     $messageLenFinal = $messageLen % 512; //Find out how much we are under a multiple of 512 

     if ($messageLenFinal > 448) { //If the message length remainder is longer than 448, then we need to add some more zeroes to get it to 448 over 
      $remainingToAdd = (512 - $messageLenFinal) + 448; //'tip it over the edge' and then add 448 to make it 64 below 512 
     } else { 
      $remainingToAdd = 448 - $messageLenFinal; 
     } 

     $finalStr = $this->padZeroRight($finalStr, $remainingToAdd); //Add zeroes onto the end until criteria is met 
     //$messageLen = $messageLen % (pow(2, 64)); //Get the length of the message MOD 2 pow 64 
     $messageLen = strlen($finalStr); 

     $messageLenStr = decbin($messageLen); //Convert the decimal representation to binary 
     $messageLenStr = str_pad($messageLenStr, 64, "0", STR_PAD_LEFT); //Pad the message with zeroes to make it 64 bits long 

     $finalStr .= $messageLenStr; 

     $chunks = $this->getCharChunks($finalStr, 512); //Get message in 512-bit chunks 

     foreach ($chunks as $chunk) { 
      $subChunks = $this->convertChunkArrayToIntegers($this->getCharChunks($chunk, 32)); //Get sub chunks of 32-bit size 
      $A = $this->a0; 
      $B = $this->b0; 
      $C = $this->c0; 
      $D = $this->d0; 

      for ($i = 0; $i < 64; $i++) { 
       if ($i >= 0 && $i < 16) { 
        $F = $this->F($B, $C, $D); 
        $g = $i; 
       } elseif ($i > 15 && $i <32) { 
        $F = $this->G($B, $C, $D); 
        $g = ((5 * $i) + 1) % 16; 
       } elseif ($i > 31 && $i < 48) { 
        $F = $this->H($B, $C, $D); 
        $g = ((3 * $i) + 5) % 16; 
       } elseif ($i > 47 && $i < 64) { 
        $F = $this->I($B, $C, $D); 
        $g = (7 * $i) % 16; 
       } 

       $DTemp = $D; 
       $D = $C; 
       $C = $B; 
       $B = $B + $this->rotate(($A + $F + $this->k[$i] + $subChunks[$g]), $this->s[$i]); 
       $A = $DTemp; 
      } 

      $this->a0 += $A; 
      $this->b0 += $B; 
      $this->c0 += $C; 
      $this->d0 += $D; 
     } 

     $final = dechex($this->a0) . dechex($this->b0) . dechex($this->c0) . dechex($this->d0); 
     return $final; 
    } 
} 

Большое спасибо,

- Сэм

+0

Почему вы хотите использовать MD5 для паролей? это не должно использоваться для живого производства; не в этот день и в возрасте. –

+0

Ах, я должен был сказать, что я делаю это для школьного проекта, а не фактически использую его в производстве. Я знаю об ошибках с алгоритмом –

ответ

0

Четыре дополнения вы выполняете в конце раунда:

$this->a0 += $A; 
$this->b0 += $B; 
$this->c0 += $C; 
$this->d0 += $D; 

не являются оберточная бумага. Это приводит к тому, что A/B/C/D становится слишком большим - вероятно, поэтому ваш выход заканчивается на 160 бит вместо 128.

Обратите внимание, что вам также нужно будет поместить результаты dechex() в заключительный этап, чтобы избежать слишком короткого результата, если один из четырех компонентов оказался очень маленьким.

(Там могут быть и другие вопросы, а также -. Это только первые, я заметил)


Если это вариант вообще, я бы сильно рекомендуем использовать C для этот проект. PHP не подходит для написания криптокода низкого уровня; вы часто будете бороться с такими проблемами.