1<?php
2
3/**
4 * DSA Public Key
5 *
6 * @category  Crypt
7 * @package   DSA
8 * @author    Jim Wigginton <terrafrost@php.net>
9 * @copyright 2015 Jim Wigginton
10 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
11 * @link      http://phpseclib.sourceforge.net
12 */
13
14namespace phpseclib3\Crypt\DSA;
15
16use phpseclib3\Crypt\Common;
17use phpseclib3\Crypt\DSA;
18use phpseclib3\Crypt\DSA\Formats\Signature\ASN1 as ASN1Signature;
19
20/**
21 * DSA Public Key
22 *
23 * @package DSA
24 * @author  Jim Wigginton <terrafrost@php.net>
25 * @access  public
26 */
27class PublicKey extends DSA implements Common\PublicKey
28{
29    use Common\Traits\Fingerprint;
30
31    /**
32     * Verify a signature
33     *
34     * @see self::verify()
35     * @access public
36     * @param string $message
37     * @param string $signature
38     * @return mixed
39     */
40    public function verify($message, $signature)
41    {
42        $format = $this->sigFormat;
43
44        $params = $format::load($signature);
45        if ($params === false || count($params) != 2) {
46            return false;
47        }
48        extract($params);
49
50        if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
51            $sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature;
52
53            $result = openssl_verify($message, $sig, $this->toString('PKCS8'), $this->hash->getHash());
54
55            if ($result != -1) {
56                return (bool) $result;
57            }
58        }
59
60        $q_1 = $this->q->subtract(self::$one);
61        if (!$r->between(self::$one, $q_1) || !$s->between(self::$one, $q_1)) {
62            return false;
63        }
64
65        $w = $s->modInverse($this->q);
66        $h = $this->hash->hash($message);
67        $h = $this->bits2int($h);
68        list(, $u1) = $h->multiply($w)->divide($this->q);
69        list(, $u2) = $r->multiply($w)->divide($this->q);
70        $v1 = $this->g->powMod($u1, $this->p);
71        $v2 = $this->y->powMod($u2, $this->p);
72        list(, $v) = $v1->multiply($v2)->divide($this->p);
73        list(, $v) = $v->divide($this->q);
74
75        return $v->equals($r);
76    }
77
78    /**
79     * Returns the public key
80     *
81     * @param string $type
82     * @param array $options optional
83     * @return string
84     */
85    public function toString($type, array $options = [])
86    {
87        $type = self::validatePlugin('Keys', $type, 'savePublicKey');
88
89        return $type::savePublicKey($this->p, $this->q, $this->g, $this->y, $options);
90    }
91}
92