[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ -> ECSignature.php (source)

   1  <?php
   2  
   3  declare(strict_types=1);
   4  
   5  /*
   6   * The MIT License (MIT)
   7   *
   8   * Copyright (c) 2014-2019 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 Cose\Algorithm\Signature\ECDSA;
  15  
  16  use InvalidArgumentException;
  17  use const STR_PAD_LEFT;
  18  
  19  /**
  20   * @internal
  21   */
  22  final class ECSignature
  23  {
  24      private const ASN1_SEQUENCE = '30';
  25      private const ASN1_INTEGER = '02';
  26      private const ASN1_MAX_SINGLE_BYTE = 128;
  27      private const ASN1_LENGTH_2BYTES = '81';
  28      private const ASN1_BIG_INTEGER_LIMIT = '7f';
  29      private const ASN1_NEGATIVE_INTEGER = '00';
  30      private const BYTE_SIZE = 2;
  31  
  32      public static function toAsn1(string $signature, int $length): string
  33      {
  34          $signature = bin2hex($signature);
  35  
  36          if (self::octetLength($signature) !== $length) {
  37              throw new InvalidArgumentException('Invalid signature length.');
  38          }
  39  
  40          $pointR = self::preparePositiveInteger(mb_substr($signature, 0, $length, '8bit'));
  41          $pointS = self::preparePositiveInteger(mb_substr($signature, $length, null, '8bit'));
  42  
  43          $lengthR = self::octetLength($pointR);
  44          $lengthS = self::octetLength($pointS);
  45  
  46          $totalLength = $lengthR + $lengthS + self::BYTE_SIZE + self::BYTE_SIZE;
  47          $lengthPrefix = $totalLength > self::ASN1_MAX_SINGLE_BYTE ? self::ASN1_LENGTH_2BYTES : '';
  48  
  49          return self::hex2bin(
  50              self::ASN1_SEQUENCE
  51              .$lengthPrefix.dechex($totalLength)
  52              .self::ASN1_INTEGER.dechex($lengthR).$pointR
  53              .self::ASN1_INTEGER.dechex($lengthS).$pointS
  54          );
  55      }
  56  
  57      public static function fromAsn1(string $signature, int $length): string
  58      {
  59          $message = bin2hex($signature);
  60          $position = 0;
  61  
  62          if (self::ASN1_SEQUENCE !== self::readAsn1Content($message, $position, self::BYTE_SIZE)) {
  63              throw new InvalidArgumentException('Invalid data. Should start with a sequence.');
  64          }
  65  
  66          if (self::ASN1_LENGTH_2BYTES === self::readAsn1Content($message, $position, self::BYTE_SIZE)) {
  67              $position += self::BYTE_SIZE;
  68          }
  69  
  70          $pointR = self::retrievePositiveInteger(self::readAsn1Integer($message, $position));
  71          $pointS = self::retrievePositiveInteger(self::readAsn1Integer($message, $position));
  72  
  73          return self::hex2bin(str_pad($pointR, $length, '0', STR_PAD_LEFT).str_pad($pointS, $length, '0', STR_PAD_LEFT));
  74      }
  75  
  76      private static function octetLength(string $data): int
  77      {
  78          return (int) (mb_strlen($data, '8bit') / self::BYTE_SIZE);
  79      }
  80  
  81      private static function preparePositiveInteger(string $data): string
  82      {
  83          if (mb_substr($data, 0, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT) {
  84              return self::ASN1_NEGATIVE_INTEGER.$data;
  85          }
  86  
  87          while (self::ASN1_NEGATIVE_INTEGER === mb_substr($data, 0, self::BYTE_SIZE, '8bit')
  88              && mb_substr($data, 2, self::BYTE_SIZE, '8bit') <= self::ASN1_BIG_INTEGER_LIMIT) {
  89              $data = mb_substr($data, 2, null, '8bit');
  90          }
  91  
  92          return $data;
  93      }
  94  
  95      private static function readAsn1Content(string $message, int &$position, int $length): string
  96      {
  97          $content = mb_substr($message, $position, $length, '8bit');
  98          $position += $length;
  99  
 100          return $content;
 101      }
 102  
 103      private static function readAsn1Integer(string $message, int &$position): string
 104      {
 105          if (self::ASN1_INTEGER !== self::readAsn1Content($message, $position, self::BYTE_SIZE)) {
 106              throw new InvalidArgumentException('Invalid data. Should contain an integer.');
 107          }
 108  
 109          $length = (int) hexdec(self::readAsn1Content($message, $position, self::BYTE_SIZE));
 110  
 111          return self::readAsn1Content($message, $position, $length * self::BYTE_SIZE);
 112      }
 113  
 114      private static function retrievePositiveInteger(string $data): string
 115      {
 116          while (self::ASN1_NEGATIVE_INTEGER === mb_substr($data, 0, self::BYTE_SIZE, '8bit')
 117              && mb_substr($data, 2, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT) {
 118              $data = mb_substr($data, 2, null, '8bit');
 119          }
 120  
 121          return $data;
 122      }
 123  
 124      private static function hex2bin(string $data): string
 125      {
 126          $result = \hex2bin($data);
 127          if (false === $result) {
 128              throw new InvalidArgumentException('Unable to convert the data');
 129          }
 130  
 131          return $result;
 132      }
 133  }


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