Реализация SHA-384 на PHP

В учебных целях (лабораторная) реализую алгоритм хэширования SHA-384 на PHP. Язык оказался не совсем удобен для оперирования числами более PHP_INT_MAX, ибо используются при вычислениях выходящие из этого диапазона целые, однако, выбор ЯП обусловлен желанием попрактиковаться, решением сделать веб-приложение для показа алгоритма преподавателю, да и бинарные операции было бы неплохо вспомнить.

Ниже прилагаю свою реализацию данного алгоритма, однако, она работает с ошибками. Я протестировал все функции, необходимые для основной хэш-функции, но в ней самой возникают вычислительные ошибки на стадии вычисления сумм. Плюс, в процессе частично переписал код, когда хорошенько перечитал про целочисленный тип в PHP, функции над ним и его диапазон. Также, для наглядности я его сравниваю со встроенной функцией хэширования

Что здесь не так? Также, приветствуются улучшения данного кода

<?php

function and_b($a, $b) {
    $rez = "";
    for ($i = 0; $i < strlen($a); $i++) {
        $rez = $rez.((string)((int)$a[$i] & (int)$b[$i]));
    }
    return $rez;
}

function or_b($a, $b) {
    $rez = "";
    for ($i = 0; $i < strlen($a); $i++) {
        $rez = $rez.((string)((int)$a[$i] | (int)$b[$i]));
    }
    return $rez;
}

function xor_b($a, $b) {
    $rez = "";
    for ($i = 0; $i < strlen($a); $i++) {
        $rez = $rez.((string)((int)$a[$i] ^ (int)$b[$i]));
    }
    return $rez;
}

function not_b($a) {
    $rez = "";
    for ($i = 0; $i < strlen($a); $i++) {
        $rez = ((int)$a[$i] === 1) ? $rez.'0' : $rez.'1';
    }
    return $rez;
}

function left_shift_b($a, $b) {
    $rez = $a;
    for ($i = 0; $i < $b; $i++) {
        $rez = substr($rez, 1, 63).'0';
    }
    return $rez;
}

function right_shift_b($a, $b) {
    $rez = $a;
    for ($i = 0; $i < $b; $i++) {
        $rez = '0'.substr($rez, 0, 63);
    }
    return $rez;
}

function add_mod_b($a, $b) {
    $rez = "";
    $ost = "0";
    while (strlen($a) < 64) {
        $a = '0'.$a;
    }
    while (strlen($b) < 64) {
        $b = '0'.$b;
    }
    $a_rev = strrev($a);
    $b_rev = strrev($b);
    
    for ($i = 0; $i < strlen($a); $i++) {
        $rez .= xor_b(xor_b($a_rev[$i], $b_rev[$i]), $ost);
        $ost = ($a_rev[$i] === "1" and $b_rev[$i] === "1") ? "1" : "0";
    }
    return strrev($rez);
}

function ROTR($n, $x) {
    return substr($x, strlen($x) - $n, $n).substr($x, 0,  strlen($x) - $n);

}

function sum_0_512($x) {
    return xor_b(xor_b(ROTR(28, $x), ROTR(34, $x)), ROTR(39, $x));
}

function sum_1_512($x) {    
    return xor_b(xor_b(ROTR(14, $x), ROTR(18, $x)), ROTR(41, $x));
}

function sigma_0_512($x) {
    return xor_b(xor_b(ROTR(1, $x), ROTR(8, $x)), right_shift_b($x, 7));
}

function sigma_1_512($x) {  
    return xor_b(xor_b(ROTR(19, $x), ROTR(61, $x)), right_shift_b($x, 6));
}

function ch($x, $y, $z) {
    return xor_b(and_b($x, $y), and_b(not_b($x), $z));

}

function maj($x, $y, $z) {
    return xor_b(xor_b(and_b($x, $y), and_b($x, $z)), and_b($y, $z));

}

