[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/web-token/jwt-signature-algorithm-rsa/Util/ -> RSA.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\Signature\Algorithm\Util;
  15  
  16  use function chr;
  17  use InvalidArgumentException;
  18  use Jose\Component\Core\Util\BigInteger;
  19  use Jose\Component\Core\Util\Hash;
  20  use Jose\Component\Core\Util\RSAKey;
  21  use function ord;
  22  use RuntimeException;
  23  
  24  /**
  25   * @internal
  26   */
  27  class RSA
  28  {
  29      /**
  30       * Probabilistic Signature Scheme.
  31       */
  32      public const SIGNATURE_PSS = 1;
  33  
  34      /**
  35       * Use the PKCS#1.
  36       */
  37      public const SIGNATURE_PKCS1 = 2;
  38  
  39      /**
  40       * @throws RuntimeException         if the data cannot be signed
  41       * @throws InvalidArgumentException if the signature mode is not supported
  42       */
  43      public static function sign(RSAKey $key, string $message, string $hash, int $mode): string
  44      {
  45          switch ($mode) {
  46              case self::SIGNATURE_PSS:
  47                  return self::signWithPSS($key, $message, $hash);
  48  
  49              case self::SIGNATURE_PKCS1:
  50                  $result = openssl_sign($message, $signature, $key->toPEM(), $hash);
  51                  if (true !== $result) {
  52                      throw new RuntimeException('Unable to sign the data');
  53                  }
  54  
  55                  return $signature;
  56  
  57              default:
  58                  throw new InvalidArgumentException('Unsupported mode.');
  59          }
  60      }
  61  
  62      /**
  63       * Create a signature.
  64       */
  65      public static function signWithPSS(RSAKey $key, string $message, string $hash): string
  66      {
  67          $em = self::encodeEMSAPSS($message, 8 * $key->getModulusLength() - 1, Hash::$hash());
  68          $message = BigInteger::createFromBinaryString($em);
  69          $signature = RSAKey::exponentiate($key, $message);
  70  
  71          return self::convertIntegerToOctetString($signature, $key->getModulusLength());
  72      }
  73  
  74      /**
  75       * Create a signature.
  76       *
  77       * @deprecated Please use openssl_sign
  78       */
  79      public static function signWithPKCS15(RSAKey $key, string $message, string $hash): string
  80      {
  81          $em = self::encodeEMSA15($message, $key->getModulusLength(), Hash::$hash());
  82          $message = BigInteger::createFromBinaryString($em);
  83          $signature = RSAKey::exponentiate($key, $message);
  84  
  85          return self::convertIntegerToOctetString($signature, $key->getModulusLength());
  86      }
  87  
  88      /**
  89       * @throws InvalidArgumentException if the signature mode is not supported
  90       */
  91      public static function verify(RSAKey $key, string $message, string $signature, string $hash, int $mode): bool
  92      {
  93          switch ($mode) {
  94              case self::SIGNATURE_PSS:
  95                  return self::verifyWithPSS($key, $message, $signature, $hash);
  96  
  97              case self::SIGNATURE_PKCS1:
  98                  return 1 === openssl_verify($message, $signature, $key->toPEM(), $hash);
  99  
 100              default:
 101                  throw new InvalidArgumentException('Unsupported mode.');
 102          }
 103      }
 104  
 105      /**
 106       * Verifies a signature.
 107       *
 108       * @throws RuntimeException if the signature cannot be verified
 109       */
 110      public static function verifyWithPSS(RSAKey $key, string $message, string $signature, string $hash): bool
 111      {
 112          if (mb_strlen($signature, '8bit') !== $key->getModulusLength()) {
 113              throw new RuntimeException();
 114          }
 115          $s2 = BigInteger::createFromBinaryString($signature);
 116          $m2 = RSAKey::exponentiate($key, $s2);
 117          $em = self::convertIntegerToOctetString($m2, $key->getModulusLength());
 118          $modBits = 8 * $key->getModulusLength();
 119  
 120          return self::verifyEMSAPSS($message, $em, $modBits - 1, Hash::$hash());
 121      }
 122  
 123      /**
 124       * Verifies a signature.
 125       *
 126       * @deprecated Please use openssl_sign
 127       *
 128       * @throws RuntimeException if the signature cannot be verified
 129       */
 130      public static function verifyWithPKCS15(RSAKey $key, string $message, string $signature, string $hash): bool
 131      {
 132          if (mb_strlen($signature, '8bit') !== $key->getModulusLength()) {
 133              throw new RuntimeException();
 134          }
 135          $signature = BigInteger::createFromBinaryString($signature);
 136          $m2 = RSAKey::exponentiate($key, $signature);
 137          $em = self::convertIntegerToOctetString($m2, $key->getModulusLength());
 138  
 139          return hash_equals($em, self::encodeEMSA15($message, $key->getModulusLength(), Hash::$hash()));
 140      }
 141  
 142      /**
 143       * @throws RuntimeException if the value cannot be converted
 144       */
 145      private static function convertIntegerToOctetString(BigInteger $x, int $xLen): string
 146      {
 147          $x = $x->toBytes();
 148          if (mb_strlen($x, '8bit') > $xLen) {
 149              throw new RuntimeException();
 150          }
 151  
 152          return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
 153      }
 154  
 155      /**
 156       * MGF1.
 157       */
 158      private static function getMGF1(string $mgfSeed, int $maskLen, Hash $mgfHash): string
 159      {
 160          $t = '';
 161          $count = ceil($maskLen / $mgfHash->getLength());
 162          for ($i = 0; $i < $count; ++$i) {
 163              $c = pack('N', $i);
 164              $t .= $mgfHash->hash($mgfSeed.$c);
 165          }
 166  
 167          return mb_substr($t, 0, $maskLen, '8bit');
 168      }
 169  
 170      /**
 171       * EMSA-PSS-ENCODE.
 172       *
 173       * @throws RuntimeException if the message length is invalid
 174       */
 175      private static function encodeEMSAPSS(string $message, int $modulusLength, Hash $hash): string
 176      {
 177          $emLen = ($modulusLength + 1) >> 3;
 178          $sLen = $hash->getLength();
 179          $mHash = $hash->hash($message);
 180          if ($emLen <= $hash->getLength() + $sLen + 2) {
 181              throw new RuntimeException();
 182          }
 183          $salt = random_bytes($sLen);
 184          $m2 = "\0\0\0\0\0\0\0\0".$mHash.$salt;
 185          $h = $hash->hash($m2);
 186          $ps = str_repeat(chr(0), $emLen - $sLen - $hash->getLength() - 2);
 187          $db = $ps.chr(1).$salt;
 188          $dbMask = self::getMGF1($h, $emLen - $hash->getLength() - 1, $hash);
 189          $maskedDB = $db ^ $dbMask;
 190          $maskedDB[0] = ~chr(0xFF << ($modulusLength & 7)) & $maskedDB[0];
 191          $em = $maskedDB.$h.chr(0xBC);
 192  
 193          return $em;
 194      }
 195  
 196      /**
 197       * EMSA-PSS-VERIFY.
 198       *
 199       * @throws InvalidArgumentException if the signature cannot be verified
 200       */
 201      private static function verifyEMSAPSS(string $m, string $em, int $emBits, Hash $hash): bool
 202      {
 203          $emLen = ($emBits + 1) >> 3;
 204          $sLen = $hash->getLength();
 205          $mHash = $hash->hash($m);
 206          if ($emLen < $hash->getLength() + $sLen + 2) {
 207              throw new InvalidArgumentException();
 208          }
 209          if ($em[mb_strlen($em, '8bit') - 1] !== chr(0xBC)) {
 210              throw new InvalidArgumentException();
 211          }
 212          $maskedDB = mb_substr($em, 0, -$hash->getLength() - 1, '8bit');
 213          $h = mb_substr($em, -$hash->getLength() - 1, $hash->getLength(), '8bit');
 214          $temp = chr(0xFF << ($emBits & 7));
 215          if ((~$maskedDB[0] & $temp) !== $temp) {
 216              throw new InvalidArgumentException();
 217          }
 218          $dbMask = self::getMGF1($h, $emLen - $hash->getLength() - 1, $hash/*MGF*/);
 219          $db = $maskedDB ^ $dbMask;
 220          $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
 221          $temp = $emLen - $hash->getLength() - $sLen - 2;
 222          if (mb_substr($db, 0, $temp, '8bit') !== str_repeat(chr(0), $temp)) {
 223              throw new InvalidArgumentException();
 224          }
 225          if (1 !== ord($db[$temp])) {
 226              throw new InvalidArgumentException();
 227          }
 228          $salt = mb_substr($db, $temp + 1, null, '8bit'); // should be $sLen long
 229          $m2 = "\0\0\0\0\0\0\0\0".$mHash.$salt;
 230          $h2 = $hash->hash($m2);
 231  
 232          return hash_equals($h, $h2);
 233      }
 234  
 235      /**
 236       * @throws RuntimeException if the value cannot be encoded
 237       */
 238      private static function encodeEMSA15(string $m, int $emBits, Hash $hash): string
 239      {
 240          $h = $hash->hash($m);
 241          $t = $hash->t();
 242          $t .= $h;
 243          $tLen = mb_strlen($t, '8bit');
 244          if ($emBits < $tLen + 11) {
 245              throw new RuntimeException();
 246          }
 247          $ps = str_repeat(chr(0xFF), $emBits - $tLen - 3);
 248  
 249          return "\0\1{$ps}\0{$t}";
 250      }
 251  }


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