Skip to content

Commit 2a02641

Browse files
committed
Keccak: tighten
1 parent 4b15ce8 commit 2a02641

File tree

2 files changed

+99
-230
lines changed

2 files changed

+99
-230
lines changed

src/Keccak.php

Lines changed: 30 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,20 @@
22

33
namespace kornrunner;
44

5+
use Exception;
6+
use function mb_strlen;
7+
use function mb_substr;
8+
59
final class Keccak
610
{
711
private const KECCAK_ROUNDS = 24;
812
private const LFSR = 0x01;
13+
private const ENCODING = '8bit';
914
private static $keccakf_rotc = [1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44];
1015
private static $keccakf_piln = [10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12,2, 20, 14, 22, 9, 6, 1];
16+
private static $x64 = (PHP_INT_SIZE === 8);
1117

12-
private static function keccakf64(&$st, $rounds)
13-
{
18+
private static function keccakf64(&$st, $rounds): void {
1419
$keccakf_rndc = [
1520
[0x00000000, 0x00000001], [0x00000000, 0x00008082], [0x80000000, 0x0000808a], [0x80000000, 0x80008000],
1621
[0x00000000, 0x0000808b], [0x00000000, 0x80000001], [0x80000000, 0x80008081], [0x80000000, 0x00008009],
@@ -90,11 +95,10 @@ private static function keccakf64(&$st, $rounds)
9095
}
9196
}
9297

93-
private static function keccak64($in_raw, $capacity, $outputlength, $suffix, $raw_output)
94-
{
98+
private static function keccak64($in_raw, int $capacity, int $outputlength, $suffix, bool $raw_output): string {
9599
$capacity /= 8;
96100

97-
$inlen = self::ourStrlen($in_raw);
101+
$inlen = mb_strlen($in_raw, self::ENCODING);
98102

99103
$rsiz = 200 - 2 * $capacity;
100104
$rsizw = $rsiz / 8;
@@ -106,7 +110,7 @@ private static function keccak64($in_raw, $capacity, $outputlength, $suffix, $ra
106110

107111
for ($in_t = 0; $inlen >= $rsiz; $inlen -= $rsiz, $in_t += $rsiz) {
108112
for ($i = 0; $i < $rsizw; $i++) {
109-
$t = unpack('V*', self::ourSubstr($in_raw, $i * 8 + $in_t, 8));
113+
$t = unpack('V*', mb_substr($in_raw, $i * 8 + $in_t, 8, self::ENCODING));
110114

111115
$st[$i] = [
112116
$st[$i][0] ^ $t[2],
@@ -117,14 +121,14 @@ private static function keccak64($in_raw, $capacity, $outputlength, $suffix, $ra
117121
self::keccakf64($st, self::KECCAK_ROUNDS);
118122
}
119123

120-
$temp = self::ourSubstr($in_raw, $in_t, $inlen);
124+
$temp = mb_substr($in_raw, $in_t, $inlen, self::ENCODING);
121125
$temp = str_pad($temp, $rsiz, "\x0", STR_PAD_RIGHT);
122126

123127
$temp[$inlen] = chr($suffix);
124128
$temp[$rsiz - 1] = chr(ord($temp[$rsiz - 1]) | 0x80);
125129

126130
for ($i = 0; $i < $rsizw; $i++) {
127-
$t = unpack('V*', self::ourSubstr($temp, $i * 8, 8));
131+
$t = unpack('V*', mb_substr($temp, $i * 8, 8, self::ENCODING));
128132

129133
$st[$i] = [
130134
$st[$i][0] ^ $t[2],
@@ -138,13 +142,12 @@ private static function keccak64($in_raw, $capacity, $outputlength, $suffix, $ra
138142
for ($i = 0; $i < 25; $i++) {
139143
$out .= $t = pack('V*', $st[$i][1], $st[$i][0]);
140144
}
141-
$r = self::ourSubstr($out, 0, $outputlength / 8);
145+
$r = mb_substr($out, 0, $outputlength / 8, self::ENCODING);
142146

143147
return $raw_output ? $r : bin2hex($r);
144148
}
145149

146-
private static function keccakf32(&$st, $rounds)
147-
{
150+
private static function keccakf32(&$st, $rounds): void {
148151
$keccakf_rndc = [
149152
[0x0000, 0x0000, 0x0000, 0x0001], [0x0000, 0x0000, 0x0000, 0x8082], [0x8000, 0x0000, 0x0000, 0x0808a], [0x8000, 0x0000, 0x8000, 0x8000],
150153
[0x0000, 0x0000, 0x0000, 0x808b], [0x0000, 0x0000, 0x8000, 0x0001], [0x8000, 0x0000, 0x8000, 0x08081], [0x8000, 0x0000, 0x0000, 0x8009],
@@ -230,11 +233,10 @@ private static function keccakf32(&$st, $rounds)
230233
}
231234
}
232235

233-
private static function keccak32($in_raw, $capacity, $outputlength, $suffix, $raw_output)
234-
{
236+
private static function keccak32($in_raw, int $capacity, int $outputlength, $suffix, bool $raw_output): string {
235237
$capacity /= 8;
236238

237-
$inlen = self::ourStrlen($in_raw);
239+
$inlen = mb_strlen($in_raw, self::ENCODING);
238240

239241
$rsiz = 200 - 2 * $capacity;
240242
$rsizw = $rsiz / 8;
@@ -246,7 +248,7 @@ private static function keccak32($in_raw, $capacity, $outputlength, $suffix, $ra
246248

247249
for ($in_t = 0; $inlen >= $rsiz; $inlen -= $rsiz, $in_t += $rsiz) {
248250
for ($i = 0; $i < $rsizw; $i++) {
249-
$t = unpack('v*', self::ourSubstr($in_raw, $i * 8 + $in_t, 8));
251+
$t = unpack('v*', mb_substr($in_raw, $i * 8 + $in_t, 8, self::ENCODING));
250252

251253
$st[$i] = [
252254
$st[$i][0] ^ $t[4],
@@ -259,14 +261,14 @@ private static function keccak32($in_raw, $capacity, $outputlength, $suffix, $ra
259261
self::keccakf32($st, self::KECCAK_ROUNDS);
260262
}
261263

262-
$temp = self::ourSubstr($in_raw, $in_t, $inlen);
264+
$temp = mb_substr($in_raw, $in_t, $inlen, self::ENCODING);
263265
$temp = str_pad($temp, $rsiz, "\x0", STR_PAD_RIGHT);
264266

265267
$temp[$inlen] = chr($suffix);
266268
$temp[$rsiz - 1] = chr((int) $temp[$rsiz - 1] | 0x80);
267269

268270
for ($i = 0; $i < $rsizw; $i++) {
269-
$t = unpack('v*', self::ourSubstr($temp, $i * 8, 8));
271+
$t = unpack('v*', mb_substr($temp, $i * 8, 8, self::ENCODING));
270272

271273
$st[$i] = [
272274
$st[$i][0] ^ $t[4],
@@ -282,118 +284,31 @@ private static function keccak32($in_raw, $capacity, $outputlength, $suffix, $ra
282284
for ($i = 0; $i < 25; $i++) {
283285
$out .= $t = pack('v*', $st[$i][3],$st[$i][2], $st[$i][1], $st[$i][0]);
284286
}
285-
$r = self::ourSubstr($out, 0, $outputlength / 8);
287+
$r = mb_substr($out, 0, $outputlength / 8, self::ENCODING);
286288

287289
return $raw_output ? $r: bin2hex($r);
288290
}
289291

290-
// 0 = not run, 1 = 64 bit passed, 2 = 32 bit passed, 3 = failed
291-
private static $test_state = 0;
292-
private static function selfTest()
293-
{
294-
if(self::$test_state === 1 || self::$test_state === 2){
295-
return;
296-
}
297-
298-
if(self::$test_state === 3){
299-
throw new \Exception('Keccak previous self test failed!');
300-
}
301-
302-
$in = '';
303-
$md = 'f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd';
304-
if(self::keccak64($in, 224, 224, self::LFSR, false) === $md){
305-
self::$test_state = 1;
306-
return;
307-
}
308-
309-
if(self::keccak32($in, 224, 224, self::LFSR, false) === $md){
310-
self::$test_state = 2;
311-
return;
312-
}
313-
314-
self::$test_state = 3;
315-
throw new \Exception('Keccak self test failed!');
292+
private static function keccak($in_raw, int $capacity, int $outputlength, $suffix, bool $raw_output): string {
293+
return self::$x64
294+
? self::keccak64($in_raw, $capacity, $outputlength, $suffix, $raw_output)
295+
: self::keccak32($in_raw, $capacity, $outputlength, $suffix, $raw_output);
316296
}
317297

318-
private static function keccak($in_raw, $capacity, $outputlength, $suffix, $raw_output)
319-
{
320-
self::selfTest();
321-
322-
if(self::$test_state === 1) {
323-
return self::keccak64($in_raw, $capacity, $outputlength, $suffix, $raw_output);
324-
}
325-
326-
return self::keccak32($in_raw, $capacity, $outputlength, $suffix, $raw_output);
327-
}
328-
329-
public static function hash($in, $mdlen, $raw_output = false)
330-
{
331-
if( ! in_array($mdlen, [224, 256, 384, 512], true)) {
332-
throw new \Exception('Unsupported Keccak Hash output size.');
298+
public static function hash($in, int $mdlen, bool $raw_output = false): string {
299+
if (!in_array($mdlen, [224, 256, 384, 512], true)) {
300+
throw new Exception('Unsupported Keccak Hash output size.');
333301
}
334302

335303
return self::keccak($in, $mdlen, $mdlen, self::LFSR, $raw_output);
336304
}
337305

338-
public static function shake($in, $security_level, $outlen, $raw_output = false)
339-
{
340-
if( ! in_array($security_level, [128, 256], true)) {
341-
throw new \Exception('Unsupported Keccak Shake security level.');
306+
public static function shake($in, int $security_level, int $outlen, bool $raw_output = false): string {
307+
if (!in_array($security_level, [128, 256], true)) {
308+
throw new Exception('Unsupported Keccak Shake security level.');
342309
}
343310

344311
return self::keccak($in, $security_level, $outlen, 0x1f, $raw_output);
345312
}
346313

347-
/**
348-
* Multi-byte-safe string functions borrowed from https://github.com/sarciszewski/php-future
349-
*/
350-
351-
/**
352-
* Multi-byte-safe string length calculation
353-
*
354-
* @param string $str
355-
* @return int
356-
*/
357-
private static function ourStrlen($str)
358-
{
359-
// Premature optimization: cache the function_exists() result
360-
static $exists = null;
361-
if ($exists === null) {
362-
$exists = \function_exists('\\mb_strlen');
363-
}
364-
// If it exists, we need to make sure we're using 8bit mode
365-
if ($exists) {
366-
$length = \mb_strlen($str, '8bit');
367-
if ($length === false) {
368-
throw new \Exception('mb_strlen() failed.');
369-
}
370-
return $length;
371-
}
372-
373-
return \strlen($str);
374-
}
375-
376-
/**
377-
* Multi-byte-safe substring calculation
378-
*
379-
* @param string $str
380-
* @param int $start
381-
* @param int $length (optional)
382-
* @return string
383-
*/
384-
private static function ourSubstr($str, $start = 0, $length = null)
385-
{
386-
// Premature optimization: cache the function_exists() result
387-
static $exists = null;
388-
if ($exists === null) {
389-
$exists = \function_exists('\\mb_substr');
390-
}
391-
// If it exists, we need to make sure we're using 8bit mode
392-
if ($exists) {
393-
return \mb_substr($str, $start, $length, '8bit');
394-
} elseif ($length !== null) {
395-
return \substr($str, $start, $length);
396-
}
397-
return \substr($str, $start);
398-
}
399314
}

0 commit comments

Comments
 (0)