[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/web-token/jwt-core/Util/ -> ECSignature.php (source)

   1  <?php
   2  
   3  declare(strict_types=1);
   4  
   5  /*
   6   * The MIT License (MIT)
   7   *
   8   * Copyright (c) 2014-2020 Spomky-Labs
   9   *
  10   * This software may be modified and distributed under the terms
  11   * of the MIT license.  See the LICENSE file for details.
  12   */
  13  
  14  namespace Jose\Component\Core\Util;
  15  
  16  use InvalidArgumentException;
  17  use function is_string;
  18  use const STR_PAD_LEFT;
  19  
  20  /**
  21   * @internal
  22   */
  23  final class ECSignature
  24  {
  25      private const ASN1_SEQUENCE = '30';
  26      private const ASN1_INTEGER = '02';
  27      private const ASN1_MAX_SINGLE_BYTE = 128;
  28      private const ASN1_LENGTH_2BYTES = '81';
  29      private const ASN1_BIG_INTEGER_LIMIT = '7f';
  30      private const ASN1_NEGATIVE_INTEGER = '00';
  31      private const BYTE_SIZE = 2;
  32  
  33      /**
  34       * @throws InvalidArgumentException if the length of the signature is invalid
  35       */
  36      public static function toAsn1(string $signature, int $length): string
  37      {
  38          $signature = bin2hex($signature);
  39  
  40          if (self::octetLength($signature) !== $length) {
  41              throw new InvalidArgumentException('Invalid signature length.');
  42          }
  43  
  44          $pointR = self::preparePositiveInteger(mb_substr($signature, 0, $length, '8bit'));
  45          $pointS = self::preparePositiveInteger(mb_substr($signature, $length, null, '8bit'));
  46  
  47          $lengthR = self::octetLength($pointR);
  48          $lengthS = self::octetLength($pointS);
  49  
  50          $totalLength = $lengthR + $lengthS + self::BYTE_SIZE + self::BYTE_SIZE;
  51          $lengthPrefix = $totalLength > self::ASN1_MAX_SINGLE_BYTE ? self::ASN1_LENGTH_2BYTES : '';
  52  
  53          $bin = hex2bin(
  54              self::ASN1_SEQUENCE
  55              .$lengthPrefix.dechex($totalLength)
  56              .self::ASN1_INTEGER.dechex($lengthR).$pointR
  57              .self::ASN1_INTEGER.dechex($lengthS).$pointS
  58          );
  59          if (!is_string($bin)) {
  60              throw new InvalidArgumentException('Unable to parse the data');
  61          }
  62  
  63          return $bin;
  64      }
  65  
  66      /**
  67       * @throws InvalidArgumentException if the signature is not an ASN.1 sequence
  68       */
  69      public static function fromAsn1(string $signature, int $length): string
  70      {
  71          $message = bin2hex($signature);
  72          $position = 0;
  73  
  74          if (self::ASN1_SEQUENCE !== self::readAsn1Content($message, $position, self::BYTE_SIZE)) {
  75              throw new InvalidArgumentException('Invalid data. Should start with a sequence.');
  76          }
  77  
  78          if (self::ASN1_LENGTH_2BYTES === self::readAsn1Content($message, $position, self::BYTE_SIZE)) {
  79              $position += self::BYTE_SIZE;
  80          }
  81  
  82          $pointR = self::retrievePositiveInteger(self::readAsn1Integer($message, $position));
  83          $pointS = self::retrievePositiveInteger(self::readAsn1Integer($message, $position));
  84  
  85          $bin = hex2bin(str_pad($pointR, $length, '0', STR_PAD_LEFT).str_pad($pointS, $length, '0', STR_PAD_LEFT));
  86          if (!is_string($bin)) {
  87              throw new InvalidArgumentException('Unable to parse the data');
  88          }
  89  
  90          return $bin;
  91      }
  92  
  93      private static function octetLength(string $data): int
  94      {
  95          return (int) (mb_strlen($data, '8bit') / self::BYTE_SIZE);
  96      }
  97  
  98      private static function preparePositiveInteger(string $data): string
  99      {
 100          if (mb_substr($data, 0, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT) {
 101              return self::ASN1_NEGATIVE_INTEGER.$data;
 102          }
 103  
 104          while (0 === mb_strpos($data, self::ASN1_NEGATIVE_INTEGER, 0, '8bit')
 105              && mb_substr($data, 2, self::BYTE_SIZE, '8bit') <= self::ASN1_BIG_INTEGER_LIMIT) {
 106              $data = mb_substr($data, 2, null, '8bit');
 107          }
 108  
 109          return $data;
 110      }
 111  
 112      private static function readAsn1Content(string $message, int &$position, int $length): string
 113      {
 114          $content = mb_substr($message, $position, $length, '8bit');
 115          $position += $length;
 116  
 117          return $content;
 118      }
 119  
 120      /**
 121       * @throws InvalidArgumentException if the data is not an integer
 122       */
 123      private static function readAsn1Integer(string $message, int &$position): string
 124      {
 125          if (self::ASN1_INTEGER !== self::readAsn1Content($message, $position, self::BYTE_SIZE)) {
 126              throw new InvalidArgumentException('Invalid data. Should contain an integer.');
 127          }
 128  
 129          $length = (int) hexdec(self::readAsn1Content($message, $position, self::BYTE_SIZE));
 130  
 131          return self::readAsn1Content($message, $position, $length * self::BYTE_SIZE);
 132      }
 133  
 134      private static function retrievePositiveInteger(string $data): string
 135      {
 136          while (0 === mb_strpos($data, self::ASN1_NEGATIVE_INTEGER, 0, '8bit')
 137              && mb_substr($data, 2, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT) {
 138              $data = mb_substr($data, 2, null, '8bit');
 139          }
 140  
 141          return $data;
 142      }
 143  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer