From d8bbcf76c7b3363fc14a2bb6d76fc965bc0e7ca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Kooman?= Date: Fri, 28 Oct 2022 09:40:07 +0200 Subject: [PATCH] restore Binary class --- src/Binary.php | 96 +++++++++++++++++++++++++++++++++++ src/Keys/EdDSA/PublicKey.php | 3 +- src/Keys/EdDSA/SecretKey.php | 7 +-- src/Keys/HS256/SecretKey.php | 4 +- src/Keys/RS256/PrivateKey.php | 3 +- 5 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 src/Binary.php diff --git a/src/Binary.php b/src/Binary.php new file mode 100644 index 0000000..8bc5d86 --- /dev/null +++ b/src/Binary.php @@ -0,0 +1,96 @@ + + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace fkooman\Jwt; + +/** + * Taken from paragonie/constant_time_encoding under MIT license + * @see https://github.com/paragonie/constant_time_encoding/blob/v1.x/src/Binary.php + * + * Copyright (c) 2016 - 2017 Paragon Initiative Enterprises. + * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) + */ +class Binary +{ + /** + * Safe string length + * + * @ref mbstring.func_overload + * + * @param string $str + * @return int + */ + public static function safeStrlen($str) + { + if (\function_exists('mb_strlen')) { + return \mb_strlen($str, '8bit'); + } else { + return \strlen($str); + } + } + + /** + * Safe substring + * + * @ref mbstring.func_overload + * + * @staticvar boolean $exists + * @param string $str + * @param int $start + * @param int $length + * @throws \TypeError + * @return string + */ + public static function safeSubstr( + $str, + $start = 0, + $length = \null + ) { + if (\function_exists('mb_substr')) { + // mb_substr($str, 0, null, '8bit') returns an empty string on PHP + // 5.3, so we have to find the length ourselves. + if (\is_null($length)) { + if ($start >= 0) { + $length = self::safeStrlen($str) - $start; + } else { + $length = -$start; + } + } + // $length calculation above might result in a 0-length string + if ($length === 0) { + return ''; + } + return \mb_substr($str, $start, $length, '8bit'); + } + if ($length === 0) { + return ''; + } + // Unlike mb_substr(), substr() doesn't accept null for length + if (!is_null($length)) { + return \substr($str, $start, $length); + } else { + return \substr($str, $start); + } + } +} diff --git a/src/Keys/EdDSA/PublicKey.php b/src/Keys/EdDSA/PublicKey.php index ab67a28..e12f10b 100644 --- a/src/Keys/EdDSA/PublicKey.php +++ b/src/Keys/EdDSA/PublicKey.php @@ -25,6 +25,7 @@ namespace fkooman\Jwt\Keys\EdDSA; use fkooman\Jwt\Base64UrlSafe; +use fkooman\Jwt\Binary; use LengthException; class PublicKey @@ -37,7 +38,7 @@ class PublicKey */ public function __construct($publicKey) { - if (SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES !== strlen($publicKey)) { + if (SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES !== Binary::safeStrlen($publicKey)) { throw new LengthException('invalid public key length'); } $this->publicKey = $publicKey; diff --git a/src/Keys/EdDSA/SecretKey.php b/src/Keys/EdDSA/SecretKey.php index 95bbb5a..764c1a3 100644 --- a/src/Keys/EdDSA/SecretKey.php +++ b/src/Keys/EdDSA/SecretKey.php @@ -25,6 +25,7 @@ namespace fkooman\Jwt\Keys\EdDSA; use fkooman\Jwt\Base64UrlSafe; +use fkooman\Jwt\Binary; class SecretKey { @@ -36,15 +37,15 @@ class SecretKey */ public function __construct($secretKey) { - switch (strlen($secretKey)) { + switch (Binary::safeStrlen($secretKey)) { case SODIUM_CRYPTO_SIGN_SECRETKEYBYTES: $this->secretKey = $secretKey; break; case SODIUM_CRYPTO_SIGN_SEEDBYTES: - $this->secretKey = substr(\sodium_crypto_sign_seed_keypair($secretKey), 0, 64); + $this->secretKey = Binary::safeSubstr(\sodium_crypto_sign_seed_keypair($secretKey), 0, 64); break; case SODIUM_CRYPTO_SIGN_KEYPAIRBYTES: - $this->secretKey = substr($secretKey, 0, 64); + $this->secretKey = Binary::safeSubstr($secretKey, 0, 64); break; default: throw new \LengthException('invalid secret key length'); diff --git a/src/Keys/HS256/SecretKey.php b/src/Keys/HS256/SecretKey.php index 8307a0e..bf36d0e 100644 --- a/src/Keys/HS256/SecretKey.php +++ b/src/Keys/HS256/SecretKey.php @@ -25,7 +25,7 @@ namespace fkooman\Jwt\Keys\HS256; use fkooman\Jwt\Base64UrlSafe; - +use fkooman\Jwt\Binary; use fkooman\Jwt\Exception\KeyException; class SecretKey @@ -41,7 +41,7 @@ class SecretKey */ public function __construct($secretKey) { - if (32 !== strlen($secretKey)) { + if (32 !== Binary::safeStrlen($secretKey)) { throw new KeyException('invalid key length'); } $this->secretKey = $secretKey; diff --git a/src/Keys/RS256/PrivateKey.php b/src/Keys/RS256/PrivateKey.php index f904812..cd34c12 100644 --- a/src/Keys/RS256/PrivateKey.php +++ b/src/Keys/RS256/PrivateKey.php @@ -24,6 +24,7 @@ namespace fkooman\Jwt\Keys\RS256; +use fkooman\Jwt\Binary; use fkooman\Jwt\Exception\KeyException; use RuntimeException; @@ -51,7 +52,7 @@ class PrivateKey $rsaInfo = $keyInfo['rsa']; // RSA key MUST be at least 2048 bits // @see https://tools.ietf.org/html/rfc7518#section-4.2 - if (256 > strlen($rsaInfo['n'])) { + if (256 > Binary::safeStrlen($rsaInfo['n'])) { throw new KeyException('invalid RSA key, must be >= 2048 bits'); } $this->privateKey = $privateKey; -- 2.45.2