pssht  latest
SSH server library written in PHP
DSS.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 
12 namespace fpoirotte\Pssht\Key\SSH;
13 
19 {
21  const DER_HEADER = "\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10";
22 
24  protected $p;
25 
27  protected $q;
28 
30  protected $g;
31 
33  protected $y;
34 
36  protected $x;
37 
38 
60  public function __construct($p, $q, $g, $y, $x = null)
61  {
62  $this->p = $p;
63  $this->q = $q;
64  $this->g = $g;
65  $this->y = $y;
66  $this->x = $x;
67  }
68 
69  public static function getName()
70  {
71  return 'ssh-dss';
72  }
73 
74  public function serialize(\fpoirotte\Pssht\Wire\Encoder $encoder)
75  {
76  $encoder->encodeString(self::getName());
77  $encoder->encodeMpint($this->p);
78  $encoder->encodeMpint($this->q);
79  $encoder->encodeMpint($this->g);
80  $encoder->encodeMpint($this->y);
81  }
82 
83  public static function unserialize(\fpoirotte\Pssht\Wire\Decoder $decoder, $private = null)
84  {
85  $p = $decoder->decodeMpint();
86  $q = $decoder->decodeMpint();
87  $g = $decoder->decodeMpint();
88  $y = $decoder->decodeMpint();
89  if (!isset($p, $q, $g, $y)) {
90  throw new \InvalidArgumentException();
91  }
92  return new static($p, $q, $g, $y, $private);
93  }
94 
95  public function sign($message)
96  {
97  if ($this->x === null) {
98  throw new \RuntimeException();
99  }
100 
101  $H = gmp_init(sha1($message, false), 16);
102  do {
103  do {
104  do {
105  $k = openssl_random_pseudo_bytes(20);
106 
107  // If $k = 0, we generate a new random number.
108  if (ltrim($k, "\0") === '') {
109  continue;
110  }
111 
112  // We reduce entropy, but since 2^159 < $this->q < 2^160,
113  // and we must have 0 < $k < $this->q, this is garanteed
114  // to work.
115  if (ord($k[0]) & 0x80) {
116  $k[0] = chr(ord($k[0]) & 0x7F);
117  }
118 
119  $k = gmp_init(bin2hex($k), 16);
120  $k_1 = gmp_invert($k, $this->q);
121  } while ($k_1 === false);
122 
123  $r = gmp_mod(gmp_powm($this->g, $k, $this->p), $this->q);
124  $s = gmp_mod(gmp_mul($k_1, gmp_add($H, gmp_mul($this->x, $r))), $this->q);
125  } while ($r === 0 || $s === 0);
126 
127  $r = str_pad(gmp_strval($r, 16), 20, '0', STR_PAD_LEFT);
128  $s = str_pad(gmp_strval($s, 16), 20, '0', STR_PAD_LEFT);
129  } while ($this->check($message, pack('H*H*', $r, $s)) === false);
130 
131  return pack('H*H*', $r, $s);
132  }
133 
134  public function check($message, $signature)
135  {
136  // The signature is the concatenation of $r & $s,
137  // each being a 160 bits integer, hence this check.
138  if (strlen($signature) != 2 * 20) {
139  throw new \InvalidArgumentException();
140  }
141 
142  $H = gmp_init(sha1($message, false), 16);
143  $rp = gmp_init(bin2hex(substr($signature, 0, 20)), 16);
144  $sp = gmp_init(bin2hex(substr($signature, 20)), 16);
145  $w = gmp_invert($sp, $this->q);
146  $g_u1 = gmp_powm($this->g, gmp_mod(gmp_mul($H, $w), $this->q), $this->p);
147  $y_u2 = gmp_powm($this->y, gmp_mod(gmp_mul($rp, $w), $this->q), $this->p);
148  $v = gmp_mod(gmp_mod(gmp_mul($g_u1, $y_u2), $this->p), $this->q);
149  return (gmp_cmp($v, $rp) === 0);
150  }
151 }
$g
DSA parameter g.
Definition: DSS.php:30
const DER_HEADER
DER header for DSA.
Definition: DSS.php:21
static getName()
Return the name of the algorithm.
Definition: DSS.php:69
$p
DSA parameter p.
Definition: DSS.php:24
$x
Private key.
Definition: DSS.php:36
serialize(\fpoirotte\Pssht\Wire\Encoder $encoder)
Definition: DSS.php:74
$q
DSA prime number.
Definition: DSS.php:27
check($message, $signature)
Definition: DSS.php:134
__construct($p, $q, $g, $y, $x=null)
Definition: DSS.php:60