summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorScott <scott@paragonie.com>2016-03-12 17:39:28 -0500
committerScott <scott@paragonie.com>2016-03-12 17:39:28 -0500
commit6709366e81deae25c770e52211e04e2afc88d01c (patch)
tree709b5b168bf5a686d24a68b0c5ff7020a573cf9d
parent0ed01f67e5a3837f3e8b52c2072127d429b3459a (diff)
downloadconstant_time_encoding-0.3.0.zip
constant_time_encoding-0.3.0.tar.gz
constant_time_encoding-0.3.0.tar.bz2
Add Base32Hex, completing RFC 4648 coverage.v0.3.0
-rw-r--r--src/Base32.php122
-rw-r--r--src/Base32Hex.php46
-rw-r--r--src/Base64.php46
-rw-r--r--src/Base64DotSlash.php14
-rw-r--r--src/Base64DotSlashOrdered.php14
-rw-r--r--src/Encoding.php21
-rw-r--r--tests/EncodingTest.php48
7 files changed, 224 insertions, 87 deletions
diff --git a/src/Base32.php b/src/Base32.php
index 18a7e38..1a010e0 100644
--- a/src/Base32.php
+++ b/src/Base32.php
@@ -1,6 +1,12 @@
<?php
namespace ParagonIE\ConstantTime;
+/**
+ * Class Base32
+ * [A-Z][2-7]
+ *
+ * @package ParagonIE\ConstantTime
+ */
abstract class Base32
{
/**
@@ -47,14 +53,14 @@ abstract class Base32
$dest = '';
for ($i = 0; $i + 8 <= $srcLen; $i += 8) {
$chunk = \unpack('C*', Core::safeSubstr($src, $i, 8));
- $c0 = self::decode5Bits($chunk[1]);
- $c1 = self::decode5Bits($chunk[2]);
- $c2 = self::decode5Bits($chunk[3]);
- $c3 = self::decode5Bits($chunk[4]);
- $c4 = self::decode5Bits($chunk[5]);
- $c5 = self::decode5Bits($chunk[6]);
- $c6 = self::decode5Bits($chunk[7]);
- $c7 = self::decode5Bits($chunk[8]);
+ $c0 = static::decode5Bits($chunk[1]);
+ $c1 = static::decode5Bits($chunk[2]);
+ $c2 = static::decode5Bits($chunk[3]);
+ $c3 = static::decode5Bits($chunk[4]);
+ $c4 = static::decode5Bits($chunk[5]);
+ $c5 = static::decode5Bits($chunk[6]);
+ $c6 = static::decode5Bits($chunk[7]);
+ $c7 = static::decode5Bits($chunk[8]);
$dest .= \pack(
'CCCCC',
@@ -68,15 +74,15 @@ abstract class Base32
}
if ($i < $srcLen) {
$chunk = \unpack('C*', Core::safeSubstr($src, $i, $srcLen - $i));
- $c0 = self::decode5Bits($chunk[1]);
+ $c0 = static::decode5Bits($chunk[1]);
if ($i + 6 < $srcLen) {
- $c1 = self::decode5Bits($chunk[2]);
- $c2 = self::decode5Bits($chunk[3]);
- $c3 = self::decode5Bits($chunk[4]);
- $c4 = self::decode5Bits($chunk[5]);
- $c5 = self::decode5Bits($chunk[6]);
- $c6 = self::decode5Bits($chunk[7]);
+ $c1 = static::decode5Bits($chunk[2]);
+ $c2 = static::decode5Bits($chunk[3]);
+ $c3 = static::decode5Bits($chunk[4]);
+ $c4 = static::decode5Bits($chunk[5]);
+ $c5 = static::decode5Bits($chunk[6]);
+ $c6 = static::decode5Bits($chunk[7]);
$dest .= \pack(
'CCCC',
@@ -87,11 +93,11 @@ abstract class Base32
);
$err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6) >> 8;
} elseif ($i + 5 < $srcLen) {
- $c1 = self::decode5Bits($chunk[2]);
- $c2 = self::decode5Bits($chunk[3]);
- $c3 = self::decode5Bits($chunk[4]);
- $c4 = self::decode5Bits($chunk[5]);
- $c5 = self::decode5Bits($chunk[6]);
+ $c1 = static::decode5Bits($chunk[2]);
+ $c2 = static::decode5Bits($chunk[3]);
+ $c3 = static::decode5Bits($chunk[4]);
+ $c4 = static::decode5Bits($chunk[5]);
+ $c5 = static::decode5Bits($chunk[6]);
$dest .= \pack(
'CCCC',
@@ -102,10 +108,10 @@ abstract class Base32
);
$err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5) >> 8;
} elseif ($i + 4 < $srcLen) {
- $c1 = self::decode5Bits($chunk[2]);
- $c2 = self::decode5Bits($chunk[3]);
- $c3 = self::decode5Bits($chunk[4]);
- $c4 = self::decode5Bits($chunk[5]);
+ $c1 = static::decode5Bits($chunk[2]);
+ $c2 = static::decode5Bits($chunk[3]);
+ $c3 = static::decode5Bits($chunk[4]);
+ $c4 = static::decode5Bits($chunk[5]);
$dest .= \pack(
'CCC',
@@ -115,9 +121,9 @@ abstract class Base32
);
$err |= ($c0 | $c1 | $c2 | $c3 | $c4) >> 8;
} elseif ($i + 3 < $srcLen) {
- $c1 = self::decode5Bits($chunk[2]);
- $c2 = self::decode5Bits($chunk[3]);
- $c3 = self::decode5Bits($chunk[4]);
+ $c1 = static::decode5Bits($chunk[2]);
+ $c2 = static::decode5Bits($chunk[3]);
+ $c3 = static::decode5Bits($chunk[4]);
$dest .= \pack(
'CC',
@@ -126,8 +132,8 @@ abstract class Base32
);
$err |= ($c0 | $c1 | $c2 | $c3) >> 8;
} elseif ($i + 2 < $srcLen) {
- $c1 = self::decode5Bits($chunk[2]);
- $c2 = self::decode5Bits($chunk[3]);
+ $c1 = static::decode5Bits($chunk[2]);
+ $c2 = static::decode5Bits($chunk[3]);
$dest .= \pack(
'CC',
@@ -136,7 +142,7 @@ abstract class Base32
);
$err |= ($c0 | $c1 | $c2) >> 8;
} elseif ($i + 1 < $srcLen) {
- $c1 = self::decode5Bits($chunk[2]);
+ $c1 = static::decode5Bits($chunk[2]);
$dest .= \pack(
'C',
@@ -177,14 +183,14 @@ abstract class Base32
$b3 = $chunk[4];
$b4 = $chunk[5];
$dest .=
- self::encode5Bits( ($b0 >> 3) & 31) .
- self::encode5Bits((($b0 << 2) | ($b1 >> 6)) & 31) .
- self::encode5Bits((($b1 >> 1) ) & 31) .
- self::encode5Bits((($b1 << 4) | ($b2 >> 4)) & 31) .
- self::encode5Bits((($b2 << 1) | ($b3 >> 7)) & 31) .
- self::encode5Bits((($b3 >> 2) ) & 31) .
- self::encode5Bits((($b3 << 3) | ($b4 >> 5)) & 31) .
- self::encode5Bits( $b4 & 31);
+ static::encode5Bits( ($b0 >> 3) & 31) .
+ static::encode5Bits((($b0 << 2) | ($b1 >> 6)) & 31) .
+ static::encode5Bits((($b1 >> 1) ) & 31) .
+ static::encode5Bits((($b1 << 4) | ($b2 >> 4)) & 31) .
+ static::encode5Bits((($b2 << 1) | ($b3 >> 7)) & 31) .
+ static::encode5Bits((($b3 >> 2) ) & 31) .
+ static::encode5Bits((($b3 << 3) | ($b4 >> 5)) & 31) .
+ static::encode5Bits( $b4 & 31);
}
if ($i < $srcLen) {
$chunk = \unpack('C*', Core::safeSubstr($src, $i, $srcLen - $i));
@@ -194,47 +200,45 @@ abstract class Base32
$b2 = $chunk[3];
$b3 = $chunk[4];
$dest .=
- self::encode5Bits( ($b0 >> 3) & 31) .
- self::encode5Bits((($b0 << 2) | ($b1 >> 6)) & 31) .
- self::encode5Bits((($b1 >> 1) ) & 31) .
- self::encode5Bits((($b1 << 4) | ($b2 >> 4)) & 31) .
- self::encode5Bits((($b2 << 1) | ($b3 >> 7)) & 31) .
- self::encode5Bits((($b3 >> 2) ) & 31) .
- self::encode5Bits((($b3 << 3) ) & 31) .
+ static::encode5Bits( ($b0 >> 3) & 31) .
+ static::encode5Bits((($b0 << 2) | ($b1 >> 6)) & 31) .
+ static::encode5Bits((($b1 >> 1) ) & 31) .
+ static::encode5Bits((($b1 << 4) | ($b2 >> 4)) & 31) .
+ static::encode5Bits((($b2 << 1) | ($b3 >> 7)) & 31) .
+ static::encode5Bits((($b3 >> 2) ) & 31) .
+ static::encode5Bits((($b3 << 3) ) & 31) .
'=';
} elseif ($i + 2 < $srcLen) {
$b1 = $chunk[2];
$b2 = $chunk[3];
$dest .=
- self::encode5Bits( ($b0 >> 3) & 31) .
- self::encode5Bits((($b0 << 2) | ($b1 >> 6)) & 31) .
- self::encode5Bits((($b1 >> 1) ) & 31) .
- self::encode5Bits((($b1 << 4) | ($b2 >> 4)) & 31) .
- self::encode5Bits((($b2 << 1) ) & 31) .
+ static::encode5Bits( ($b0 >> 3) & 31) .
+ static::encode5Bits((($b0 << 2) | ($b1 >> 6)) & 31) .
+ static::encode5Bits((($b1 >> 1) ) & 31) .
+ static::encode5Bits((($b1 << 4) | ($b2 >> 4)) & 31) .
+ static::encode5Bits((($b2 << 1) ) & 31) .
'===';
} elseif ($i + 1 < $srcLen) {
$b1 = $chunk[2];
$dest .=
- self::encode5Bits( ($b0 >> 3) & 31) .
- self::encode5Bits((($b0 << 2) | ($b1 >> 6)) & 31) .
- self::encode5Bits((($b1 >> 1) ) & 31) .
- self::encode5Bits((($b1 << 4) ) & 31) .
+ static::encode5Bits( ($b0 >> 3) & 31) .
+ static::encode5Bits((($b0 << 2) | ($b1 >> 6)) & 31) .
+ static::encode5Bits((($b1 >> 1) ) & 31) .
+ static::encode5Bits((($b1 << 4) ) & 31) .
'====';
} else {
$dest .=
- self::encode5Bits( ($b0 >> 3) & 31) .
- self::encode5Bits( ($b0 << 2) & 31) .
+ static::encode5Bits( ($b0 >> 3) & 31) .
+ static::encode5Bits( ($b0 << 2) & 31) .
'======';
}
}
return $dest;
}
-
-
/**
*
- * @param $src
+ * @param int $src
* @return int
*/
protected static function decode5Bits($src)
diff --git a/src/Base32Hex.php b/src/Base32Hex.php
new file mode 100644
index 0000000..fde2644
--- /dev/null
+++ b/src/Base32Hex.php
@@ -0,0 +1,46 @@
+<?php
+namespace ParagonIE\ConstantTime;
+
+/**
+ * Class Base32Hex
+ * [0-9][A-V]
+ *
+ * @package ParagonIE\ConstantTime
+ */
+abstract class Base32Hex extends Base32
+{
+ /**
+ * Base64 character set:
+ * [0-9] [A-V]
+ * 0x30-0x39, 0x41-0x56
+ *
+ * @param int $src
+ * @return int
+ */
+ protected static function decode5Bits($src)
+ {
+ $ret = -1;
+
+ // if ($src > 0x30 && $src < 0x3a) ret += $src - 0x2e + 1; // -47
+ $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src - 47);
+
+ // if ($src > 0x40 && $src < 0x57) ret += $src - 0x41 + 10 + 1; // -54
+ $ret += (((0x40 - $src) & ($src - 0x57)) >> 8) & ($src - 54);
+
+ return $ret;
+ }
+
+ /**
+ * @param int $src
+ * @return string
+ */
+ protected static function encode5Bits($src)
+ {
+ $src += 0x30;
+
+ // if ($src > 0x39) $src += 0x41 - 0x3a; // 7
+ $src += ((0x39 - $src) >> 8) & 7;
+
+ return \pack('C', $src);
+ }
+} \ No newline at end of file
diff --git a/src/Base64.php b/src/Base64.php
index 477e848..1e7c4f5 100644
--- a/src/Base64.php
+++ b/src/Base64.php
@@ -1,6 +1,12 @@
<?php
namespace ParagonIE\ConstantTime;
+/**
+ * Class Base64
+ * [A-Z][a-z][0-9]+/
+ *
+ * @package ParagonIE\ConstantTime
+ */
abstract class Base64
{
/**
@@ -22,10 +28,10 @@ abstract class Base64
$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);
+ static::encode6Bits( $b0 >> 2 ) .
+ static::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
+ static::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) .
+ static::encode6Bits( $b2 & 63);
}
if ($i < $srcLen) {
$chunk = \unpack('C*', Core::safeSubstr($src, $i, $srcLen - $i));
@@ -33,13 +39,13 @@ abstract class Base64
if ($i + 1 < $srcLen) {
$b1 = $chunk[2];
$dest .=
- self::encode6Bits( $b0 >> 2 ) .
- self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
- self::encode6Bits( ($b1 << 2) & 63) . '=';
+ static::encode6Bits( $b0 >> 2 ) .
+ static::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
+ static::encode6Bits( ($b1 << 2) & 63) . '=';
} else {
$dest .=
- self::encode6Bits( $b0 >> 2) .
- self::encode6Bits(($b0 << 4) & 63) . '==';
+ static::encode6Bits( $b0 >> 2) .
+ static::encode6Bits(($b0 << 4) & 63) . '==';
}
}
return $dest;
@@ -50,8 +56,8 @@ abstract class Base64
*
* Base64 character set "./[A-Z][a-z][0-9]"
*
- * @param $src
- * @return bool|string
+ * @param string $src
+ * @return string
* @throws \RangeException
*/
public static function decode($src)
@@ -77,10 +83,10 @@ abstract class Base64
$dest = '';
for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
$chunk = \unpack('C*', Core::safeSubstr($src, $i, 4));
- $c0 = self::decode6Bits($chunk[1]);
- $c1 = self::decode6Bits($chunk[2]);
- $c2 = self::decode6Bits($chunk[3]);
- $c3 = self::decode6Bits($chunk[4]);
+ $c0 = static::decode6Bits($chunk[1]);
+ $c1 = static::decode6Bits($chunk[2]);
+ $c2 = static::decode6Bits($chunk[3]);
+ $c3 = static::decode6Bits($chunk[4]);
$dest .= \pack(
'CCC',
@@ -92,11 +98,11 @@ abstract class Base64
}
if ($i < $srcLen) {
$chunk = \unpack('C*', Core::safeSubstr($src, $i, $srcLen - $i));
- $c0 = self::decode6Bits($chunk[1]);
- $c1 = self::decode6Bits($chunk[2]);
+ $c0 = static::decode6Bits($chunk[1]);
+ $c1 = static::decode6Bits($chunk[2]);
if ($i + 2 < $srcLen) {
- $c2 = self::decode6Bits($chunk[3]);
+ $c2 = static::decode6Bits($chunk[3]);
$dest .= \pack(
'CC',
((($c0 << 2) | ($c1 >> 4)) & 0xff),
@@ -125,7 +131,7 @@ abstract class Base64
* [A-Z] [a-z] [0-9] + /
* 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
*
- * @param $src
+ * @param int $src
* @return int
*/
protected static function decode6Bits($src)
@@ -151,7 +157,7 @@ abstract class Base64
}
/**
- * @param $src
+ * @param int $src
* @return string
*/
protected static function encode6Bits($src)
diff --git a/src/Base64DotSlash.php b/src/Base64DotSlash.php
index 039106f..f316a26 100644
--- a/src/Base64DotSlash.php
+++ b/src/Base64DotSlash.php
@@ -1,15 +1,21 @@
<?php
namespace ParagonIE\ConstantTime;
+/**
+ * Class Base64DotSlash
+ * ./[A-Z][a-z][0-9]
+ *
+ * @package ParagonIE\ConstantTime
+ */
abstract class Base64DotSlash extends Base64
{
/**
*
* Base64 character set:
- * [A-Z] [a-z] [0-9] + /
- * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
+ * ./ [A-Z] [a-z] [0-9]
+ * 0x2e-0x2f, 0x41-0x5a, 0x61-0x7a, 0x30-0x39
*
- * @param $src
+ * @param int $src
* @return int
*/
protected static function decode6Bits($src)
@@ -32,7 +38,7 @@ abstract class Base64DotSlash extends Base64
}
/**
- * @param $src
+ * @param int $src
* @return string
*/
protected static function encode6Bits($src)
diff --git a/src/Base64DotSlashOrdered.php b/src/Base64DotSlashOrdered.php
index 797cba5..3057738 100644
--- a/src/Base64DotSlashOrdered.php
+++ b/src/Base64DotSlashOrdered.php
@@ -1,14 +1,20 @@
<?php
namespace ParagonIE\ConstantTime;
+/**
+ * Class Base64DotSlashOrdered
+ * ./[0-9][A-Z][a-z]
+ *
+ * @package ParagonIE\ConstantTime
+ */
abstract class Base64DotSlashOrdered extends Base64
{
/**
* Base64 character set:
- * [A-Z] [a-z] [0-9] + /
- * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
+ * [.-9] [A-Z] [a-z]
+ * 0x2e-0x39, 0x41-0x5a, 0x61-0x7a
*
- * @param $src
+ * @param int $src
* @return int
*/
protected static function decode6Bits($src)
@@ -28,7 +34,7 @@ abstract class Base64DotSlashOrdered extends Base64
}
/**
- * @param $src
+ * @param int $src
* @return string
*/
protected static function encode6Bits($src)
diff --git a/src/Encoding.php b/src/Encoding.php
index 657e855..a8fadb0 100644
--- a/src/Encoding.php
+++ b/src/Encoding.php
@@ -45,6 +45,27 @@ abstract class Encoding
{
return Base32::decode($str);
}
+ /**
+ * RFC 4648 Base32 encoding
+ *
+ * @param $str
+ * @return string
+ */
+ public static function base32HexEncode($str)
+ {
+ return Base32Hex::encode($str);
+ }
+
+ /**
+ * RFC 4648 Base32 decoding
+ *
+ * @param $str
+ * @return string
+ */
+ public static function base32HexDecode($str)
+ {
+ return Base32Hex::decode($str);
+ }
/**
* RFC 4648 Base64 encoding
diff --git a/tests/EncodingTest.php b/tests/EncodingTest.php
index 9216e8b..e62b082 100644
--- a/tests/EncodingTest.php
+++ b/tests/EncodingTest.php
@@ -1,5 +1,11 @@
<?php
+use \ParagonIE\ConstantTime\Base32;
+use \ParagonIE\ConstantTime\Base32Hex;
+use \ParagonIE\ConstantTime\Base64;
+use \ParagonIE\ConstantTime\Base64DotSlash;
+use \ParagonIE\ConstantTime\Base64DotSlashOrdered;
use \ParagonIE\ConstantTime\Encoding;
+use \ParagonIE\ConstantTime\Hex;
class EncodingTest extends PHPUnit_Framework_TestCase
{
@@ -70,6 +76,41 @@ class EncodingTest extends PHPUnit_Framework_TestCase
'22222222'
);
}
+
+ public function testBase32Hex()
+ {
+ $this->assertEquals(
+ Base32Hex::encode("\x00"),
+ '00======'
+ );
+ $this->assertEquals(
+ Base32Hex::encode("\x00\x00"),
+ '0000===='
+ );
+ $this->assertEquals(
+ Base32Hex::encode("\x00\x00\x00"),
+ '00000==='
+ );
+ $this->assertEquals(
+ Base32Hex::encode("\x00\x00\x00\x00"),
+ '0000000='
+ );
+ $this->assertEquals(
+ Base32Hex::encode("\x00\x00\x00\x00\x00"),
+ '00000000'
+ );
+ $this->assertEquals(
+ Base32Hex::encode("\x00\x00\x0F\xFF\xFF"),
+ '0000VVVV'
+ );
+ $this->assertEquals(
+ Base32Hex::encode("\xFF\xFF\xF0\x00\x00"),
+ 'VVVV0000'
+ );
+
+
+ }
+
/**
* Based on test vectors from RFC 4648
*/
@@ -186,6 +227,13 @@ class EncodingTest extends PHPUnit_Framework_TestCase
"Base32 Encoding - Length: " . $i
);
+ $enc = Encoding::base32HexEncode($rand);
+ $this->assertEquals(
+ bin2hex($rand),
+ bin2hex(Encoding::base32HexDecode($enc)),
+ "Base32 Encoding - Length: " . $i
+ );
+
$enc = Encoding::base64Encode($rand);
$this->assertEquals(
$rand,