function hex_to_bin($x) {
    $rez = "";
    for ($i = 0; $i < strlen($x); $i++) {
        
        $num = (string)base_convert($x[$i], 16, 2);
        while (strlen($num) < 4) {
            $num = '0'.$num;
        }
        
        $rez .= $num;
    }

    while (strlen($rez) < 64) {
        $rez = '0'.$rez;
    }
    return $rez;
}

function bin_to_hex($x) {
    $rez = "";
    for ($i = 0; $i < intdiv(strlen($x), 4); $i++) {
        $rez .= (string)base_convert(substr($x, $i * 4, 4), 2, 16);
    }
    while (strlen($rez) < 16) {
        $rez = '0'.$rez;
    }

    return $rez;
}

function SHA_384($word) {
    $binary_msg = "";
    $symbols = str_split($word);
    foreach ($symbols as $s) {
        $bin = strval(base_convert(ord($s), 10, 2));
        while (strlen($bin) !== 8) {
            $bin = '0'.$bin;
        }
        $binary_msg .= $bin;
    }
    
    $binary_msg .= '1';
    while (strlen($binary_msg) % 1024 !== 896) {
        $binary_msg .= '0';
    }


    $bin_len = (string)base_convert(strlen($word) * 8, 10, 2);
    while (strlen($bin_len) < 128) {
        $bin_len = '0'.$bin_len;
    }
    $bin_len = substr($bin_len, strlen($bin_str) - 128, 128);
    $binary_msg .= $bin_len;

    $m = array();
    for ($i = 0; $i < intdiv(strlen($binary_msg), 1024); $i++) {
        $mi = str_split($binary_msg, 64);
        array_push($m, $mi);
    }
    
    $kt = file('k.txt');
    $ht = file('h.txt');
    for ($i = 0; $i < 80; $i++) {
        $kt[$i] = hex_to_bin(substr($kt[$i], 0, 16));
    }
    for ($i = 0; $i < 8; $i++) {
        $ht[$i] = hex_to_bin(substr($ht[$i], 0, 16));
    }
    
    foreach ($m as $mi) {
        $w = array();
        foreach ($mi as $mit) {
            array_push($w, $mit);
        }
        for ($t = 16; $t <= 79; $t++) {
            array_push($w, add_mod_b(add_mod_b(add_mod_b(sigma_1_512($w[$t-2]), $w[$t-7]), sigma_0_512($w[$t-15])), $w[$t-16]));
        }
        list($a, $b, $c, $d, $e, $f, $g, $h) = $ht;

        for ($t = 0; $t <= 79; $t++) {
            $t1 = add_mod_b(add_mod_b(add_mod_b(add_mod_b($h, sum_1_512($e)), ch($e, $f, $g)), $kt[$t]), $w[$t]);
            $t2 = add_mod_b(sum_0_512($a), maj($a, $b, $c));

            $h = $g;
            $g = $f;
            $f = $e;
            $e = add_mod_b($d, $t1);
            $d = $c;
            $c = $b;
            $b = $a;
            $a = add_mod_b($t1, $t2);

        }
        $ht[0] = add_mod_b($ht[0], $a);
        $ht[1] = add_mod_b($ht[1], $b);
        $ht[2] = add_mod_b($ht[2], $c);
        $ht[3] = add_mod_b($ht[3], $d);
        $ht[4] = add_mod_b($ht[4], $e);
        $ht[5] = add_mod_b($ht[5], $f);
        $ht[6] = add_mod_b($ht[6], $g);
        $ht[7] = add_mod_b($ht[7], $h);
    }
    $result = "";
    for ($i = 0; $i <= 5; $i++) {
        $result .= bin_to_hex($ht[$i])." "; 
    }
        
    return $result;
    
}



echo var_dump(SHA_384($_GET["word"]));
echo var_dump(hash('sha384', $_GET["word"]));
?>

Ответы (0 шт):