diff options
-rw-r--r-- | src/Base32.php | 122 | ||||
-rw-r--r-- | src/Base32Hex.php | 46 | ||||
-rw-r--r-- | src/Base64.php | 46 | ||||
-rw-r--r-- | src/Base64DotSlash.php | 14 | ||||
-rw-r--r-- | src/Base64DotSlashOrdered.php | 14 | ||||
-rw-r--r-- | src/Encoding.php | 21 | ||||
-rw-r--r-- | tests/EncodingTest.php | 48 |
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, |