update lock clucknut
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 14s
Build, Push and Deploy / build-and-push (push) Successful in 3m14s
Build, Push and Deploy / deploy-staging (push) Successful in 25s
Build, Push and Deploy / deploy-production (push) Has been skipped

This commit is contained in:
2026-04-18 20:32:18 +07:00
parent 4554035227
commit dcaf267458
3359 changed files with 153185 additions and 205489 deletions

View File

@@ -356,9 +356,11 @@ public static function switchEndianness($x)
// from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits
$p1 = ($b * 0x0802) & 0x22110;
$p2 = ($b * 0x8020) & 0x88440;
$r .= chr(
(($p1 | $p2) * 0x10101) >> 16
);
$temp = ($p1 | $p2) * 0x10101;
if (is_float($temp)) {
$temp = (int) fmod($temp, 0x7FFFFFFF);
}
$r .= chr(($temp >> 16) & 0xFF);
}
}
return $r;

View File

@@ -448,8 +448,8 @@ protected function setupKey()
protected static function initialize_static_variables()
{
if (is_float(self::$sbox[0x200])) {
self::$sbox = array_map('intval', self::$sbox);
self::$parray = array_map('intval', self::$parray);
self::$sbox = array_map([self::class, 'safe_intval'], self::$sbox);
self::$parray = array_map([self::class, 'safe_intval'], self::$parray);
}
parent::initialize_static_variables();

View File

@@ -279,10 +279,10 @@ protected static function quarterRound(&$a, &$b, &$c, &$d)
// xor'ing and rotation are all on the same line so i'm keeping it on the same
// line here as well
// @codingStandardsIgnoreStart
$a+= $b; $d = self::leftRotate(intval($d) ^ intval($a), 16);
$c+= $d; $b = self::leftRotate(intval($b) ^ intval($c), 12);
$a+= $b; $d = self::leftRotate(intval($d) ^ intval($a), 8);
$c+= $d; $b = self::leftRotate(intval($b) ^ intval($c), 7);
$a+= $b; $d = self::leftRotate(self::safe_intval($d) ^ self::safe_intval($a), 16);
$c+= $d; $b = self::leftRotate(self::safe_intval($b) ^ self::safe_intval($c), 12);
$a+= $b; $d = self::leftRotate(self::safe_intval($d) ^ self::safe_intval($a), 8);
$c+= $d; $b = self::leftRotate(self::safe_intval($b) ^ self::safe_intval($c), 7);
// @codingStandardsIgnoreEnd
}
@@ -357,424 +357,424 @@ protected static function salsa20($x)
// @codingStandardsIgnoreStart
// columnRound
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);
// rowRound
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);
// columnRound
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);
// rowRound
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);
// columnRound
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);
// rowRound
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);
// columnRound
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);
// rowRound
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);
// columnRound
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);
// rowRound
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);
// columnRound
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);
// rowRound
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);
// columnRound
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);
// rowRound
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);
// columnRound
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);
// rowRound
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);
// columnRound
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);
// rowRound
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);
// columnRound
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
$x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
$x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
$x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
$x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
$x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
$x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
$x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
$x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);
// rowRound
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
$x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
$x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
$x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
$x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
$x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
$x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
$x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
$x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);
// @codingStandardsIgnoreEnd
$x0 += $z0;
@@ -794,6 +794,6 @@ protected static function salsa20($x)
$x14 += $z14;
$x15 += $z15;
return pack('V*', $x0, $x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15);
return pack('V*', self::safe_intval($x0), self::safe_intval($x1), self::safe_intval($x2), self::safe_intval($x3), self::safe_intval($x4), self::safe_intval($x5), self::safe_intval($x6), self::safe_intval($x7), self::safe_intval($x8), self::safe_intval($x9), self::safe_intval($x10), self::safe_intval($x11), self::safe_intval($x12), self::safe_intval($x13), self::safe_intval($x14), self::safe_intval($x15));
}
}

View File

