Реализация 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"]));
?>