pssht  latest
SSH server library written in PHP
Base.php
1 <?php
2 
3 /*
4 * This file is part of pssht.
5 *
6 * (c) François Poirotte <clicky@erebot.net>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11 
13 
18 abstract class Base implements
21 {
23  protected $Q;
24 
26  protected $d;
27 
29  protected $rng;
30 
44  public function __construct(\fpoirotte\Pssht\ECC\Point $Q, $d = null)
45  {
46  $this->Q = $Q;
47  $this->d = $d;
48  $this->rng = new \fpoirotte\Pssht\Random\OpenSSL();
49  }
50 
51  public static function getName()
52  {
53  return 'ecdsa-sha2-' . static::getIdentifier();
54  }
55 
56  public function serialize(\fpoirotte\Pssht\Wire\Encoder $encoder)
57  {
58  $encoder->encodeString(static::getName());
59  $encoder->encodeString(static::getIdentifier());
60  $encoder->encodeString(
61  $this->Q->serialize(
62  \fpoirotte\Pssht\ECC\Curve::getCurve(static::getIdentifier())
63  )
64  );
65  }
66 
67  public static function unserialize(\fpoirotte\Pssht\Wire\Decoder $decoder, $private = null)
68  {
69  if ($decoder->decodeString() !== static::getIdentifier()) {
70  throw new \InvalidArgumentException();
71  }
72  $Q = \fpoirotte\Pssht\ECC\Point::unserialize(
73  \fpoirotte\Pssht\ECC\Curve::getCurve(static::getIdentifier()),
74  $decoder->decodeString()
75  );
76  return new static($Q, $private);
77  }
78 
79  public function sign($message, $raw_output = false)
80  {
81  if ($this->d === null) {
82  throw new \RuntimeException();
83  }
84 
85  $curve = \fpoirotte\Pssht\ECC\Curve::getCurve(static::getIdentifier());
86  $mod = $curve->getOrder();
87  $mlen = gmp_init(strlen(gmp_strval($mod, 2)));
88  $mlen = gmp_intval(gmp_div_q($mlen, 8, GMP_ROUND_PLUSINF));
89  $M = gmp_init(hash($this->getHash(), $message, false), 16);
90  $generator = $curve->getGenerator();
91 
92  do {
93  do {
94  do {
95  $k = gmp_init(bin2hex($this->rng->getBytes($mlen)), 16);
96  } while (gmp_cmp($k, gmp_sub($mod, 1)) >= 0);
97  $sig1 = $generator->multiply($curve, $k)->x;
98  } while (gmp_cmp($sig1, 0) === 0);
99 
100  $bezout = gmp_gcdext($k, $mod);
101  $k_inv = gmp_mod(gmp_add($bezout['s'], $mod), $mod);
102  $sig2 = gmp_mod(gmp_mul($k_inv, gmp_add($M, gmp_mul($this->d, $sig1))), $mod);
103  } while (gmp_cmp($sig2, 0) === 0);
104 
105  $encoder = new \fpoirotte\Pssht\Wire\Encoder();
106  $encoder->encodeMpint($sig1);
107  $encoder->encodeMpint($sig2);
108  return $encoder->getBuffer()->get(0);
109  }
110 
111  public function check($message, $signature)
112  {
113  $decoder = new \fpoirotte\Pssht\Wire\Decoder(
114  new \fpoirotte\Pssht\Buffer($signature)
115  );
116 
117  $curve = \fpoirotte\Pssht\ECC\Curve::getCurve(static::getIdentifier());
118  $sig1 = $decoder->decodeMpint();
119  $sig2 = $decoder->decodeMpint();
120  $mod = $curve->getOrder();
121  $M = gmp_init(hash($this->getHash(), $message, false), 16);
122  $bezout = gmp_gcdext($sig2, $mod);
123  $w = gmp_mod(gmp_add($bezout['s'], $mod), $mod);
124  $u1 = gmp_mod(gmp_mul($M, $w), $mod);
125  $u2 = gmp_mod(gmp_mul($sig1, $w), $mod);
126  $R = \fpoirotte\Pssht\ECC\Point::add(
127  $curve,
128  $curve->getGenerator()->multiply($curve, $u1),
129  $this->Q->multiply($curve, $u2)
130  );
131  return (gmp_cmp($R->x, $sig1) === 0);
132  }
133 
140  public function getRNG()
141  {
142  return $this->rng;
143  }
144 
152  public function setRNG(\fpoirotte\Pssht\Random\RandomInterface $rng)
153  {
154  $this->rng = $rng;
155  return $this;
156  }
157 
158  public function isValid()
159  {
160  $curve = \fpoirotte\Pssht\ECC\Curve::getCurve(static::getIdentifier());
161  if ($this->Q->isIdentity($curve)) {
162  return false;
163  }
164 
165  $p = $curve->getModulus();
166  if (gmp_cmp($this->Q->x, 0) < 0 || gmp_cmp($this->Q->x, $p) >= 0 ||
167  gmp_cmp($this->Q->y, 0) < 0 || gmp_cmp($this->Q->y, $p) >= 0) {
168  return false;
169  }
170 
171  $left = gmp_mod(gmp_mul($this->Q->y, $this->Q->y), $p);
172  $right = gmp_mod(
173  gmp_add(
174  gmp_add(
175  gmp_pow($this->Q->x, 3),
176  gmp_mul($curve->getA(), $this->Q->x)
177  ),
178  $curve->getB()
179  ),
180  $p
181  );
182  if (gmp_cmp($left, $right)) {
183  return false;
184  }
185 
186  if ($curve->getCofactor() === 1) {
187  return true;
188  }
189 
190  return $this->Q->multiply($curve->getOrder())->isIdentity();
191  }
192 
193  public function getPublic()
194  {
195  return $this->Q;
196  }
197 }
serialize(\fpoirotte\Pssht\Wire\Encoder $encoder)
Definition: Base.php:56
__construct(\fpoirotte\Pssht\ECC\Point $Q, $d=null)
Definition: Base.php:44
setRNG(\fpoirotte\Pssht\Random\RandomInterface $rng)
Definition: Base.php:152
check($message, $signature)
Definition: Base.php:111
static getName()
Return the name of the algorithm.
Definition: Base.php:51