Skip to content

Commit

Permalink
Merge pull request #95 from paragonie/v1-11-0
Browse files Browse the repository at this point in the history
Missing features from polyfill, closes #92
  • Loading branch information
paragonie-scott authored Sep 11, 2019
2 parents 54af2c8 + e195cad commit ae99ad5
Show file tree
Hide file tree
Showing 18 changed files with 3,595 additions and 15 deletions.
297 changes: 296 additions & 1 deletion lib/php72compat.php

Large diffs are not rendered by default.

699 changes: 698 additions & 1 deletion src/Compat.php

Large diffs are not rendered by default.

43 changes: 37 additions & 6 deletions src/Core/BLAKE2b.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ protected static function xor64(SplFixedArray $x, SplFixedArray $y)
throw new SodiumException('y[1] is not an integer');
}
return self::new64(
(int) ($x[0] ^ $y[0]),
(int) ($x[1] ^ $y[1])
(int) (($x[0] ^ $y[0]) & 0xffffffff),
(int) (($x[1] ^ $y[1]) & 0xffffffff)
);
}

Expand Down Expand Up @@ -299,12 +299,13 @@ public static function pseudoConstructor()
*/
protected static function context()
{
$ctx = new SplFixedArray(5);
$ctx = new SplFixedArray(6);
$ctx[0] = new SplFixedArray(8); // h
$ctx[1] = new SplFixedArray(2); // t
$ctx[2] = new SplFixedArray(2); // f
$ctx[3] = new SplFixedArray(256); // buf
$ctx[4] = 0; // buflen
$ctx[5] = 0; // last_node (uint8_t)

for ($i = 8; $i--;) {
$ctx[0][$i] = self::$iv[$i];
Expand Down Expand Up @@ -550,6 +551,8 @@ public static function finish(SplFixedArray $ctx, SplFixedArray $out)
*
* @param SplFixedArray|null $key
* @param int $outlen
* @param SplFixedArray|null $salt
* @param SplFixedArray|null $personal
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
Expand All @@ -559,8 +562,12 @@ public static function finish(SplFixedArray $ctx, SplFixedArray $out)
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
*/
public static function init($key = null, $outlen = 64)
{
public static function init(
$key = null,
$outlen = 64,
$salt = null,
$personal = null
) {
self::pseudoConstructor();
$klen = 0;

Expand All @@ -578,6 +585,7 @@ public static function init($key = null, $outlen = 64)
$ctx = self::context();

$p = new SplFixedArray(64);
// Zero our param buffer...
for ($i = 64; --$i;) {
$p[$i] = 0;
}
Expand All @@ -587,10 +595,32 @@ public static function init($key = null, $outlen = 64)
$p[2] = 1; // fanout
$p[3] = 1; // depth

if ($salt instanceof SplFixedArray) {
// salt: [32] through [47]
for ($i = 0; $i < 16; ++$i) {
$p[32 + $i] = (int) $salt[$i];
}
}
if ($personal instanceof SplFixedArray) {
// personal: [48] through [63]
for ($i = 0; $i < 16; ++$i) {
$p[48 + $i] = (int) $personal[$i];
}
}

$ctx[0][0] = self::xor64(
$ctx[0][0],
self::load64($p, 0)
);
if ($salt instanceof SplFixedArray || $personal instanceof SplFixedArray) {
// We need to do what blake2b_init_param() does:
for ($i = 1; $i < 8; ++$i) {
$ctx[0][$i] = self::xor64(
$ctx[0][$i],
self::load64($p, $i << 3)
);
}
}

if ($klen > 0 && $key instanceof SplFixedArray) {
$block = new SplFixedArray(128);
Expand All @@ -601,6 +631,7 @@ public static function init($key = null, $outlen = 64)
$block[$i] = $key[$i];
}
self::update($ctx, $block, 128);
$ctx[4] = 128;
}

return $ctx;
Expand Down Expand Up @@ -693,7 +724,7 @@ public static function contextToString(SplFixedArray $ctx)
self::intToChr(($ctx4 >> 56) & 0xff)
));
# uint8_t last_node;
return $str . "\x00";
return $str . self::intToChr($ctx[5]) . str_repeat("\x00", 23);
}

