Files
md6/md6.php
T
2014-10-10 23:53:24 +09:00

267 lines
7.1 KiB
PHP

<?php
/**
*
* md6hash for PHP
*
* Usage :
* $md6 = new md6hash;
* $data = "md6 FTW";
* $result = $md6->hex($data);
* echo $result; // 7bfaa624f661a683be2a3b2007493006a30a7845ee1670e499927861a8e74cce
*
*/
class md6hash {
private function to_word($input) {
$output = array();
for($i = 0 ; $i < count($input) ; $i += 8) {
array_push($output, array(
(($input[$i ] << 24) | ($input[$i+1] << 16) | ($input[$i+2] << 8) | ($input[$i+3])),
(($input[$i+4] << 24) | ($input[$i+5] << 16) | ($input[$i+6] << 8) | ($input[$i+7]))
));
}
return $output;
}
private function from_word($input) {
$output = array();
for($i = 0 ; $i < count($input) ; $i += 1) {
array_push($output, ($input[$i][0] >> 24) & 0xff);
array_push($output, ($input[$i][0] >> 16) & 0xff);
array_push($output, ($input[$i][0] >> 8) & 0xff);
array_push($output, ($input[$i][0] >> 0) & 0xff);
array_push($output, ($input[$i][1] >> 24) & 0xff);
array_push($output, ($input[$i][1] >> 16) & 0xff);
array_push($output, ($input[$i][1] >> 8) & 0xff);
array_push($output, ($input[$i][1] >> 0) & 0xff);
}
return $output;
}
private function _xor($x, $y) {
return array($x[0] ^ $y[0], $x[1] ^ $y[1]);
}
private function _and($x, $y) {
return array($x[0] & $y[0], $x[1] & $y[1]);
}
private function _shl($x, $n) {
$a = $x[0];
$b = $x[1];
if($n >= 32) {
return array(($b << ($n - 32)) & 0xffffffff, 0x00000000);
}
else {
return array((($a << $n) | ($b >> (32 - $n))) & 0xffffffff, ($b << $n) & 0xffffffff);
}
}
private function _shr($x, $n) {
$a = $x[0];
$b = $x[1];
if($n >= 32) {
return array(0x00000000, $a >> ($n - 32));
}
else {
return array(($a >> $n) & 0xffffffff, (($a << (32 - $n)) | ($b >> $n)) & 0xffffffff);
}
}
private function crop($size, $hash, $right = false) {
$length = floor(($size + 7) / 8);
$remain = $size % 8;
if($right) {
$hash = array_slice($hash, count($hash) - $length);
}
else {
$hash = array_slice($hash, 0, $length);
}
if($remain > 0) {
$hash[$length - 1] &= (0xff << (8 - $remain)) & 0xff;
}
return $hash;
}
private function bytes($input) {
$output = array();
$length = strlen($input);
for($i = 0 ; $i < $length ; $i++) {
array_push($output, ord($input[$i]));
}
return $output;
}
private function f($N) {
$S = array_merge(array(), $this->S0);
$A = array_merge(array(), $N);
for($j = 0, $i = $this->n ; $j < $this->r ; $j += 1, $i += 16) {
for($s = 0 ; $s < 16 ; $s += 1) {
$x = array_merge(array(), $S);
$x = $this->_xor($x, $A[$i + $s - $this->t[5]]);
$x = $this->_xor($x, $A[$i + $s - $this->t[0]]);
$x = $this->_xor($x, $this->_and($A[$i + $s - $this->t[1]], $A[$i + $s - $this->t[2]]));
$x = $this->_xor($x, $this->_and($A[$i + $s - $this->t[3]], $A[$i + $s - $this->t[4]]));
$x = $this->_xor($x, $this->_shr($x, $this->rs[$s]));
$A[$i + $s] = $this->_xor($x, $this->_shl($x, $this->ls[$s]));
}
$S = $this->_xor($this->_xor($this->_shl($S, 1), $this->_shr($S, 63)), $this->_and($S, $this->Sm));
}
return array_slice($A, count($A) - 16);
}
private function mid($B, $C, $i, $p, $z) {
$U = array(
(($this->ell & 0xff) << 24) | (($i / 0xffffffff) & 0xffffff),
$i & 0xffffffff
);
$V = array(
(($this->r & 0xfff) << 16) | (($this->L & 0xff) << 8) | (($z & 0xf) << 4) | (($p & 0xf000) >> 12),
(($p & 0xfff) << 20) | (($this->k & 0xff) << 12) | (($this->d & 0xfff))
);
return $this->f(array_merge($this->Q, $this->K, array($U, $V), $C, $B));
}
private function par($M) {
$P = 0;
$B = array();
$C = array();
$z = count($M) > $this->b ? 0 : 1;
while(count($M) < 1 || (count($M) % $this->b) > 0) {
array_push($M, 0x00);
$P += 8;
}
$M = $this->to_word($M);
while(count($M) > 0) {
array_push($B, array_slice($M, 0, ($this->b / 8)));
$M = array_slice($M, $this->b / 8);
}
for($i = 0, $p = 0, $l = count($B) ; $i < $l ; $i += 1, $p = 0) {
$p = ($i === (count($B) - 1)) ? $P : 0;
$C = array_merge($C, $this->mid($B[$i], array(), $i, $p, $z));
}
return $this->from_word($C);
}
private function seq($M) {
$P = 0;
$B = array();
$C = array(
array(0x0, 0x0), array(0x0, 0x0), array(0x0, 0x0), array(0x0, 0x0),
array(0x0, 0x0), array(0x0, 0x0), array(0x0, 0x0), array(0x0, 0x0),
array(0x0, 0x0), array(0x0, 0x0), array(0x0, 0x0), array(0x0, 0x0),
array(0x0, 0x0), array(0x0, 0x0), array(0x0, 0x0), array(0x0, 0x0)
);
while(count($M) < 1 || (count($M) % ($this->b - $this->c)) > 0) {
array_push($M, 0x00);
$P += 8;
}
$M = $this->to_word($M);
while(count($M) > 0) {
array_push($B, array_slice($M, 0, (($this->b - $this->c) / 8)));
$M = array_slice(($this->b - $this->c) / 8);
}
for($i = 0, $p = 0, $l = count($B) ; $i < $l ; $i += 1, $p = 0) {
$p = ($i === (count($B) - 1)) ? $P : 0;
$z = ($i === (count($B) - 1)) ? 1 : 0;
$C = $this->mid($B[$i], $C, $i, $p, $z);
}
return $this->from_word($C);
}
private $b, $c, $n, $d, $K, $k, $r, $L, $ell, $S0, $Sm, $Q, $t, $rs, $ls;
private function _hash($data, $size, $key, $levels) {
$this->b = 512;
$this->c = 128;
$this->n = 89;
$this->d = $size;
$this->M = $data;
$this->K = array_slice($key, 0, 64);
$this->k = count($this->K);
while(count($this->K) < 64) {
array_push($this->K, 0x00);
}
$this->K = $this->to_word($this->K);
$this->r = max(($this->k ? 80 : 0), (40 + ($this->d / 4)));
$this->L = $levels;
$this->ell = 0;
$this->S0 = array(0x01234567, 0x89abcdef);
$this->Sm = array(0x7311c281, 0x2425cfa0);
$this->Q = array(
array(0x7311c281, 0x2425cfa0), array(0x64322864, 0x34aac8e7), array(0xb60450e9, 0xef68b7c1),
array(0xe8fb2390, 0x8d9f06f1), array(0xdd2e76cb, 0xa691e5bf), array(0x0cd0d63b, 0x2c30bc41),
array(0x1f8ccf68, 0x23058f8a), array(0x54e5ed5b, 0x88e3775d), array(0x4ad12aae, 0x0a6d6031),
array(0x3e7f16bb, 0x88222e0d), array(0x8af8671d, 0x3fb50c2c), array(0x995ad117, 0x8bd25c31),
array(0xc878c1dd, 0x04c4b633), array(0x3b72066c, 0x7a1552ac), array(0x0d6f3522, 0x631effcb)
);
$this->t = array(17, 18, 21, 31, 67, 89);
$this->rs = array(10, 5, 13, 10, 11, 12, 2, 7, 14, 15, 7, 13, 11, 7, 6, 12);
$this->ls = array(11, 24, 9, 16, 15, 9, 27, 15, 6, 2, 29, 8, 15, 5, 31, 9);
do {
$this->ell += 1;
$this->M = $this->ell > $this->L ? $this->seq($this->M) : $this->par($this->M);
} while(count($this->M) !== $this->c);
return $this->crop($this->d, $this->M, true);
}
private function _prehash($data, $size, $key, $levels) {
$data = $this->bytes($data);
$key = $this->bytes($key);
if($size <= 0) $size = 1;
if($size > 512) $size = 512;
return $this->_hash($data, $size, $key, $levels);
}
public function hex($data = "", $size = 256, $key = "", $levels = 64) {
$hash = $this->_prehash($data, $size, $key, $levels);
$hex = "";
foreach($hash as $v) $hex .= str_pad(dechex($v), 2, "0", STR_PAD_LEFT);
return $hex;
}
public function raw($data = "", $size = 256, $key = "", $levels = 64) {
$hash = $this->_prehash($data, $size, $key, $levels);
$raw = "";
foreach($hash as $v) $raw .= chr($v);
return $raw;
}
}