BaseCurves
9 months ago
Curves
9 months ago
Formats
9 months ago
.htaccess
9 months ago
Parameters.php
9 months ago
PrivateKey.php
9 months ago
PublicKey.php
9 months ago
index.html
9 months ago
web.config
9 months ago
PublicKey.php
172 lines
| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * EC Public Key |
| 5 | * |
| 6 | * @author Jim Wigginton <terrafrost@php.net> |
| 7 | * @copyright 2015 Jim Wigginton |
| 8 | * @license http://www.opensource.org/licenses/mit-license.html MIT License |
| 9 | * @link http://phpseclib.sourceforge.net |
| 10 | */ |
| 11 | |
| 12 | declare(strict_types=1); |
| 13 | |
| 14 | namespace phpseclib3\Crypt\EC; |
| 15 | |
| 16 | use phpseclib3\Common\Functions\Strings; |
| 17 | use phpseclib3\Crypt\Common; |
| 18 | use phpseclib3\Crypt\EC; |
| 19 | use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve; |
| 20 | use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve; |
| 21 | use phpseclib3\Crypt\EC\Curves\Ed25519; |
| 22 | use phpseclib3\Crypt\EC\Formats\Keys\PKCS1; |
| 23 | use phpseclib3\Crypt\EC\Formats\Signature\ASN1 as ASN1Signature; |
| 24 | use phpseclib3\Crypt\Hash; |
| 25 | use phpseclib3\Exception\UnsupportedOperationException; |
| 26 | use phpseclib3\Math\BigInteger; |
| 27 | |
| 28 | /** |
| 29 | * EC Public Key |
| 30 | * |
| 31 | * @author Jim Wigginton <terrafrost@php.net> |
| 32 | */ |
| 33 | final class PublicKey extends EC implements Common\PublicKey |
| 34 | { |
| 35 | use Common\Traits\Fingerprint; |
| 36 | |
| 37 | /** |
| 38 | * Verify a signature |
| 39 | * |
| 40 | * @see self::verify() |
| 41 | * @param string $message |
| 42 | * @param string $signature |
| 43 | */ |
| 44 | public function verify($message, $signature): bool |
| 45 | { |
| 46 | if ($this->curve instanceof MontgomeryCurve) { |
| 47 | throw new UnsupportedOperationException('Montgomery Curves cannot be used to create signatures'); |
| 48 | } |
| 49 | |
| 50 | $shortFormat = $this->shortFormat; |
| 51 | $format = $this->sigFormat; |
| 52 | if ($format === false) { |
| 53 | return false; |
| 54 | } |
| 55 | |
| 56 | $order = $this->curve->getOrder(); |
| 57 | |
| 58 | if ($this->curve instanceof TwistedEdwardsCurve) { |
| 59 | if ($shortFormat == 'SSH2') { |
| 60 | [, $signature] = Strings::unpackSSH2('ss', $signature); |
| 61 | } |
| 62 | |
| 63 | if ($this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context)) { |
| 64 | return sodium_crypto_sign_verify_detached($signature, $message, $this->toString('libsodium')); |
| 65 | } |
| 66 | |
| 67 | $curve = $this->curve; |
| 68 | if (strlen($signature) != 2 * $curve::SIZE) { |
| 69 | return false; |
| 70 | } |
| 71 | |
| 72 | $R = substr($signature, 0, $curve::SIZE); |
| 73 | $S = substr($signature, $curve::SIZE); |
| 74 | |
| 75 | try { |
| 76 | $R = PKCS1::extractPoint($R, $curve); |
| 77 | $R = $this->curve->convertToInternal($R); |
| 78 | } catch (\Exception $e) { |
| 79 | return false; |
| 80 | } |
| 81 | |
| 82 | $S = strrev($S); |
| 83 | $S = new BigInteger($S, 256); |
| 84 | |
| 85 | if ($S->compare($order) >= 0) { |
| 86 | return false; |
| 87 | } |
| 88 | |
| 89 | $A = $curve->encodePoint($this->QA); |
| 90 | |
| 91 | if ($curve instanceof Ed25519) { |
| 92 | $dom2 = !isset($this->context) ? '' : |
| 93 | 'SigEd25519 no Ed25519 collisions' . "\0" . chr(strlen($this->context)) . $this->context; |
| 94 | } else { |
| 95 | $context = $this->context ?? ''; |
| 96 | $dom2 = 'SigEd448' . "\0" . chr(strlen($context)) . $context; |
| 97 | } |
| 98 | |
| 99 | $hash = new Hash($curve::HASH); |
| 100 | $k = $hash->hash($dom2 . substr($signature, 0, $curve::SIZE) . $A . $message); |
| 101 | $k = strrev($k); |
| 102 | $k = new BigInteger($k, 256); |
| 103 | [, $k] = $k->divide($order); |
| 104 | |
| 105 | $qa = $curve->convertToInternal($this->QA); |
| 106 | |
| 107 | $lhs = $curve->multiplyPoint($curve->getBasePoint(), $S); |
| 108 | $rhs = $curve->multiplyPoint($qa, $k); |
| 109 | $rhs = $curve->addPoint($rhs, $R); |
| 110 | $rhs = $curve->convertToAffine($rhs); |
| 111 | |
| 112 | return $lhs[0]->equals($rhs[0]) && $lhs[1]->equals($rhs[1]); |
| 113 | } |
| 114 | |
| 115 | $params = $format::load($signature); |
| 116 | if ($params === false || count($params) != 2) { |
| 117 | return false; |
| 118 | } |
| 119 | extract($params); |
| 120 | |
| 121 | if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) { |
| 122 | $sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature; |
| 123 | |
| 124 | $result = openssl_verify($message, $sig, $this->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash()); |
| 125 | |
| 126 | if ($result != -1) { |
| 127 | return (bool) $result; |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | $n_1 = $order->subtract(self::$one); |
| 132 | if (!$r->between(self::$one, $n_1) || !$s->between(self::$one, $n_1)) { |
| 133 | return false; |
| 134 | } |
| 135 | |
| 136 | $e = $this->hash->hash($message); |
| 137 | $e = new BigInteger($e, 256); |
| 138 | |
| 139 | $Ln = $this->hash->getLength() - $order->getLength(); |
| 140 | $z = $Ln > 0 ? $e->bitwise_rightShift($Ln) : $e; |
| 141 | |
| 142 | $w = $s->modInverse($order); |
| 143 | [, $u1] = $z->multiply($w)->divide($order); |
| 144 | [, $u2] = $r->multiply($w)->divide($order); |
| 145 | |
| 146 | $u1 = $this->curve->convertInteger($u1); |
| 147 | $u2 = $this->curve->convertInteger($u2); |
| 148 | |
| 149 | [$x1, $y1] = $this->curve->multiplyAddPoints( |
| 150 | [$this->curve->getBasePoint(), $this->QA], |
| 151 | [$u1, $u2] |
| 152 | ); |
| 153 | |
| 154 | $x1 = $x1->toBigInteger(); |
| 155 | [, $x1] = $x1->divide($order); |
| 156 | |
| 157 | return $x1->equals($r); |
| 158 | } |
| 159 | |
| 160 | /** |
| 161 | * Returns the public key |
| 162 | * |
| 163 | * @param array $options optional |
| 164 | */ |
| 165 | public function toString(string $type, array $options = []): string |
| 166 | { |
| 167 | $type = self::validatePlugin('Keys', $type, 'savePublicKey'); |
| 168 | |
| 169 | return $type::savePublicKey($this->curve, $this->QA, $options); |
| 170 | } |
| 171 | } |
| 172 |