@@ -78,13 +78,6 @@ abstract class AsymmetricKey
*/
private static $invisiblePlugins = [];
/**
* Available Engines
*
* @var boolean[]
*/
protected static $engines = [];
/**
* Key Comment
*
@@ -92,6 +85,14 @@ abstract class AsymmetricKey
*/
private $comment;
/**
* OpenSSL configuration file name.
*
* @see self::createKey()
* @var ?string
*/
protected static $configFile;
/**
* @param string $type
* @return array|string
@@ -119,6 +120,10 @@ protected static function initialize_static_variables()
self::$one = new BigInteger(1);
}
if (!isset(self::$configFile)) {
self::$configFile = dirname(__FILE__) . '/../../openssl.cnf';
}
self::loadPlugins('Keys');
if (static::ALGORITHM != 'RSA' && static::ALGORITHM != 'DH') {
self::loadPlugins('Signature');
@@ -363,6 +368,18 @@ public static function getSupportedKeyFormats()
return self::$plugins[static::ALGORITHM]['Keys'];
}
/**
* Sets the OpenSSL config file path
*
* Set to the empty string to use the default config file
*
* @param string $val
*/
public static function setOpenSSLConfigPath($val)
{
self::$configFile = $val;
}
/**
* Add a fileformat plugin
*
@@ -419,34 +436,28 @@ public function getComment()
}
/**
* Tests engine validity
*
* Force engine (useful for unit testing)
*/
public static function useBestEngine()
public static function forceEngine($engine = null)
{
static::$engines = [
'PHP' => true,
'OpenSSL' => extension_loaded('openssl'),
// this test can be satisfied by either of the following:
// http://php.net/manual/en/book.sodium.php
// https://github.com/paragonie/sodium_compat
'libsodium' => function_exists('sodium_crypto_sign_keypair')
];
return static::$engines;
if (!isset($engine)) {
static::$forcedEngine = null;
return;
}
switch ($engine) {
case 'PHP':
case 'OpenSSL':
case 'libsodium':
static::$forcedEngine = $engine;
break;
default:
throw new \InvalidArgumentException('Valid engines are null, PHP, OpenSSL or libsodium');
}
}
/**
* Flag to use internal engine only (useful for unit testing)
*
*/
public static function useInternalEngine()
public static function getForcedEngine()
{
static::$engines = [
'PHP' => true,
'OpenSSL' => false,
'libsodium' => false
];
return static::$forcedEngine;
}
/**

View File

@@ -118,7 +118,7 @@ public static function load($key, $password = '')
return compact('type', 'publicKey', 'paddedKey');
}
$parts = explode(' ', $key, 3);
$parts = preg_split("#[\t ]+#", $key);
if (!isset($parts[1])) {
$key = base64_decode($parts[0]);

View File

@@ -565,7 +565,7 @@ protected static function wrapPrivateKey($key, $attr, $params, $password, $oid =
],
'privateKey' => $key
];
if ($oid != 'id-Ed25519' && $oid != 'id-Ed448') {
if ($oid != 'id-Ed25519' && $oid != 'id-Ed448' && $oid != 'id-X25519' && $oid != 'id-X448') {
$key['privateKeyAlgorithm']['parameters'] = $params;
}
if (!empty($attr)) {
@@ -682,7 +682,7 @@ protected static function wrapPublicKey($key, $params, $oid = null, array $optio
'publicKey' => "\0" . $key
];
if ($oid != 'id-Ed25519' && $oid != 'id-Ed448') {
if ($oid != 'id-Ed25519' && $oid != 'id-Ed448' && $oid != 'id-X25519' && $oid != 'id-X448') {
$key['publicKeyAlgorithm']['parameters'] = $params;
}

View File

@@ -666,6 +666,11 @@ protected static function initialize_static_variables()
{
if (!isset(self::$use_reg_intval)) {
switch (true) {
// PHP 8.5, per https://www.php.net/manual/en/migration85.incompatible.php, now emits a warning
// "when casting floats (or strings that look like floats) to int if they cannot be represented as one"
case PHP_VERSION_ID >= 80500 && PHP_INT_SIZE == 4:
self::$use_reg_intval = false;
break;
// PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
case (PHP_OS & "\xDF\xDF\xDF") === 'WIN':
case !function_exists('php_uname'):
@@ -2591,7 +2596,7 @@ protected function unpad($text)
$length = ord($text[strlen($text) - 1]);
if (!$length || $length > $this->block_size) {
if (!$length | ($length > $this->block_size)) {
throw new BadDecryptionException("The ciphertext has an invalid padding length ($length) compared to the block size ({$this->block_size})");
}

View File

@@ -673,14 +673,14 @@ private function processBlock($block, $mode)
{
static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
if (!$sbox1) {
$sbox1 = array_map('intval', self::$sbox1);
$sbox2 = array_map('intval', self::$sbox2);
$sbox3 = array_map('intval', self::$sbox3);
$sbox4 = array_map('intval', self::$sbox4);
$sbox5 = array_map('intval', self::$sbox5);
$sbox6 = array_map('intval', self::$sbox6);
$sbox7 = array_map('intval', self::$sbox7);
$sbox8 = array_map('intval', self::$sbox8);
$sbox1 = array_map([self::class, 'safe_intval'], self::$sbox1);
$sbox2 = array_map([self::class, 'safe_intval'], self::$sbox2);
$sbox3 = array_map([self::class, 'safe_intval'], self::$sbox3);
$sbox4 = array_map([self::class, 'safe_intval'], self::$sbox4);
$sbox5 = array_map([self::class, 'safe_intval'], self::$sbox5);
$sbox6 = array_map([self::class, 'safe_intval'], self::$sbox6);
$sbox7 = array_map([self::class, 'safe_intval'], self::$sbox7);
$sbox8 = array_map([self::class, 'safe_intval'], self::$sbox8);
/* Merge $shuffle with $[inv]ipmap */
for ($i = 0; $i < 256; ++$i) {
$shuffleip[] = self::$shuffle[self::$ipmap[$i]];
@@ -1243,9 +1243,9 @@ protected function setupKey()
$pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[ $d & 0xFF];
// Reorder: odd bytes/even bytes. Push the result in key schedule.
$val1 = ( $cp & intval(0xFF000000)) | (($cp << 8) & 0x00FF0000) |
$val1 = ( $cp & self::safe_intval(0xFF000000)) | (($cp << 8) & 0x00FF0000) |
(($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF);
$val2 = (($cp << 8) & intval(0xFF000000)) | (($cp << 16) & 0x00FF0000) |
$val2 = (($cp << 8) & self::safe_intval(0xFF000000)) | (($cp << 16) & 0x00FF0000) |
(($dp >> 8) & 0x0000FF00) | ( $dp & 0x000000FF);
$keys[$des_round][self::ENCRYPT][ ] = $val1;
$keys[$des_round][self::DECRYPT][$ki - 1] = $val1;
@@ -1292,14 +1292,14 @@ protected function setupInlineCrypt()
$init_crypt = 'static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
if (!$sbox1) {
$sbox1 = array_map("intval", self::$sbox1);
$sbox2 = array_map("intval", self::$sbox2);
$sbox3 = array_map("intval", self::$sbox3);
$sbox4 = array_map("intval", self::$sbox4);
$sbox5 = array_map("intval", self::$sbox5);
$sbox6 = array_map("intval", self::$sbox6);
$sbox7 = array_map("intval", self::$sbox7);
$sbox8 = array_map("intval", self::$sbox8);'
$sbox1 = array_map("self::safe_intval", self::$sbox1);
$sbox2 = array_map("self::safe_intval", self::$sbox2);
$sbox3 = array_map("self::safe_intval", self::$sbox3);
$sbox4 = array_map("self::safe_intval", self::$sbox4);
$sbox5 = array_map("self::safe_intval", self::$sbox5);
$sbox6 = array_map("self::safe_intval", self::$sbox6);
$sbox7 = array_map("self::safe_intval", self::$sbox7);
$sbox8 = array_map("self::safe_intval", self::$sbox8);'
/* Merge $shuffle with $[inv]ipmap */ . '
for ($i = 0; $i < 256; ++$i) {
$shuffleip[] = self::$shuffle[self::$ipmap[$i]];

View File

@@ -28,8 +28,14 @@
use phpseclib3\Crypt\DH\Parameters;
use phpseclib3\Crypt\DH\PrivateKey;
use phpseclib3\Crypt\DH\PublicKey;
use phpseclib3\Crypt\EC\Curves\Curve25519;
use phpseclib3\Crypt\EC\Curves\Curve448;
use phpseclib3\Crypt\EC\Formats\Keys\PKCS1;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Exception\NoKeyLoadedException;
use phpseclib3\Exception\UnsupportedOperationException;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;
/**
@@ -295,21 +301,51 @@ public static function computeSecret($private, $public)
}
if ($private instanceof EC\PrivateKey) {
$privateCurve = $private->getCurve();
switch (true) {
case $public instanceof EC\PublicKey:
if ($privateCurve !== $public->getCurve()) {
throw new \InvalidArgumentException("The public key curve (" . $public->getCurve() . ") and private key curve ($privateCurve) need to match");
}
$orig = $public;
$public = $public->getEncodedCoordinates();
// fall-through
case is_string($public):
$point = $private->multiply($public);
switch ($private->getCurve()) {
case 'Curve25519':
case 'Curve448':
$secret = $point;
break;
default:
// according to https://www.secg.org/sec1-v2.pdf#page=33 only X is returned
$secret = substr($point, 1, (strlen($point) - 1) >> 1);
$forcedEngine = EC::getForcedEngine();
if ($forcedEngine === 'libsodium' && $privateCurve !== 'Curve25519') {
throw new BadConfigurationException('Engine libsodium is forced but can only used with Curve25519 for ECDH');
}
if (!isset($forcedEngine) || $forcedEngine === 'OpenSSL') {
// PHP 7.3.0 introduced the openssl_pkey_derive() function
// openssl_dh_computee_key() has been around since PHP 5.3.0+ BUT it did not support ECDH
// until PHP 8.1.0 / OpenSSL 3.0.0
if ($forcedEngine === 'OpenSSL' && !function_exists('openssl_pkey_derive')) {
throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for ECDH');
}
if (function_exists('openssl_pkey_derive')) {
$privateStr = (string) $private->withPassword();
$publicStr = (string) (isset($orig) ? $orig : EC::convertPointToPublicKey($private->getCurve(), $public));
$result = openssl_pkey_derive($publicStr, $privateStr);
if ($result) {
return $result;
}
if ($forcedEngine === 'OpenSSL') {
// i suppose we _could_ try openssl_dh_compute_key() at this point
// quoting https://www.php.net/openssl-dh-compute-key "ECDH is only supported as of PHP 8.1.0 and OpenSSL 3.0.0". ie.
// PHP_VERSION_ID >= 80100 && OPENSSL_VERSION_NUMBER >= 0x3000000f
// but i think that's overkill. if openssl_pkey_derive() doesn't work it seems doubtful to me that openssl_dh_compute_key() would
throw new BadConfigurationException('Engine OpenSSL is forced but was unable to perform ECDH because of ' . openssl_error_string());
}
}
}
$curveName = $private->getCurve();
$isMontgomeryCurve = $curveName == 'Curve25519' || $curveName == 'Curve448';
if (!$isMontgomeryCurve) {
$public = EC::convertPointToPublicKey($curveName, $public, false);
}
$point = $private->multiply($public);
// according to https://www.secg.org/sec1-v2.pdf#page=33 only X is returned
$secret = $isMontgomeryCurve ? $point : substr($point, 1, (strlen($point) - 1) >> 1);
/*
if (($secret[0] & "\x80") === "\x80") {
$secret = "\0$secret";

View File

@@ -33,6 +33,7 @@
use phpseclib3\Crypt\DSA\Parameters;
use phpseclib3\Crypt\DSA\PrivateKey;
use phpseclib3\Crypt\DSA\PublicKey;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Exception\InsufficientSetupException;
use phpseclib3\Math\BigInteger;
@@ -87,6 +88,14 @@ abstract class DSA extends AsymmetricKey
*/
protected $sigFormat;
/**
* Forced Engine
*
* @var ?string
* @see parent::forceEngine()
*/
protected static $forcedEngine = null;
/**
* Signature Format (Short)
*
@@ -110,10 +119,6 @@ public static function createParameters($L = 2048, $N = 224)
throw new \RuntimeException('createParameters() should not be called from final classes (' . static::class . ')');
}
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
switch (true) {
case $N == 160:
/*
@@ -185,15 +190,19 @@ public static function createKey(...$args)
{
self::initialize_static_variables();
if (self::$forcedEngine == 'libsodium') {
throw new BadConfigurationException('Engine ' . self::$forcedEngine . ' is forced but unsupported for DSA');
}
if (self::$forcedEngine == 'OpenSSL' && !defined('OPENSSL_KEYTYPE_DSA')) {
throw new BadConfigurationException("Engine OpenSSL is forced but unsupported for DSA");
}
$class = new \ReflectionClass(static::class);
if ($class->isFinal()) {
throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')');
}
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
if (count($args) == 2 && is_int($args[0]) && is_int($args[1])) {
$params = self::createParameters($args[0], $args[1]);
} elseif (count($args) == 1 && $args[0] instanceof Parameters) {
@@ -204,6 +213,33 @@ public static function createKey(...$args)
throw new InsufficientSetupException('Valid parameters are either two integers (L and N), a single DSA object or no parameters at all.');
}
// at this point the only two supported values for self::$forcedEngine are OpenSSL, PHP and null
// if it's either OpenSSL or null we'll use OpenSSL (if it's available)
if (self::$forcedEngine !== 'PHP' && defined('OPENSSL_KEYTYPE_DSA')) {
$config = [];
if (self::$configFile) {
$config['config'] = self::$configFile;
}
$dsa = openssl_pkey_new($config + [
'private_key_type' => OPENSSL_KEYTYPE_DSA,
'p' => $params->p,
'q' => $params->q,
'g' => $params->g,
]);
if ($dsa && openssl_pkey_export($dsa, $privatekeystr, null, $config)) {
// clear the buffer of error strings stemming from a minimalistic openssl.cnf
// https://github.com/php/php-src/issues/11054 talks about other errors this'll pick up
while (openssl_error_string() !== false) {
}
return DSA::load($privatekeystr)
->withHash($params->hash->getHash())
->withSignatureFormat($params->shortFormat);
} elseif (isset(self::$forcedEngine)) {
throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for DSA');
}
}
$private = new PrivateKey();
$private->p = $params->p;
$private->q = $params->q;
@@ -227,10 +263,6 @@ public static function createKey(...$args)
*/
protected static function onLoad(array $components)
{
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
if (!isset($components['x']) && !isset($components['y'])) {
$new = new Parameters();
} elseif (isset($components['x'])) {
@@ -276,22 +308,6 @@ public function getLength()
return ['L' => $this->p->getLength(), 'N' => $this->q->getLength()];
}
/**
* Returns the current engine being used
*
* @see self::useInternalEngine()
* @see self::useBestEngine()
* @return string
*/
public function getEngine()
{
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
return self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods()) ?
'OpenSSL' : 'PHP';
}
/**
* Returns the parameters
*

View File

@@ -66,10 +66,22 @@ public static function load($key, $password = '')
return $key;
}
$key = ASN1::asn1map($decoded[0], Maps\DSAPublicKey::MAP);
if (is_array($key)) {
return $key;
}
// PKCS1 DSA public keys are not supported by phpseclib since they can't be used to do
// anything on their own. in order to verify a signature with DSA you need p, q, g and y.
// a PKCS1 DSA public key only has y. to verify a signature with a PKCS1 DSA public key
// you'd also need to load a PKCS1 DSA parameters file separately. like you'd need to
// load two files instead of just one. there's no other key format that phpseclib supports
// that has that requirement so building it in for PKCS1 DSA public keys seems excessive.
//
// the whole thing would be rather like an RSA public key having the modulo live in
// a separate file than the exponent.
//
// this isn't an issue for PKCS8 DSA public keys because those keys have the parameters
// included. eg. \phpseclib3\File\ASN1\Maps\SubjectPublicKeyInfo has "algorithm" and
// "subjectPublicKey" and "algorithm", in turn, has "algorithm" and "parameters". y
// is saved as "subjectPublicKey" and p, q and g are saved as "parameters".
//$key = ASN1::asn1map($decoded[0], Maps\DSAPublicKey::MAP);
throw new \RuntimeException('Unable to perform ASN1 mapping');
}

View File

@@ -15,6 +15,7 @@
use phpseclib3\Crypt\DSA;
use phpseclib3\Crypt\DSA\Formats\Signature\ASN1 as ASN1Signature;
use phpseclib3\Math\BigInteger;
use phpseclib3\Exception\BadConfigurationException;
/**
* DSA Private Key
@@ -79,20 +80,34 @@ public function sign($message)
{
$format = $this->sigFormat;
if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
$signature = '';
$result = openssl_sign($message, $signature, $this->toString('PKCS8'), $this->hash->getHash());
if (self::$forcedEngine === 'libsodium') {
throw new BadConfigurationException('Engine libsodium is forced but unsupported for DSA');
}
if ($result) {
if ($this->shortFormat == 'ASN1') {
return $signature;
if (self::$forcedEngine === 'OpenSSL' && !function_exists('openssl_get_md_methods')) {
throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for DSA');
}
if (function_exists('openssl_get_md_methods') && self::$forcedEngine !== 'PHP') {
if (in_array($this->hash->getHash(), openssl_get_md_methods())) {
$signature = '';
$result = openssl_sign($message, $signature, $this->toString('PKCS8'), $this->hash->getHash());
if ($result) {
if ($this->shortFormat == 'ASN1') {
return $signature;
}
$loaded = ASN1Signature::load($signature);
$r = $loaded['r'];
$s = $loaded['s'];
return $format::save($r, $s);
} elseif (self::$forcedEngine === 'OpenSSL') {
throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string());
}
$loaded = ASN1Signature::load($signature);
$r = $loaded['r'];
$s = $loaded['s'];
return $format::save($r, $s);
} elseif (self::$forcedEngine === 'OpenSSL') {
throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for DSA / ' . $this->hash->getHash());
}
}

View File

@@ -14,6 +14,7 @@
use phpseclib3\Crypt\Common;
use phpseclib3\Crypt\DSA;
use phpseclib3\Crypt\DSA\Formats\Signature\ASN1 as ASN1Signature;
use phpseclib3\Exception\BadConfigurationException;
/**
* DSA Public Key
@@ -34,6 +35,14 @@ final class PublicKey extends DSA implements Common\PublicKey
*/
public function verify($message, $signature)
{
if (self::$forcedEngine === 'libsodium') {
throw new BadConfigurationException('Engine libsodium is forced but unsupported for DSA');
}
if (self::$forcedEngine === 'OpenSSL' && !function_exists('openssl_get_md_methods')) {
throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for DSA');
}
$format = $this->sigFormat;
$params = $format::load($signature);
@@ -43,13 +52,17 @@ public function verify($message, $signature)
$r = $params['r'];
$s = $params['s'];
if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
$sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature;
if (function_exists('openssl_get_md_methods') && self::$forcedEngine !== 'PHP') {
if (in_array($this->hash->getHash(), openssl_get_md_methods())) {
$sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature;
$result = openssl_verify($message, $sig, $this->toString('PKCS8'), $this->hash->getHash());
$result = openssl_verify($message, $sig, $this->toString('PKCS8'), $this->hash->getHash());
if ($result != -1) {
return (bool) $result;
if ($result != -1) {
return (bool) $result;
}
} elseif (self::$forcedEngine === 'OpenSSL') {
throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for DSA / ' . $this->hash->getHash());
}
}

View File

@@ -33,12 +33,15 @@
use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use phpseclib3\Crypt\EC\Curves\Curve25519;
use phpseclib3\Crypt\EC\Curves\Curve448;
use phpseclib3\Crypt\EC\Curves\Ed25519;
use phpseclib3\Crypt\EC\Curves\Ed448;
use phpseclib3\Crypt\EC\Formats\Keys\PKCS1;
use phpseclib3\Crypt\EC\Formats\Keys\PKCS8;
use phpseclib3\Crypt\EC\Parameters;
use phpseclib3\Crypt\EC\PrivateKey;
use phpseclib3\Crypt\EC\PublicKey;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Exception\UnsupportedAlgorithmException;
use phpseclib3\Exception\UnsupportedCurveException;
use phpseclib3\Exception\UnsupportedOperationException;
@@ -74,13 +77,6 @@ abstract class EC extends AsymmetricKey
*/
protected $curve;
/**
* Signature Format
*
* @var string
*/
protected $format;
/**
* Signature Format (Short)
*
@@ -130,6 +126,14 @@ abstract class EC extends AsymmetricKey
*/
protected $sigFormat;
/**
* Forced Engine
*
* @var ?string
* @see parent::forceEngine()
*/
protected static $forcedEngine = null;
/**
* Create public / private key pair.
*
@@ -145,31 +149,7 @@ public static function createKey($curve)
throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')');
}
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
$curve = strtolower($curve);
if (self::$engines['libsodium'] && $curve == 'ed25519' && function_exists('sodium_crypto_sign_keypair')) {
$kp = sodium_crypto_sign_keypair();
$privatekey = EC::loadFormat('libsodium', sodium_crypto_sign_secretkey($kp));
//$publickey = EC::loadFormat('libsodium', sodium_crypto_sign_publickey($kp));
$privatekey->curveName = 'Ed25519';
//$publickey->curveName = $curve;
return $privatekey;
}
$privatekey = new PrivateKey();
$curveName = $curve;
if (preg_match('#(?:^curve|^ed)\d+$#', $curveName)) {
$curveName = ucfirst($curveName);
} elseif (substr($curveName, 0, 10) == 'brainpoolp') {
$curveName = 'brainpoolP' . substr($curveName, 10);
}
$curveName = self::getCurveCase($curve);
$curve = '\phpseclib3\Crypt\EC\Curves\\' . $curveName;
if (!class_exists($curve)) {
@@ -180,6 +160,53 @@ public static function createKey($curve)
$curveName = $reflect->isFinal() ?
$reflect->getParentClass()->getShortName() :
$reflect->getShortName();
$curveEngineName = self::getOpenSSLCurveName(strtolower($curveName));
switch ($curveName) {
case 'Ed25519':
$providers = [
'libsodium' => function_exists('sodium_crypto_sign_keypair'),
// OPENSSL_KEYTYPE_ED25519 introduced in PHP 8.4.0
'OpenSSL' => defined('OPENSSL_KEYTYPE_ED25519'),
];
break;
case 'Ed448':
// OPENSSL_KEYTYPE_ED448 introduced in PHP 8.4.0
$providers = ['OpenSSL' => defined('OPENSSL_KEYTYPE_ED448')];
break;
case 'Curve25519':
$providers = [
'libsodium' => function_exists('sodium_crypto_box_publickey_from_secretkey'),
// OPENSSL_KEYTYPE_X25519 introduced in PHP 8.4.0
'OpenSSL' => defined('OPENSSL_KEYTYPE_X25519'),
];
// OPENSSL_KEYTYPE_X448 introduced in PHP 8.4.0
case 'Curve448':
$providers = ['OpenSSL' => defined('OPENSSL_KEYTYPE_X448')];
break;
default:
// openssl_get_curve_names() was introduced in PHP 7.1.0
// exclude curve25519 and curve448 from testing
$providers = ['OpenSSL' => function_exists('openssl_get_curve_names') && substr($curveEngineName, 0, 5) != 'curve' && in_array($curveEngineName, openssl_get_curve_names())];
};
foreach ($providers as $engine => $isSupported) {
// if an engine is being forced and the forced engine doesn't match $engine, skip it
if (isset(self::$forcedEngine) && self::$forcedEngine !== $engine) {
continue;
}
if ($isSupported) {
$result = self::generateWithEngine($engine, $curveEngineName);
if (isset($result)) {
return $result;
}
}
if (self::$forcedEngine === $engine) {
throw new BadConfigurationException("EC::createKey: Engine $engine is forced but unsupported for $curve");
}
}
$privatekey = new PrivateKey();
$curve = new $curve();
if ($curve instanceof TwistedEdwardsCurve) {
@@ -189,21 +216,14 @@ public static function createKey($curve)
} else {
$privatekey->dA = $dA = $curve->createRandomMultiplier();
}
if ($curve instanceof Curve25519 && self::$engines['libsodium']) {
//$r = pack('H*', '0900000000000000000000000000000000000000000000000000000000000000');
//$QA = sodium_crypto_scalarmult($dA->toBytes(), $r);
$QA = sodium_crypto_box_publickey_from_secretkey($dA->toBytes());
$privatekey->QA = [$curve->convertInteger(new BigInteger(strrev($QA), 256))];
} else {
$privatekey->QA = $curve->multiplyPoint($curve->getBasePoint(), $dA);
}
$privatekey->curve = $curve;
$privatekey->curveName = $curveName;
$privatekey->QA = $curve->multiplyPoint($curve->getBasePoint(), $dA);
//$publickey = clone $privatekey;
//unset($publickey->dA);
//unset($publickey->x);
$privatekey->curveName = $curveName;
//$publickey->curveName = $curveName;
if ($privatekey->curve instanceof TwistedEdwardsCurve) {
@@ -213,6 +233,130 @@ public static function createKey($curve)
return $privatekey;
}
/**
* Returns the actual case of the curve
*
* Useful for initializing the curve class
*
* @param string $curveName
* @return string
*/
private static function getCurveCase($curveName)
{
$curveName = strtolower($curveName);
if (preg_match('#(?:^curve|^ed)\d+$#', $curveName)) {
return ucfirst($curveName);
}
if (substr($curveName, 0, 10) == 'brainpoolp') {
return 'brainpoolP' . substr($curveName, 10);
}
return $curveName;
}
/**
* Return the OpenSSL name for a curve
*
* @param string $curve
* @return string
*/
private static function getOpenSSLCurveName($curve)
{
switch ($curve) {
case 'secp256r1':
return 'prime256v1';
case 'secp192r1':
return 'prime192v1';
}
return $curve;
}
/**
* Generate the key for a given curve / engine combo
*
* @param string $engine
* @param string $curve
* @return ?PrivateKey
*/
private static function generateWithEngine($engine, $curve)
{
if ($engine == 'libsodium') {
if ($curve == 'ed25519') {
$kp = sodium_crypto_sign_keypair();
$privatekey = EC::loadFormat('libsodium', sodium_crypto_sign_secretkey($kp));
//$publickey = EC::loadFormat('libsodium', sodium_crypto_sign_publickey($kp));
$privatekey->curveName = 'Ed25519';
//$publickey->curveName = $curve;
return $privatekey;
} else { // $curve == 'curve25519
$privatekey = new PrivateKey();
$privatekey->curve = new Curve25519();
$privatekey->curveName = 'Curve25519';
$privatekey->dA = $privatekey->curve->createRandomMultiplier();
$dA = str_pad($privatekey->dA->toBytes(), 32, "\0", STR_PAD_LEFT);
//$r = pack('H*', '0900000000000000000000000000000000000000000000000000000000000000');
//$QA = sodium_crypto_scalarmult($dA, $r);
$QA = sodium_crypto_box_publickey_from_secretkey($dA);
$privatekey->QA = [$privatekey->curve->convertInteger(new BigInteger(strrev($QA), 256))];
return $privatekey;
}
}
// at this point $engine == 'OpenSSL'
$curveName = self::getCurveCase($curve);
$config = [];
if (self::$configFile) {
$config['config'] = self::$configFile;
}
$params = $config;
switch ($curve) {
case 'ed25519':
$params['private_key_type'] = OPENSSL_KEYTYPE_ED25519;
break;
case 'ed448':
$params['private_key_type'] = OPENSSL_KEYTYPE_ED448;
break;
case 'curve25519':
$params['private_key_type'] = OPENSSL_KEYTYPE_X25519;
break;
case 'curve448':
$params['private_key_type'] = OPENSSL_KEYTYPE_X448;
break;
default:
$params['private_key_type'] = OPENSSL_KEYTYPE_EC;
$params['curve_name'] = $curveName;
}
$key = openssl_pkey_new($params);
if (!$key) {
return null;
}
$privateKeyStr = '';
if (!openssl_pkey_export($key, $privateKeyStr, null, $config)) {
return null;
}
// clear the buffer of error strings
while (openssl_error_string() !== false) {
}
// some versions of OpenSSL / PHP return PKCS1 keys, others return PKCS8 keys
$privatekey = EC::load($privateKeyStr);
switch ($curveName) {
case 'prime256v1':
$privatekey->curveName = 'secp256r1';
break;
case 'prime192v1':
$privatekey->curveName = 'secp192r1';
break;
default:
$privatekey->curveName = $curveName;
}
return $privatekey;
}
/**
* OnLoad Handler
*
@@ -220,10 +364,6 @@ public static function createKey($curve)
*/
protected static function onLoad(array $components)
{
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
if (!isset($components['dA']) && !isset($components['QA'])) {
$new = new Parameters();
$new->curve = $components['curve'];
@@ -320,27 +460,6 @@ public function getLength()
return $this->curve->getLength();
}
/**
* Returns the current engine being used
*
* @see self::useInternalEngine()
* @see self::useBestEngine()
* @return string
*/
public function getEngine()
{
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
if ($this->curve instanceof TwistedEdwardsCurve) {
return $this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context) ?
'libsodium' : 'PHP';
}
return self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods()) ?
'OpenSSL' : 'PHP';
}
/**
* Returns the public key coordinates as a string
*
@@ -359,6 +478,48 @@ public function getEncodedCoordinates()
return "\4" . $this->QA[0]->toBytes(true) . $this->QA[1]->toBytes(true);
}
/**
* Convert point to public key
*
* For Weierstrass curves, if only the x coordinate is present (as is the case after doing a round of ECDH)
* then we'll guess at the y coordinate. There are only two possible y values and, atleast in-so-far as
* multiplication is concerned, neither value affects the resultant x value
*
* If $toPublicKey is set to false then a string will be returned - a kind of public key precursor
*
* @param string $curveName
* @param string $secret
* @param bool $toPublicKey optional
* @return PublicKey|string
*/
public static function convertPointToPublicKey($curveName, $secret, $toPublicKey = true)
{
$curveName = self::getCurveCase($curveName);
$curve = '\phpseclib3\Crypt\EC\Curves\\' . $curveName;
if (!class_exists($curve)) {
throw new UnsupportedCurveException('Named Curve of ' . $curveName . ' is not supported');
}
$curve = new $curve();
if (!$curve instanceof TwistedEdwardsCurve) {
if ($curve instanceof MontgomeryCurve) {
$secret = strrev($secret);
} elseif ($curve->getLengthInBytes() == strlen($secret)) {
$secret = "\3$secret";
}
if (!$toPublicKey) {
return $secret;
}
$secret = "\0$secret";
} elseif (!$toPublicKey) {
return $secret;
}
$QA = PKCS8::extractPoint($secret, $curve);
$key = PKCS8::savePublicKey($curve, $QA);
return EC::loadFormat('PKCS8', $key);
}
/**
* Returns the parameters
*
@@ -463,18 +624,4 @@ public function withHash($hash)
return parent::withHash($hash);
}
/**
* __toString() magic method
*
* @return string
*/
public function __toString()
{
if ($this->curve instanceof MontgomeryCurve) {
return '';
}
return parent::__toString();
}
}

View File

@@ -18,6 +18,8 @@
class Curve25519 extends Montgomery
{
const SIZE = 32;
public function __construct()
{
// 2^255 - 19
@@ -47,10 +49,12 @@ public function __construct()
*/
public function multiplyPoint(array $p, BigInteger $d)
{
//$r = strrev(sodium_crypto_scalarmult($d->toBytes(), strrev($p[0]->toBytes())));
$d = $d->toBytes();
$d = str_pad($d, 32, "\0", STR_PAD_LEFT);
//$r = strrev(sodium_crypto_scalarmult($d, strrev($p[0]->toBytes())));
//return [$this->factory->newInteger(new BigInteger($r, 256))];
$d = $d->toBytes();
$d &= "\xF8" . str_repeat("\xFF", 30) . "\x7F";
$d = strrev($d);
$d |= "\x40";

View File

@@ -18,6 +18,8 @@
class Curve448 extends Montgomery
{
const SIZE = 56;
public function __construct()
{
// 2^448 - 2^224 - 1
@@ -58,10 +60,12 @@ public function __construct()
*/
public function multiplyPoint(array $p, BigInteger $d)
{
//$r = strrev(sodium_crypto_scalarmult($d->toBytes(), strrev($p[0]->toBytes())));
$d = $d->toBytes();
$d = str_pad($d, 56, "\0", STR_PAD_LEFT);
//$r = strrev(sodium_crypto_scalarmult($d, strrev($p[0]->toBytes())));
//return [$this->factory->newInteger(new BigInteger($r, 256))];
$d = $d->toBytes();
$d[0] = $d[0] & "\xFC";
$d = strrev($d);
$d |= "\x80";

View File

@@ -16,6 +16,7 @@
use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve;
use phpseclib3\Crypt\EC\BaseCurves\Binary as BinaryCurve;
use phpseclib3\Crypt\EC\BaseCurves\Montgomery;
use phpseclib3\Crypt\EC\BaseCurves\Prime as PrimeCurve;
use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use phpseclib3\Exception\UnsupportedCurveException;
@@ -274,6 +275,9 @@ protected static function loadCurveByParam(array $params)
*/
public static function extractPoint($str, BaseCurve $curve)
{
if ($curve instanceof Montgomery) {
return [new BigInteger($str, 256)];
}
if ($curve instanceof TwistedEdwardsCurve) {
// first step of point deciding as discussed at the following URL's:
// https://tools.ietf.org/html/rfc8032#section-5.1.3

View File

@@ -96,6 +96,6 @@ public static function savePrivateKey(BigInteger $privateKey, MontgomeryCurve $c
throw new UnsupportedFormatException('MontgomeryPrivate private keys do not support encryption');
}
return $privateKey->toBytes();
return str_pad($privateKey->toBytes(), $curve::SIZE, "\0", STR_PAD_RIGHT);
}
}

View File

@@ -111,6 +111,9 @@ private static function getAlias(BaseCurve $curve)
$reflect = new \ReflectionClass($curve);
$name = $reflect->getShortName();
if (!isset(self::$curveOIDs[$name])) {
throw new UnsupportedCurveException($name . ' is not a curve that the OpenSSH plugin supports');
}
$oid = self::$curveOIDs[$name];
$aliases = array_filter(self::$curveOIDs, function ($v) use ($oid) {
return $v == $oid;

View File

@@ -23,10 +23,13 @@
namespace phpseclib3\Crypt\EC\Formats\Keys;
use phpseclib3\Math\Common\FiniteField\Integer;
use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor;
use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve;
use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use phpseclib3\Crypt\EC\Curves\Curve25519;
use phpseclib3\Crypt\EC\Curves\Curve448;
use phpseclib3\Crypt\EC\Curves\Ed25519;
use phpseclib3\Crypt\EC\Curves\Ed448;
use phpseclib3\Exception\UnsupportedCurveException;
@@ -48,14 +51,14 @@ abstract class PKCS8 extends Progenitor
*
* @var array
*/
const OID_NAME = ['id-ecPublicKey', 'id-Ed25519', 'id-Ed448'];
const OID_NAME = ['id-ecPublicKey', 'id-Ed25519', 'id-Ed448', 'id-X25519', 'id-X448'];
/**
* OID Value
*
* @var string
*/
const OID_VALUE = ['1.2.840.10045.2.1', '1.3.101.112', '1.3.101.113'];
const OID_VALUE = ['1.2.840.10045.2.1', '1.3.101.112', '1.3.101.113', '1.3.101.110', '1.3.101.111'];
/**
* Break a public or private key down into its constituent components
@@ -81,6 +84,9 @@ public static function load($key, $password = '')
case 'id-Ed25519':
case 'id-Ed448':
return self::loadEdDSA($key);
case 'id-X25519':
case 'id-X448':
return self::loadECDH($key);
}
$decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element);
@@ -158,20 +164,64 @@ private static function loadEdDSA(array $key)
return $components;
}
private static function loadECDH(array $key)
{
$components = [];
if (isset($key['privateKey'])) {
$components['curve'] = $key['privateKeyAlgorithm']['algorithm'] == 'id-X25519' ? new Curve25519() : new Curve448();
$expected = chr(ASN1::TYPE_OCTET_STRING) . ASN1::encodeLength($components['curve']::SIZE);
$privateKey = (string) $key['privateKey'];
if (substr($privateKey, 0, 2) != $expected) {
throw new \RuntimeException(
'The first two bytes of the ' .
$key['privateKeyAlgorithm']['algorithm'] .
' private key field should be 0x' . bin2hex($expected)
);
}
$components['dA'] = new BigInteger(substr($privateKey, 2), 256);
}
if (isset($key['publicKey'])) {
if (!isset($components['curve'])) {
$components['curve'] = $key['publicKeyAlgorithm']['algorithm'] == 'id-X25519' ? new Curve25519() : new Curve448();
}
$components['QA'] = [$components['curve']->convertInteger(new BigInteger(strrev($key['publicKey']), 256))];
}
if (isset($key['privateKey']) && !isset($components['QA'])) {
if ($components['curve'] instanceof Curve25519 && function_exists('sodium_crypto_box_publickey_from_secretkey')) {
//$r = pack('H*', '0900000000000000000000000000000000000000000000000000000000000000');
//$QA = sodium_crypto_scalarmult($components['dA']->toBytes(), $r);
$QA = sodium_crypto_box_publickey_from_secretkey(str_pad($components['dA']->toBytes(), 32, chr(0), STR_PAD_LEFT));
$components['QA'] = [$components['curve']->convertInteger(new BigInteger(strrev($QA), 256))];
} else {
$components['QA'] = [$components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA'])[0]];
}
}
return $components;
}
/**
* Convert an EC public key to the appropriate format
*
* @param BaseCurve $curve
* @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
* @param Integer[] $publicKey
* @param array $options optional
* @return string
*/
public static function savePublicKey(BaseCurve $curve, array $publicKey, array $options = [])
{
self::initialize_static_variables();
if ($curve instanceof MontgomeryCurve) {
throw new UnsupportedCurveException('Montgomery Curves are not supported');
return self::wrapPublicKey(
str_pad(strrev($publicKey[0]->toBytes()), $curve::SIZE, "\0", STR_PAD_RIGHT),
null,
$curve instanceof Curve25519 ? 'id-X25519' : 'id-X448',
$options
);
}
if ($curve instanceof TwistedEdwardsCurve) {
@@ -206,7 +256,13 @@ public static function savePrivateKey(BigInteger $privateKey, BaseCurve $curve,
self::initialize_static_variables();
if ($curve instanceof MontgomeryCurve) {
throw new UnsupportedCurveException('Montgomery Curves are not supported');
return self::wrapPrivateKey(
chr(ASN1::TYPE_OCTET_STRING) . ASN1::encodeLength($curve::SIZE) . str_pad($privateKey->toBytes(), $curve::SIZE, "\0", STR_PAD_LEFT),
[],
null,
$password,
$curve instanceof Curve25519 ? 'id-X25519' : 'id-X448'
);
}
if ($curve instanceof TwistedEdwardsCurve) {

View File

@@ -21,6 +21,7 @@
use phpseclib3\Crypt\EC\Formats\Keys\PKCS1;
use phpseclib3\Crypt\EC\Formats\Signature\ASN1 as ASN1Signature;
use phpseclib3\Crypt\Hash;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Exception\UnsupportedOperationException;
use phpseclib3\Math\BigInteger;
@@ -59,18 +60,34 @@ final class PrivateKey extends EC implements Common\PrivateKey
*/
public function multiply($coordinates)
{
if ($this->curve instanceof MontgomeryCurve) {
if ($this->curve instanceof Curve25519 && self::$engines['libsodium']) {
return sodium_crypto_scalarmult($this->dA->toBytes(), $coordinates);
}
if (self::$forcedEngine === 'OpenSSL') {
throw new BadConfigurationException('Engine OpenSSL is not supported for the multiplication operation');
}
if (self::$forcedEngine === 'libsodium' && !$this->curve instanceof Curve25519) {
throw new BadConfigurationException('Engine libsodium is only supported for Curve25519');
}
if ($this->curve instanceof Curve25519 && self::$forcedEngine !== 'PHP') {
if (self::$forcedEngine === 'libsodium' && !function_exists('sodium_crypto_scalarmult')) {
throw new BadConfigurationException('Engine libsodium is forced but unsupported for Curve25519');
}
if (function_exists('sodium_crypto_scalarmult')) {
$dA = str_pad($this->dA->toBytes(), 32, "\0", STR_PAD_LEFT);
return sodium_crypto_scalarmult($dA, $coordinates);
}
}
if ($this->curve instanceof MontgomeryCurve) {
$point = [$this->curve->convertInteger(new BigInteger(strrev($coordinates), 256))];
$point = $this->curve->multiplyPoint($point, $this->dA);
return strrev($point[0]->toBytes(true));
}
if (!$this->curve instanceof TwistedEdwardsCurve) {
$coordinates = "\0$coordinates";
}
$point = PKCS1::extractPoint($coordinates, $this->curve);
$point = $this->curve->multiplyPoint($point, $this->dA);
if ($this->curve instanceof TwistedEdwardsCurve) {
@@ -104,11 +121,56 @@ public function sign($message)
return false;
}
if ($this->curve instanceof TwistedEdwardsCurve) {
if ($this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context)) {
if (self::$forcedEngine === 'libsodium' && !$this->curve instanceof Ed25519) {
throw new BadConfigurationException('Engine libsodium is only supported for Ed25519');
}
// at this point either self::$forcedEngine is NOT libsodium or the curve is Ed25519
if ($this->curve instanceof Ed25519 && self::$forcedEngine !== 'PHP' && self::$forcedEngine !== 'OpenSSL') {
if (self::$forcedEngine === 'libsodium') {
if (!function_exists('sodium_crypto_sign_detached')) {
throw new BadConfigurationException('Engine libsodium is forced but unsupported for Ed25519 / Ed448');
}
if (isset($this->context)) {
throw new BadConfigurationException('Engine libsodium is forced but unsupported for Ed25519ctx (context)');
}
}
if (function_exists('sodium_crypto_sign_detached') && !isset($this->context)) {
$result = sodium_crypto_sign_detached($message, $this->withPassword()->toString('libsodium'));
return $shortFormat == 'SSH2' ? Strings::packSSH2('ss', 'ssh-' . strtolower($this->getCurve()), $result) : $result;
}
}
// at this point self::$forcedEngine CAN'T be libsodium so we won't check for it henceforth
if ($this->curve instanceof TwistedEdwardsCurve) {
if (self::$forcedEngine !== 'PHP') {
$keyTypeConstant = $this->curve instanceof Ed25519 ? 'OPENSSL_KEYTYPE_ED25519' : 'OPENSSL_KEYTYPE_ED448';
if (self::$forcedEngine === 'OpenSSL') {
if (!defined($keyTypeConstant)) {
throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for Ed25519 / Ed448');
}
// OpenSSL supports Ed25519/Ed448 but not Ed25519ctx (context), so skip if context is set
if (isset($this->context)) {
throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for Ed25519 / Ed448 curves with context\'s');
}
}
if (defined($keyTypeConstant) && !isset($this->context)) {
$result = '';
// algorithm 0 is used because EdDSA has a built-in hash
openssl_sign($message, $result, $this->withPassword()->toString('PKCS8'), 0);
if ($result) {
$signature = $shortFormat == 'SSH2'
? Strings::packSSH2('ss', 'ssh-' . strtolower($this->getCurve()), $result)
: $result;
return $signature;
}
if (self::$forcedEngine === 'OpenSSL') {
throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string());
}
}
}
// contexts (Ed25519ctx) are supported but prehashing (Ed25519ph) is not.
// quoting https://tools.ietf.org/html/rfc8032#section-8.5 ,
@@ -143,26 +205,37 @@ public function sign($message)
return $shortFormat == 'SSH2' ? Strings::packSSH2('ss', 'ssh-' . strtolower($this->getCurve()), $R . $S) : $R . $S;
}
if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
$signature = '';
// altho PHP's OpenSSL bindings only supported EC key creation in PHP 7.1 they've long
// supported signing / verification
// we use specified curves to avoid issues with OpenSSL possibly not supporting a given named curve;
// doing this may mean some curve-specific optimizations can't be used but idk if OpenSSL even
// has curve-specific optimizations
$result = openssl_sign($message, $signature, $this->withPassword()->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash());
if (self::$forcedEngine === 'OpenSSL' && !function_exists('openssl_get_md_methods')) {
throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for ECDSA');
}
if ($result) {
if ($shortFormat == 'ASN1') {
return $signature;
// at this point $forcedEngine is either PHP or null. either that OR openssl_get_md_methods() exists
if (self::$forcedEngine !== 'PHP') {
if (in_array($this->hash->getHash(), openssl_get_md_methods())) {
$signature = '';
// altho PHP's OpenSSL bindings only supported EC key creation in PHP 7.1 they've long
// supported signing / verification
// we use specified curves to avoid issues with OpenSSL possibly not supporting a given named curve;
// doing this may mean some curve-specific optimizations can't be used but idk if OpenSSL even
// has curve-specific optimizations
$result = openssl_sign($message, $signature, $this->withPassword()->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash());
if ($result) {
if ($shortFormat == 'ASN1') {
return $signature;
}
$loaded = ASN1Signature::load($signature);
$r = $loaded['r'];
$s = $loaded['s'];
return $this->formatSignature($r, $s);
} elseif (self::$forcedEngine === 'OpenSSL') {
throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string());
}
$loaded = ASN1Signature::load($signature);
$r = $loaded['r'];
$s = $loaded['s'];
return $this->formatSignature($r, $s);
} elseif (self::$forcedEngine === 'OpenSSL') {
throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for ECDSA / ' . $this->hash->getHash());
}
}

View File

@@ -20,6 +20,7 @@
use phpseclib3\Crypt\EC\Formats\Keys\PKCS1;
use phpseclib3\Crypt\EC\Formats\Signature\ASN1 as ASN1Signature;
use phpseclib3\Crypt\Hash;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Exception\UnsupportedOperationException;
use phpseclib3\Math\BigInteger;
@@ -52,17 +53,62 @@ public function verify($message, $signature)
return false;
}
$order = $this->curve->getOrder();
if (self::$forcedEngine === 'libsodium' && !$this->curve instanceof Ed25519) {
throw new BadConfigurationException('Engine libsodium is only supported for Ed25519');
}
// at this point either self::$forcedEngine is NOT libsodium or the curve is Ed25519
if ($this->curve instanceof Ed25519 && self::$forcedEngine !== 'PHP' && self::$forcedEngine !== 'OpenSSL') {
if (self::$forcedEngine === 'libsodium') {
if (!function_exists('sodium_crypto_sign_verify_detached')) {
throw new BadConfigurationException('Engine libsodium is forced but unsupported for Ed25519 / Ed448');
}
if (isset($this->context)) {
throw new BadConfigurationException('Engine libsodium is forced but unsupported for Ed25519ctx (context)');
}
}
if (function_exists('sodium_crypto_sign_verify_detached') && !isset($this->context)) {
if ($shortFormat == 'SSH2') {
list(, $signature) = Strings::unpackSSH2('ss', $signature);
}
return sodium_crypto_sign_verify_detached($signature, $message, $this->toString('libsodium'));
}
}
// at this point self::$forcedEngine CAN'T be libsodium so we won't check for it henceforth
if ($this->curve instanceof TwistedEdwardsCurve) {
if ($shortFormat == 'SSH2') {
list(, $signature) = Strings::unpackSSH2('ss', $signature);
}
if ($this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context)) {
return sodium_crypto_sign_verify_detached($signature, $message, $this->toString('libsodium'));
if (self::$forcedEngine !== 'PHP') {
$keyTypeConstant = $this->curve instanceof Ed25519 ? 'OPENSSL_KEYTYPE_ED25519' : 'OPENSSL_KEYTYPE_ED448';
if (self::$forcedEngine === 'OpenSSL') {
if (!defined($keyTypeConstant)) {
throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for Ed25519 / Ed448');
}
// OpenSSL supports Ed25519/Ed448 but not Ed25519ctx (context), so skip if context is set
if (isset($this->context)) {
throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for Ed25519 / Ed448 curves with context\'s');
}
}
if (defined($keyTypeConstant) && !isset($this->context)) {
// algorithm 0 is used because EdDSA has a built-in hash
$result = openssl_verify($message, $signature, $this->toString('PKCS8'), 0) === 1;
if ($result !== -1 && $result !== false) {
return (bool) $result;
}
if (self::$forcedEngine === 'OpenSSL') {
throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string());
}
}
}
$order = $this->curve->getOrder();
$curve = $this->curve;
if (strlen($signature) != 2 * $curve::SIZE) {
return false;
@@ -118,16 +164,31 @@ public function verify($message, $signature)
$r = $params['r'];
$s = $params['s'];
if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
$sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature;
if (self::$forcedEngine === 'OpenSSL' && !function_exists('openssl_get_md_methods')) {
throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for ECDSA');
}
$result = openssl_verify($message, $sig, $this->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash());
// at this point $forcedEngine is either PHP or null. either that OR openssl_get_md_methods() exists
if ($result != -1) {
return (bool) $result;
if (self::$forcedEngine !== 'PHP') {
if (in_array($this->hash->getHash(), openssl_get_md_methods())) {
$sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature;
$result = openssl_verify($message, $sig, $this->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash());
if ($result !== -1 && $result !== false) {
return (bool) $result;
}
if (self::$forcedEngine === 'OpenSSL') {
throw new BadConfigurationException('Engine OpenSSL is forced but was unable to verify signature because of ' . openssl_error_string());
}
} elseif (self::$forcedEngine === 'OpenSSL') {
throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for ECDSA / ' . $this->hash->getHash());
}
}
$order = $this->curve->getOrder();
$n_1 = $order->subtract(self::$one);
if (!$r->between(self::$one, $n_1) || !$s->between(self::$one, $n_1)) {
return false;

View File

@@ -295,7 +295,7 @@ public function getHash()
public function setHash($hash)
{
$oldHash = $this->hashParam;
$this->hashParam = $hash = strtolower($hash);
$this->hashParam = $hash = strtolower(str_replace('/', '-', $hash));
switch ($hash) {
case 'umac-32':
case 'umac-64':
@@ -323,8 +323,8 @@ public function setHash($hash)
case 'sha256-96':
case 'sha384-96':
case 'sha512-96':
case 'sha512/224-96':
case 'sha512/256-96':
case 'sha512-224-96':
case 'sha512-256-96':
$hash = substr($hash, 0, -3);
$this->length = 12; // 96 / 8 = 12
break;
@@ -336,7 +336,7 @@ public function setHash($hash)
$this->length = 20;
break;
case 'sha224':
case 'sha512/224':
case 'sha512-224':
case 'sha3-224':
$this->length = 28;
break;
@@ -344,7 +344,7 @@ public function setHash($hash)
$this->paddingType = self::PADDING_KECCAK;
// fall-through
case 'sha256':
case 'sha512/256':
case 'sha512-256':
case 'sha3-256':
$this->length = 32;
break;
@@ -424,12 +424,12 @@ public function setHash($hash)
}
}
if ($hash == 'sha512/224' || $hash == 'sha512/256') {
if ($hash == 'sha512-224' || $hash == 'sha512-256') {
// PHP 7.1.0 introduced sha512/224 and sha512/256 support:
// http://php.net/ChangeLog-7.php#7.1.0
if (version_compare(PHP_VERSION, '7.1.0') < 0) {
// from http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#page=24
$initial = $hash == 'sha512/256' ?
$initial = $hash == 'sha512-256' ?
[
'22312194FC2BF72C', '9F555FA3C84C64C2', '2393B86B6F53B151', '963877195940EABD',
'96283EE2A88EFFE3', 'BE5E1E2553863992', '2B0199FC2C85B8AA', '0EB72DDC81C52CA2'
@@ -459,6 +459,15 @@ public function setHash($hash)
$this->opad = str_repeat(chr(0x5C), $b);
}
// PHP's built in hash function does sha3-256 but sha512/256 so we'll update those accordingly
switch ($hash) {
case 'sha512-224':
$hash = 'sha512/224';
break;
case 'sha512-256':
$hash = 'sha512/256';
}
$this->algo = $hash;
$this->computeKey();

View File

@@ -57,6 +57,7 @@
use phpseclib3\Crypt\RSA\Formats\Keys\PSS;
use phpseclib3\Crypt\RSA\PrivateKey;
use phpseclib3\Crypt\RSA\PublicKey;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Exception\InconsistentSetupException;
use phpseclib3\Exception\UnsupportedAlgorithmException;
use phpseclib3\Math\BigInteger;
@@ -227,14 +228,6 @@ abstract class RSA extends AsymmetricKey
*/
protected static $enableBlinding = true;
/**
* OpenSSL configuration file name.
*
* @see self::createKey()
* @var ?string
*/
protected static $configFile;
/**
* Smallest Prime
*
@@ -256,6 +249,14 @@ abstract class RSA extends AsymmetricKey
*/
protected $publicExponent;
/**
* Forced Engine
*
* @var ?string
* @see parent::forceEngine()
*/
protected static $forcedEngine = null;
/**
* Sets the public exponent for key generation
*
@@ -280,18 +281,6 @@ public static function setSmallestPrime($val)
self::$smallestPrime = $val;
}
/**
* Sets the OpenSSL config file path
*
* Set to the empty string to use the default config file
*
* @param string $val
*/
public static function setOpenSSLConfigPath($val)
{
self::$configFile = $val;
}
/**
* Create a private key
*
@@ -309,6 +298,10 @@ public static function createKey($bits = 2048)
throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')');
}
if (self::$forcedEngine == 'libsodium' || (self::$forcedEngine == 'OpenSSL' && !function_exists('openssl_pkey_new'))) {
throw new BadConfigurationException('Engine ' . self::$forcedEngine . ' is forced but unsupported for RSA');
}
$regSize = $bits >> 1; // divide by two to see how many bits P and Q would be
if ($regSize > self::$smallestPrime) {
$num_primes = floor($bits / self::$smallestPrime);
@@ -318,25 +311,27 @@ public static function createKey($bits = 2048)
}
if ($num_primes == 2 && $bits >= 384 && self::$defaultExponent == 65537) {
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
// OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
if (self::$engines['OpenSSL']) {
// at this point the only two supported values for self::$forcedEngine are OpenSSL, PHP and null
// if it's either OpenSSL or null we'll use OpenSSL (if it's available)
if (self::$forcedEngine !== 'PHP' && function_exists('openssl_pkey_new')) {
$config = [];
if (self::$configFile) {
$config['config'] = self::$configFile;
}
// OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
$rsa = openssl_pkey_new(['private_key_bits' => $bits] + $config);
openssl_pkey_export($rsa, $privatekeystr, null, $config);
if (!$rsa || !openssl_pkey_export($rsa, $privatekeystr, null, $config)) {
if (isset(self::$forcedEngine)) {
throw new BadConfigurationException('Engine OpenSSL is forced but produced an error - ' . openssl_error_string());
}
} else {
// clear the buffer of error strings stemming from a minimalistic openssl.cnf
// https://github.com/php/php-src/issues/11054 talks about other errors this'll pick up
while (openssl_error_string() !== false) {
}
// clear the buffer of error strings stemming from a minimalistic openssl.cnf
// https://github.com/php/php-src/issues/11054 talks about other errors this'll pick up
while (openssl_error_string() !== false) {
return RSA::load($privatekeystr);
}
return RSA::load($privatekeystr);
}
}
@@ -478,18 +473,6 @@ protected static function onLoad(array $components)
return $key;
}
/**
* Initialize static variables
*/
protected static function initialize_static_variables()
{
if (!isset(self::$configFile)) {
self::$configFile = dirname(__FILE__) . '/../openssl.cnf';
}
parent::initialize_static_variables();
}
/**
* Constructor
*
@@ -581,6 +564,22 @@ protected function emsa_pkcs1_v1_5_encode($m, $emLen)
break;
case 'sha512/256':
$t = "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x06\x05\x00\x04\x20";
break;
// the following 3x algorithms are not specified in PKCS1 v2.2, however, some standards none-the-less do use them:
// https://sk-eid.github.io/smart-id-documentation/rp-api/changes.html#_security_enhancements
// the OIDs are from this URL:
// https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration#Hash
case 'sha3/224':
$t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x07\x05\x00\x04\x1c";
break;
case 'sha3/256':
$t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x08\x05\x00\x04\x20";
break;
case 'sha3/384':
$t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x09\x05\x00\x04\x30";
break;
case 'sha3/512':
$t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0A\x05\x00\x04\x40";
}
$t .= $h;
$tLen = strlen($t);
@@ -638,6 +637,22 @@ protected function emsa_pkcs1_v1_5_encode_without_null($m, $emLen)
case 'sha512/256':
$t = "\x30\x2f\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x06\x04\x20";
break;
// the following 3x algorithms are not specified in PKCS1 v2.2, however, some standards none-the-less do use them:
// https://sk-eid.github.io/smart-id-documentation/rp-api/changes.html#_security_enhancements
// the OIDs are from this URL:
// https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration#Hash
case 'sha3/224':
$t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x07\x04\x1c";
break;
case 'sha3/256':
$t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x08\x04\x20";
break;
case 'sha3/384':
$t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x09\x04\x30";
break;
case 'sha3/512':
$t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0A\x04\x40";
break;
default:
throw new UnsupportedAlgorithmException('md2 and md5 require NULLs');
}
@@ -713,11 +728,15 @@ public function withHash($hash)
case 'sha224':
case 'sha512/224':
case 'sha512/256':
case 'sha3/224':
case 'sha3/256':
case 'sha3/384':
case 'sha3/512':
$new->hash = new Hash($hash);
break;
default:
throw new UnsupportedAlgorithmException(
'The only supported hash algorithms are: md2, md5, sha1, sha256, sha384, sha512, sha224, sha512/224, sha512/256'
"The only supported hash algorithms are: md2, md5, sha1, sha256, sha384, sha512, sha224, sha512/224, sha512/256 - $hash provided"
);
}
$new->hLen = $new->hash->getLengthInBytes();
@@ -748,11 +767,15 @@ public function withMGFHash($hash)
case 'sha224':
case 'sha512/224':
case 'sha512/256':
case 'sha3/224':
case 'sha3/256':
case 'sha3/384':
case 'sha3/512':
$new->mgfHash = new Hash($hash);
break;
default:
throw new UnsupportedAlgorithmException(
'The only supported hash algorithms are: md2, md5, sha1, sha256, sha384, sha512, sha224, sha512/224, sha512/256'
"The only supported hash algorithms are: md2, md5, sha1, sha256, sha384, sha512, sha224, sha512/224, sha512/256 - $hash provided"
);
}
$new->mgfHLen = $new->mgfHash->getLengthInBytes();
@@ -891,28 +914,6 @@ public function getPadding()
return $this->signaturePadding | $this->encryptionPadding;
}
/**
* Returns the current engine being used
*
* OpenSSL is only used in this class (and it's subclasses) for key generation
* Even then it depends on the parameters you're using. It's not used for
* multi-prime RSA nor is it used if the key length is outside of the range
* supported by OpenSSL
*
* @see self::useInternalEngine()
* @see self::useBestEngine()
* @return string
*/
public function getEngine()
{
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
return self::$engines['OpenSSL'] && self::$defaultExponent == 65537 ?
'OpenSSL' :
'PHP';
}
/**
* Enable RSA Blinding
*
@@ -930,4 +931,140 @@ public static function disableBlinding()
{
static::$enableBlinding = false;
}
/**
* Handles OpenSSL encryption / decryption / signature creation / verification
*
* @param string $func
* @param string $message
* @param ?string $signature
* @return bool|string|null
*/
protected function handleOpenSSL($func, $message, $signature = null)
{
switch ($func) {
case 'openssl_verify':
case 'openssl_sign':
$paddingType = 'signaturePadding';
break;
case 'openssl_public_encrypt':
case 'openssl_private_decrypt':
$paddingType = 'encryptionPadding';
}
if (self::$forcedEngine === 'libsodium') {
throw new BadConfigurationException('Engine libsodium is not supported for RSA');
}
if ((isset(self::$forcedEngine) && self::$forcedEngine !== 'PHP') && $this->$paddingType === self::SIGNATURE_RELAXED_PKCS1) {
throw new BadConfigurationException('Only the PHP engine can be used with relaxed PKCS1 padding');
}
if (self::$forcedEngine !== 'PHP') {
if (self::$forcedEngine === 'OpenSSL' && !function_exists($func)) {
throw new BadConfigurationException('Engine OpenSSL is forced but unavailable for RSA');
}
if ($this->$paddingType === self::SIGNATURE_PSS) {
switch (true) {
case !defined('OPENSSL_PKCS1_PSS_PADDING'):
$error = 'Engine OpenSSL is forced but PSS encryption requires PHP >= 8.5.0';
break;
case $this->hash->getHash() !== $this->mgfHash->getHash():
$error = 'Engine OpenSSL is forced but can\'t be used because the Hash and MGF Hash do not match';
break;
case $this->getSaltLength() !== $this->hLen:
$error = 'Engine OpenSSL is forced but can\'t be used because the salt length doesn\'t match the hash length';
}
}
if ($this->$paddingType === self::ENCRYPTION_OAEP) {
switch (true) {
case $this->hash->getHash() !== $this->mgfHash->getHash():
$error = 'Engine OpenSSL is forced but can\'t be used because the Hash and MGF Hash do not match';
break;
case $this->hash->getHash() !== 'sha1' && PHP_VERSION_ID < 80500:
$error = 'Engine OpenSSL is forced but non-sha1 hashes are only supported on PHP 8.5.0+';
break;
case strlen($this->label):
$error = 'Engine OpenSSL is forced but can\'t be used because the label is not the empty string';
}
}
if (isset($error)) {
if (self::$forcedEngine === 'OpenSSL') {
throw new BadConfigurationException($error);
}
} elseif ($paddingType === 'signaturePadding') {
switch (true) {
case $this->signaturePadding === self::SIGNATURE_PSS && defined('OPENSSL_PKCS1_PSS_PADDING'):
case $this->signaturePadding !== self::SIGNATURE_PSS && function_exists($func):
$key = $this instanceof PrivateKey ?
$this->withPassword()->toString('PKCS8') :
$this->toString('PKCS8');
if ($func === 'openssl_sign' && strpos($key, 'PUBLIC') !== false) {
if (self::$forcedEngine === 'OpenSSL') {
throw new BadConfigurationException('Engine OpenSSL is forced but cannot be used because the private key does not have the prime components within it');
}
break;
}
$hash = $this->hash->getHash();
// on github actions, php 7.0 and 7.1 on windows emit the following warning:
// openssl_sign(): supplied key param cannot be coerced into a private key
set_error_handler(function ($errno, $errstr) {
throw new BadConfigurationException("Engine OpenSSL is forced but got error: $errstr");
});
try {
$result = $this->signaturePadding === self::SIGNATURE_PSS ?
$func($message, $signature, $key, $hash, OPENSSL_PKCS1_PSS_PADDING) :
$func($message, $signature, $key, $hash);
} catch (BadConfigurationException $e) {
if (self::$forcedEngine === 'OpenSSL') {
throw $e;
}
$result = false;
} finally {
restore_error_handler();
}
if ($func === 'openssl_verify' && $result !== -1 && $result !== false) {
return (bool) $result;
}
if ($result) {
return $signature;
}
if (self::$forcedEngine === 'OpenSSL') {
throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string());
}
}
} else {
if ($this->encryptionPadding !== self::ENCRYPTION_OAEP || PHP_VERSION_ID >= 80500) {
$key = $this->toString('PKCS8');
if ($func === 'openssl_private_decrypt' && strpos($key, 'PUBLIC') !== false) {
if ($this->encryptionPadding === self::ENCRYPTION_OAEP) {
if (self::$forcedEngine === 'OpenSSL') {
throw new BadConfigurationException('Engine OpenSSL is forced but cannot be used because openssl_public_decrypt() doesn\'t have a hash parameter like openssl_private_decrypt() does');
}
return null;
}
$func = 'openssl_public_decrypt';
}
$hash = $this->hash->getHash();
$output = '';
switch ($this->encryptionPadding) {
case self::ENCRYPTION_NONE:
case self::ENCRYPTION_PKCS1:
$padding = $this->encryptionPadding === self::ENCRYPTION_NONE ? OPENSSL_NO_PADDING : OPENSSL_PKCS1_PADDING;
$result = $func($message, $output, $key, $padding);
break;
//case self::ENCRYPTION_OAEP:
default:
$result = $func($message, $output, $key, OPENSSL_PKCS1_OAEP_PADDING, $hash);
}
if ($result) {
return $output;
}
}
}
return null;
}
}
}

View File

@@ -216,7 +216,7 @@ private function emsa_pss_encode($m, $emBits)
$db = $ps . chr(1) . $salt;
$dbMask = $this->mgf1($h, $emLen - $this->hLen - 1); // ie. stlren($db)
$maskedDB = $db ^ $dbMask;
$maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
$maskedDB[0] = ~chr(256 - (1 << ($emBits & 7))) & $maskedDB[0];
$em = $maskedDB . $h . chr(0xBC);
return $em;
@@ -288,6 +288,11 @@ private function rsassa_pkcs1_v1_5_sign($m)
*/
public function sign($message)
{
$result = $this->handleOpenSSL('openssl_sign', $message);
if ($result !== null) {
return $result;
}
switch ($this->signaturePadding) {
case self::SIGNATURE_PKCS1:
case self::SIGNATURE_RELAXED_PKCS1:
@@ -434,6 +439,11 @@ private function raw_encrypt($m)
*/
public function decrypt($ciphertext)
{
$result = $this->handleOpenSSL('openssl_private_decrypt', $ciphertext);
if ($result !== null) {
return $result;
}
switch ($this->encryptionPadding) {
case self::ENCRYPTION_NONE:
return $this->raw_encrypt($ciphertext);

View File

@@ -17,6 +17,7 @@
use phpseclib3\Crypt\Random;
use phpseclib3\Crypt\RSA;
use phpseclib3\Crypt\RSA\Formats\Keys\PSS;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Exception\UnsupportedAlgorithmException;
use phpseclib3\Exception\UnsupportedFormatException;
use phpseclib3\File\ASN1;
@@ -116,7 +117,7 @@ private function rsassa_pkcs1_v1_5_verify($m, $s)
}
// Compare
return $r1 || $r2;
return boolval($r1 | $r2);
}
/**
@@ -241,13 +242,13 @@ private function emsa_pss_verify($m, $em, $emBits)
$maskedDB = substr($em, 0, -$this->hLen - 1);
$h = substr($em, -$this->hLen - 1, $this->hLen);
$temp = chr(0xFF << ($emBits & 7));
$temp = chr(256 - (1 << ($emBits & 7)));
if ((~$maskedDB[0] & $temp) != $temp) {
return false;
}
$dbMask = $this->mgf1($h, $emLen - $this->hLen - 1);
$db = $maskedDB ^ $dbMask;
$db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
$db[0] = ~chr(256 - (1 << ($emBits & 7))) & $db[0];
$temp = $emLen - $this->hLen - $sLen - 2;
if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
return false;
@@ -301,6 +302,49 @@ private function rsassa_pss_verify($m, $s)
*/
public function verify($message, $signature)
{
/*
https://datatracker.ietf.org/doc/html/rfc4055#page-6 says the following:
There are two possible encodings for the AlgorithmIdentifier
parameters field associated with these object identifiers. The two
alternatives arise from the loss of the OPTIONAL associated with the
algorithm identifier parameters when the 1988 syntax for
AlgorithmIdentifier was translated into the 1997 syntax. Later the
OPTIONAL was recovered via a defect report, but by then many people
thought that algorithm parameters were mandatory. Because of this
history some implementations encode parameters as a NULL element
while others omit them entirely. The correct encoding is to omit the
parameters field; however, when RSASSA-PSS and RSAES-OAEP were
defined, it was done using the NULL parameters rather than absent
parameters.
All implementations MUST accept both NULL and absent parameters as
legal and equivalent encodings.
OpenSSL does NOT accept both - it REQUIRES NULL be present. phpseclib, however,
DOES accept both. at first, it didn't. at first, not knowing why some small number
of PKCS1 signatures ommitted NULL, i added the SIGNATURE_RELAXED_PKCS1 mode on
2015-08-26. https://phpseclib.com/docs/rsa#rsasignature_relaxed_pkcs1 talks more
about that mode. later, on 2021-04-05, there was CVE-2021-30130. consequently,
the SIGNATURE_PKCS1 mode was updated to accept either NULL or non-NULL.
because phpseclib accepts PKCS1 signatures that OpenSSL doesn't, OpenSSL isn't
used for PKCS1. if the OpenSSL extension is installed then it'll be used to perform
unpadded RSA (ie. modular exponentation), however, the actual PKCS1 construction
takes place in PHP code vs OpenSSL.
see https://security.stackexchange.com/questions/110330/encoding-of-optional-null-in-der
for an additional reference
*/
if ($this->signaturePadding === self::SIGNATURE_PKCS1 && isset(self::$forcedEngine) && self::$forcedEngine !== 'PHP') {
throw new BadConfigurationException('Engine OpenSSL is forced but unavailable for RSA PKCS1 signature verification');
}
$result = $this->handleOpenSSL('openssl_verify', $message, $signature);
if ($result !== null) {
return $result;
}
switch ($this->signaturePadding) {
case self::SIGNATURE_RELAXED_PKCS1:
return $this->rsassa_pkcs1_v1_5_relaxed_verify($message, $signature);
@@ -450,6 +494,11 @@ private function raw_encrypt($m)
*/
public function encrypt($plaintext)
{
$result = $this->handleOpenSSL('openssl_public_encrypt', $plaintext);
if ($result !== null) {
return $result;
}
switch ($this->encryptionPadding) {
case self::ENCRYPTION_NONE:
return $this->raw_encrypt($plaintext);

View File

@@ -378,7 +378,7 @@ protected function encryptBlock($in)
$k = $c[2];
$l = $c[3];
while ($i < $Nb) {
$temp[$i] = ($state[$i] & intval(0xFF000000)) ^
$temp[$i] = ($state[$i] & (PHP_INT_SIZE == 8 ? 0xFF000000 : -16777216)) ^
($state[$j] & 0x00FF0000) ^
($state[$k] & 0x0000FF00) ^
($state[$l] & 0x000000FF) ^
@@ -452,7 +452,7 @@ protected function decryptBlock($in)
$l = $Nb - $c[3];
while ($i < $Nb) {
$word = ($state[$i] & intval(0xFF000000)) |
$word = ($state[$i] & (PHP_INT_SIZE == 8 ? 0xFF000000 : -16777216)) |
($state[$j] & 0x00FF0000) |
($state[$k] & 0x0000FF00) |
($state[$l] & 0x000000FF);
@@ -528,7 +528,7 @@ protected function setupKey()
0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
];
$rcon = array_map('intval', $rcon);
$rcon = array_map([self::class, 'safe_intval'], $rcon);
}
if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_length === $this->kl['key_length'] && $this->block_size === $this->kl['block_size']) {
@@ -568,7 +568,9 @@ protected function setupKey()
// on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
// 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
// with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
$temp = (($temp << 8) & intval(0xFFFFFF00)) | (($temp >> 24) & 0x000000FF); // rotWord
$temp = PHP_INT_SIZE == 8 ? // rotWord
(($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF) :
($temp << 8) | (($temp >> 24) & 0x000000FF);
$temp = $this->subWord($temp) ^ $rcon[$i / $this->Nk];
} elseif ($this->Nk > 6 && $i % $this->Nk == 4) {
$temp = $this->subWord($temp);
@@ -659,7 +661,7 @@ protected function &getTables()
// according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
// precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
// those are the names we'll use.
$t3 = array_map('intval', [
$t3 = array_map([self::class, 'safe_intval'], [
// with array_map('intval', ...) we ensure we have only int's and not
// some slower floats converted by php automatically on high values
0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
@@ -697,9 +699,9 @@ protected function &getTables()
]);
foreach ($t3 as $t3i) {
$t0[] = (($t3i << 24) & intval(0xFF000000)) | (($t3i >> 8) & 0x00FFFFFF);
$t1[] = (($t3i << 16) & intval(0xFFFF0000)) | (($t3i >> 16) & 0x0000FFFF);
$t2[] = (($t3i << 8) & intval(0xFFFFFF00)) | (($t3i >> 24) & 0x000000FF);
$t0[] = (($t3i << 24) & self::safe_intval(0xFF000000)) | (($t3i >> 8) & 0x00FFFFFF);
$t1[] = (($t3i << 16) & self::safe_intval(0xFFFF0000)) | (($t3i >> 16) & 0x0000FFFF);
$t2[] = (($t3i << 8) & self::safe_intval(0xFFFFFF00)) | (($t3i >> 24) & 0x000000FF);
}
$tables = [
@@ -744,7 +746,7 @@ protected function &getInvTables()
{
static $tables;
if (empty($tables)) {
$dt3 = array_map('intval', [
$dt3 = array_map([self::class, 'safe_intval'], [
0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
@@ -779,11 +781,19 @@ protected function &getInvTables()
0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
]);
foreach ($dt3 as $dt3i) {
$dt0[] = (($dt3i << 24) & intval(0xFF000000)) | (($dt3i >> 8) & 0x00FFFFFF);
$dt1[] = (($dt3i << 16) & intval(0xFFFF0000)) | (($dt3i >> 16) & 0x0000FFFF);
$dt2[] = (($dt3i << 8) & intval(0xFFFFFF00)) | (($dt3i >> 24) & 0x000000FF);
};
if (PHP_INT_SIZE === 8) {
foreach ($dt3 as $dt3i) {
$dt0[] = (($dt3i << 24) & 0xFF000000) | (($dt3i >> 8) & 0x00FFFFFF);
$dt1[] = (($dt3i << 16) & 0xFFFF0000) | (($dt3i >> 16) & 0x0000FFFF);
$dt2[] = (($dt3i << 8) & 0xFFFFFF00) | (($dt3i >> 24) & 0x000000FF);
};
} else {
foreach ($dt3 as $dt3i) {
$dt0[] = ($dt3i << 24) | (($dt3i >> 8) & 0x00FFFFFF);
$dt1[] = ($dt3i << 16) | (($dt3i >> 16) & 0x0000FFFF);
$dt2[] = ($dt3i << 8) | (($dt3i >> 24) & 0x000000FF);
};
}
$tables = [
// The Precomputed inverse mixColumns tables dt0 - dt3
@@ -879,7 +889,7 @@ protected function setupInlineCrypt()
$encrypt_block .= '$in = pack("N*"' . "\n";
for ($i = 0; $i < $Nb; ++$i) {
$encrypt_block .= ',
($' . $e . $i . ' & ' . ((int)0xFF000000) . ') ^
($' . $e . $i . ' & ' . (PHP_INT_SIZE == 8 ? 0xFF000000 : -16777216) . ') ^
($' . $e . (($i + $c[1]) % $Nb) . ' & 0x00FF0000 ) ^
($' . $e . (($i + $c[2]) % $Nb) . ' & 0x0000FF00 ) ^
($' . $e . (($i + $c[3]) % $Nb) . ' & 0x000000FF ) ^
@@ -935,7 +945,7 @@ protected function setupInlineCrypt()
$decrypt_block .= '$in = pack("N*"' . "\n";
for ($i = 0; $i < $Nb; ++$i) {
$decrypt_block .= ',
($' . $e . $i . ' & ' . ((int)0xFF000000) . ') ^
($' . $e . $i . ' & ' . (PHP_INT_SIZE == 8 ? 0xFF000000 : -16777216) . ') ^
($' . $e . (($Nb + $i - $c[1]) % $Nb) . ' & 0x00FF0000 ) ^
($' . $e . (($Nb + $i - $c[2]) % $Nb) . ' & 0x0000FF00 ) ^
($' . $e . (($Nb + $i - $c[3]) % $Nb) . ' & 0x000000FF ) ^

View File

@@ -411,7 +411,7 @@ protected static function leftRotate($x, $n)
$r1 &= 0xFFFFFFFF;
$r2 = ($x & 0xFFFFFFFF) >> (32 - $n);
} else {
$x = (int) $x;
$x = self::safe_intval($x);
$r1 = $x << $n;
$r2 = $x >> (32 - $n);
$r2 &= (1 << $n) - 1;
@@ -482,7 +482,7 @@ protected static function salsa20($x)
}
for ($i = 1; $i <= 16; $i++) {
$x[$i] += $z[$i];
$x[$i] = self::safe_intval($x[$i] + $z[$i]);
}
return pack('V*', ...$x);

View File

@@ -373,12 +373,12 @@ public function __construct($mode)
protected static function initialize_static_variables()
{
if (is_float(self::$m3[0])) {
self::$m0 = array_map('intval', self::$m0);
self::$m1 = array_map('intval', self::$m1);
self::$m2 = array_map('intval', self::$m2);
self::$m3 = array_map('intval', self::$m3);
self::$q0 = array_map('intval', self::$q0);
self::$q1 = array_map('intval', self::$q1);
self::$m0 = array_map([self::class, 'safe_intval'], self::$m0);
self::$m1 = array_map([self::class, 'safe_intval'], self::$m1);
self::$m2 = array_map([self::class, 'safe_intval'], self::$m2);
self::$m3 = array_map([self::class, 'safe_intval'], self::$m3);
self::$q0 = array_map([self::class, 'safe_intval'], self::$q0);
self::$q1 = array_map([self::class, 'safe_intval'], self::$q1);
}
parent::initialize_static_variables();

View File

@@ -315,6 +315,7 @@ public function __construct()
'id-at-uniqueIdentifier' => '2.5.4.45',
'id-at-role' => '2.5.4.72',
'id-at-postalAddress' => '2.5.4.16',
'id-at-organizationIdentifier' => '2.5.4.97',
'jurisdictionOfIncorporationCountryName' => '1.3.6.1.4.1.311.60.2.1.3',
'jurisdictionOfIncorporationStateOrProvinceName' => '1.3.6.1.4.1.311.60.2.1.2',
'jurisdictionLocalityName' => '1.3.6.1.4.1.311.60.2.1.1',
@@ -1612,6 +1613,9 @@ private function translateDNProp($propName)
case 'organizationalunitname':
case 'ou':
return 'id-at-organizationalUnitName';
case 'id-at-organizationidentifier':
case 'organizationIdentifier':
return 'id-at-organizationIdentifier';
case 'id-at-pseudonym':
case 'pseudonym':
return 'id-at-pseudonym';

View File

@@ -549,8 +549,8 @@ protected static function base256_lshift(&$x, $shift)
$carry = 0;
for ($i = strlen($x) - 1; $i >= 0; --$i) {
$temp = ord($x[$i]) << $shift | $carry;
$x[$i] = chr($temp);
$temp = (ord($x[$i]) << $shift) | $carry;
$x[$i] = chr($temp & 0xFF);
$carry = $temp >> 8;
}
$carry = ($carry != 0) ? chr($carry) : '';

View File

@@ -3738,12 +3738,12 @@ private function get_binary_packet()
substr($packet->raw, 0, -$this->hmac_size);
if (($this->hmac_check->getHash() & "\xFF\xFF\xFF\xFF") == 'umac') {
$this->hmac_check->setNonce("\0\0\0\0" . pack('N', $this->get_seq_no));
if ($hmac != $this->hmac_check->hash($reconstructed)) {
if (!hash_equals($hmac, $this->hmac_check->hash($reconstructed))) {
$this->disconnect_helper(NET_SSH2_DISCONNECT_MAC_ERROR);
throw new ConnectionClosedException('Invalid UMAC');
}
} else {
if ($hmac != $this->hmac_check->hash(pack('Na*', $this->get_seq_no, $reconstructed))) {
if (!hash_equals($hmac, $this->hmac_check->hash(pack('Na*', $this->get_seq_no, $reconstructed)))) {
$this->disconnect_helper(NET_SSH2_DISCONNECT_MAC_ERROR);
throw new ConnectionClosedException('Invalid HMAC');
}

View File

@@ -2,5 +2,8 @@
HOME = .
RANDFILE = $ENV::HOME/.rnd
# without this line you'll get this error with openssl_pkey_new():
# Warning: openssl_pkey_new(): Private key length must be at least 384 bits, configured to 0
default_bits = 384
[ v3_ca ]