~fkooman/php-jwt

d8bbcf76c7b3363fc14a2bb6d76fc965bc0e7ca1 — François Kooman 10 months ago 14afbe0
restore Binary class
A src/Binary.php => src/Binary.php +96 -0
@@ 0,0 1,96 @@
<?php

/*
 * Copyright (c) 2019-2020 François Kooman <fkooman@tuxed.net>
 *
 * 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);
        }
    }
}

M src/Keys/EdDSA/PublicKey.php => src/Keys/EdDSA/PublicKey.php +2 -1
@@ 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;

M src/Keys/EdDSA/SecretKey.php => src/Keys/EdDSA/SecretKey.php +4 -3
@@ 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');

M src/Keys/HS256/SecretKey.php => src/Keys/HS256/SecretKey.php +2 -2
@@ 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;

M src/Keys/RS256/PrivateKey.php => src/Keys/RS256/PrivateKey.php +2 -1
@@ 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;