/**
Expand Down
213 changes: 213 additions & 0 deletions src/Core/Base64/Common.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
<?php

/**
* Class ParagonIE_Sodium_Core_Base64
*
* Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*
* We have to copy/paste the contents into the variant files because PHP 5.2
* doesn't support late static binding, and we have no better workaround
* available that won't break PHP 7+. Therefore, we're forced to duplicate code.
*/
abstract class ParagonIE_Sodium_Core_Base64_Common
{
/**
* Encode into Base64
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
* @throws TypeError
*/
public static function encode($src)
{
return self::doEncode($src, true);
}

/**
* Encode into Base64, no = padding
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
* @throws TypeError
*/
public static function encodeUnpadded($src)
{
return self::doEncode($src, false);
}

/**
* @param string $src
* @param bool $pad Include = padding?
* @return string
* @throws TypeError
*/
protected static function doEncode($src, $pad = true)
{
$dest = '';
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
// Main loop (no padding):
for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 3));
$b0 = $chunk[1];
$b1 = $chunk[2];
$b2 = $chunk[3];

$dest .=
self::encode6Bits( $b0 >> 2 ) .
self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
self::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) .
self::encode6Bits( $b2 & 63);
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
$b0 = $chunk[1];
if ($i + 1 < $srcLen) {
$b1 = $chunk[2];
$dest .=
self::encode6Bits($b0 >> 2) .
self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
self::encode6Bits(($b1 << 2) & 63);
if ($pad) {
$dest .= '=';
}
} else {
$dest .=
self::encode6Bits( $b0 >> 2) .
self::encode6Bits(($b0 << 4) & 63);
if ($pad) {
$dest .= '==';
}
}
}
return $dest;
}

/**
* decode from base64 into binary
*
* Base64 character set "./[A-Z][a-z][0-9]"
*
* @param string $src
* @param bool $strictPadding
* @return string
* @throws RangeException
* @throws TypeError
* @psalm-suppress RedundantCondition
*/
public static function decode($src, $strictPadding = false)
{
// Remove padding
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
if ($srcLen === 0) {
return '';
}

if ($strictPadding) {
if (($srcLen & 3) === 0) {
if ($src[$srcLen - 1] === '=') {
$srcLen--;
if ($src[$srcLen - 1] === '=') {
$srcLen--;
}
}
}
if (($srcLen & 3) === 1) {
throw new RangeException(
'Incorrect padding'
);
}
if ($src[$srcLen - 1] === '=') {
throw new RangeException(
'Incorrect padding'
);
}
} else {
$src = rtrim($src, '=');
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
}

$err = 0;
$dest = '';
// Main loop (no padding):
for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 4));
$c0 = self::decode6Bits($chunk[1]);
$c1 = self::decode6Bits($chunk[2]);
$c2 = self::decode6Bits($chunk[3]);
$c3 = self::decode6Bits($chunk[4]);

$dest .= pack(
'CCC',
((($c0 << 2) | ($c1 >> 4)) & 0xff),
((($c1 << 4) | ($c2 >> 2)) & 0xff),
((($c2 << 6) | $c3 ) & 0xff)
);
$err |= ($c0 | $c1 | $c2 | $c3) >> 8;
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
$c0 = self::decode6Bits($chunk[1]);

if ($i + 2 < $srcLen) {
$c1 = self::decode6Bits($chunk[2]);
$c2 = self::decode6Bits($chunk[3]);
$dest .= pack(
'CC',
((($c0 << 2) | ($c1 >> 4)) & 0xff),
((($c1 << 4) | ($c2 >> 2)) & 0xff)
);
$err |= ($c0 | $c1 | $c2) >> 8;
} elseif ($i + 1 < $srcLen) {
$c1 = self::decode6Bits($chunk[2]);
$dest .= pack(
'C',
((($c0 << 2) | ($c1 >> 4)) & 0xff)
);
$err |= ($c0 | $c1) >> 8;
} elseif ($i < $srcLen && $strictPadding) {
$err |= 1;
}
}
/** @var bool $check */
$check = ($err === 0);
if (!$check) {
throw new RangeException(
'Base64::decode() only expects characters in the correct base64 alphabet'
);
}
return $dest;
}

/**
* Uses bitwise operators instead of table-lookups to turn 6-bit integers
* into 8-bit integers.
*
* Base64 character set:
* [A-Z] [a-z] [0-9] + /
* 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
*
* @param int $src
* @return int
*/
abstract protected static function decode6Bits($src);

/**
* Uses bitwise operators instead of table-lookups to turn 8-bit integers
* into 6-bit integers.
*
* @param int $src
* @return string
*/
abstract protected static function encode6Bits($src);
}
Loading

0 comments on commit ae99ad5

Please sign in to comment.