[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/web-auth/cose-lib/src/Algorithm/Signature/RSA/ -> PSSRSA.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\RSA;
  15  
  16  use function ceil;
  17  use Cose\Algorithm\Signature\Signature;
  18  use Cose\Key\Key;
  19  use Cose\Key\RsaKey;
  20  use function hash_equals;
  21  use InvalidArgumentException;
  22  use Jose\Component\Core\Util\BigInteger;
  23  use Jose\Component\Core\Util\Hash;
  24  use function mb_strlen;
  25  use function mb_substr;
  26  use function pack;
  27  use function random_bytes;
  28  use RuntimeException;
  29  use function str_pad;
  30  use function str_repeat;
  31  
  32  /**
  33   * @internal
  34   */
  35  abstract class PSSRSA implements Signature
  36  {
  37      public function sign(string $data, Key $key): string
  38      {
  39          $key = $this->handleKey($key);
  40          $modulusLength = mb_strlen($key->n(), '8bit');
  41  
  42          $em = $this->encodeEMSAPSS($data, 8 * $modulusLength - 1, $this->getHashAlgorithm());
  43          $message = BigInteger::createFromBinaryString($em);
  44          $signature = $this->exponentiate($key, $message);
  45  
  46          return $this->convertIntegerToOctetString($signature, $modulusLength);
  47      }
  48  
  49      public function verify(string $data, Key $key, string $signature): bool
  50      {
  51          $key = $this->handleKey($key);
  52          $modulusLength = mb_strlen($key->n(), '8bit');
  53  
  54          if (mb_strlen($signature, '8bit') !== $modulusLength) {
  55              throw new InvalidArgumentException('Invalid modulus length');
  56          }
  57          $s2 = BigInteger::createFromBinaryString($signature);
  58          $m2 = $this->exponentiate($key, $s2);
  59          $em = $this->convertIntegerToOctetString($m2, $modulusLength);
  60          $modBits = 8 * $modulusLength;
  61  
  62          return $this->verifyEMSAPSS($data, $em, $modBits - 1, $this->getHashAlgorithm());
  63      }
  64  
  65      private function handleKey(Key $key): RsaKey
  66      {
  67          return new RsaKey($key->getData());
  68      }
  69  
  70      abstract protected function getHashAlgorithm(): Hash;
  71  
  72      private function convertIntegerToOctetString(BigInteger $x, int $xLen): string
  73      {
  74          $x = $x->toBytes();
  75          if (mb_strlen($x, '8bit') > $xLen) {
  76              throw new RuntimeException('Unable to convert the integer');
  77          }
  78  
  79          return str_pad($x, $xLen, \chr(0), STR_PAD_LEFT);
  80      }
  81  
  82      /**
  83       * MGF1.
  84       */
  85      private function getMGF1(string $mgfSeed, int $maskLen, Hash $mgfHash): string
  86      {
  87          $t = '';
  88          $count = ceil($maskLen / $mgfHash->getLength());
  89          for ($i = 0; $i < $count; ++$i) {
  90              $c = pack('N', $i);
  91              $t .= $mgfHash->hash($mgfSeed.$c);
  92          }
  93  
  94          return mb_substr($t, 0, $maskLen, '8bit');
  95      }
  96  
  97      /**
  98       * EMSA-PSS-ENCODE.
  99       */
 100      private function encodeEMSAPSS(string $message, int $modulusLength, Hash $hash): string
 101      {
 102          $emLen = ($modulusLength + 1) >> 3;
 103          $sLen = $hash->getLength();
 104          $mHash = $hash->hash($message);
 105          if ($emLen <= $hash->getLength() + $sLen + 2) {
 106              throw new RuntimeException();
 107          }
 108          $salt = random_bytes($sLen);
 109          $m2 = "\0\0\0\0\0\0\0\0".$mHash.$salt;
 110          $h = $hash->hash($m2);
 111          $ps = str_repeat(\chr(0), $emLen - $sLen - $hash->getLength() - 2);
 112          $db = $ps.\chr(1).$salt;
 113          $dbMask = $this->getMGF1($h, $emLen - $hash->getLength() - 1, $hash);
 114          $maskedDB = $db ^ $dbMask;
 115          $maskedDB[0] = ~\chr(0xFF << ($modulusLength & 7)) & $maskedDB[0];
 116  
 117          return $maskedDB.$h.\chr(0xBC);
 118      }
 119  
 120      /**
 121       * EMSA-PSS-VERIFY.
 122       */
 123      private function verifyEMSAPSS(string $m, string $em, int $emBits, Hash $hash): bool
 124      {
 125          $emLen = ($emBits + 1) >> 3;
 126          $sLen = $hash->getLength();
 127          $mHash = $hash->hash($m);
 128          if ($emLen < $hash->getLength() + $sLen + 2) {
 129              throw new InvalidArgumentException();
 130          }
 131          if ($em[mb_strlen($em, '8bit') - 1] !== \chr(0xBC)) {
 132              throw new InvalidArgumentException();
 133          }
 134          $maskedDB = mb_substr($em, 0, -$hash->getLength() - 1, '8bit');
 135          $h = mb_substr($em, -$hash->getLength() - 1, $hash->getLength(), '8bit');
 136          $temp = \chr(0xFF << ($emBits & 7));
 137          if ((~$maskedDB[0] & $temp) !== $temp) {
 138              throw new InvalidArgumentException();
 139          }
 140          $dbMask = $this->getMGF1($h, $emLen - $hash->getLength() - 1, $hash/*MGF*/);
 141          $db = $maskedDB ^ $dbMask;
 142          $db[0] = ~\chr(0xFF << ($emBits & 7)) & $db[0];
 143          $temp = $emLen - $hash->getLength() - $sLen - 2;
 144          if (mb_substr($db, 0, $temp, '8bit') !== str_repeat(\chr(0), $temp)) {
 145              throw new InvalidArgumentException();
 146          }
 147          if (1 !== \ord($db[$temp])) {
 148              throw new InvalidArgumentException();
 149          }
 150          $salt = mb_substr($db, $temp + 1, null, '8bit'); // should be $sLen long
 151          $m2 = "\0\0\0\0\0\0\0\0".$mHash.$salt;
 152          $h2 = $hash->hash($m2);
 153  
 154          return hash_equals($h, $h2);
 155      }
 156  
 157      /**
 158       * Exponentiate with or without Chinese Remainder Theorem.
 159       * Operation with primes 'p' and 'q' is appox. 2x faster.
 160       */
 161      public function exponentiate(RsaKey $key, BigInteger $c): BigInteger
 162      {
 163          if ($c->compare(BigInteger::createFromDecimal(0)) < 0 || $c->compare(BigInteger::createFromBinaryString($key->n())) > 0) {
 164              throw new RuntimeException();
 165          }
 166          if ($key->isPublic() || !$key->hasPrimes() || !$key->hasExponents() || !$key->hasCoefficient()) {
 167              return $c->modPow(BigInteger::createFromBinaryString($key->e()), BigInteger::createFromBinaryString($key->n()));
 168          }
 169  
 170          $p = $key->primes()[0];
 171          $q = $key->primes()[1];
 172          $dP = $key->exponents()[0];
 173          $dQ = $key->exponents()[1];
 174          $qInv = BigInteger::createFromBinaryString($key->QInv());
 175  
 176          $m1 = $c->modPow($dP, $p);
 177          $m2 = $c->modPow($dQ, $q);
 178          $h = $qInv->multiply($m1->subtract($m2)->add($p))->mod($p);
 179  
 180          return $m2->add($h->multiply($q));
 181      }
 182  }


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