DSA.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. <?php
  2. /**
  3. * Pure-PHP FIPS 186-4 compliant implementation of DSA.
  4. *
  5. * PHP version 5
  6. *
  7. * Here's an example of how to create signatures and verify signatures with this library:
  8. * <code>
  9. * <?php
  10. * include 'vendor/autoload.php';
  11. *
  12. * extract(\phpseclib\Crypt\DSA::createKey());
  13. *
  14. * $plaintext = 'terrafrost';
  15. *
  16. * $signature = $privatekey->sign($plaintext, 'ASN1');
  17. *
  18. * echo $publickey->verify($plaintext, $signature) ? 'verified' : 'unverified';
  19. * ?>
  20. * </code>
  21. *
  22. * @category Crypt
  23. * @package DSA
  24. * @author Jim Wigginton <terrafrost@php.net>
  25. * @copyright 2016 Jim Wigginton
  26. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  27. * @link http://phpseclib.sourceforge.net
  28. */
  29. namespace phpseclib\Crypt;
  30. use ParagonIE\ConstantTime\Base64;
  31. use phpseclib\File\ASN1;
  32. use phpseclib\Math\BigInteger;
  33. use phpseclib\Crypt\Common\AsymmetricKey;
  34. use phpseclib\Common\Functions\Strings;
  35. /**
  36. * Pure-PHP FIPS 186-4 compliant implementation of DSA.
  37. *
  38. * @package DSA
  39. * @author Jim Wigginton <terrafrost@php.net>
  40. * @access public
  41. */
  42. class DSA extends AsymmetricKey
  43. {
  44. /**
  45. * Algorithm Name
  46. *
  47. * @var string
  48. * @access private
  49. */
  50. const ALGORITHM = 'DSA';
  51. /**
  52. * DSA Prime P
  53. *
  54. * @var \phpseclib\Math\BigInteger
  55. * @access private
  56. */
  57. private $p;
  58. /**
  59. * DSA Group Order q
  60. *
  61. * Prime divisor of p-1
  62. *
  63. * @var \phpseclib\Math\BigInteger
  64. * @access private
  65. */
  66. protected $q;
  67. /**
  68. * DSA Group Generator G
  69. *
  70. * @var \phpseclib\Math\BigInteger
  71. * @access private
  72. */
  73. private $g;
  74. /**
  75. * DSA secret exponent x
  76. *
  77. * @var \phpseclib\Math\BigInteger
  78. * @access private
  79. */
  80. protected $x;
  81. /**
  82. * DSA public key value y
  83. *
  84. * @var \phpseclib\Math\BigInteger
  85. * @access private
  86. */
  87. private $y;
  88. /**
  89. * Parameters Format
  90. *
  91. * @var string
  92. * @access private
  93. */
  94. private $parametersFormat = 'PKCS1';
  95. /**
  96. * Create DSA parameters
  97. *
  98. * @access public
  99. * @param int $L
  100. * @param int $N
  101. * @return \phpseclib\Crypt\DSA
  102. */
  103. static function createParameters($L = 2048, $N = 224)
  104. {
  105. self::initialize_static_variables();
  106. switch (true) {
  107. case $N == 160:
  108. /*
  109. in FIPS 186-1 and 186-2 N was fixed at 160 whereas K had an upper bound of 1024.
  110. RFC 4253 (SSH Transport Layer Protocol) references FIPS 186-2 and as such most
  111. SSH DSA implementations only support keys with an N of 160.
  112. puttygen let's you set the size of L (but not the size of N) and uses 2048 as the
  113. default L value. that's not really compliant with any of the FIPS standards, however,
  114. for the purposes of maintaining compatibility with puttygen, we'll support it
  115. */
  116. //case ($L >= 512 || $L <= 1024) && (($L & 0x3F) == 0) && $N == 160:
  117. // FIPS 186-3 changed this as follows:
  118. //case $L == 1024 && $N == 160:
  119. case $L == 2048 && $N == 224:
  120. case $L == 2048 && $N == 256:
  121. case $L == 3072 && $N == 256:
  122. break;
  123. default:
  124. return false;
  125. }
  126. $two = new BigInteger(2);
  127. $q = BigInteger::randomPrime($N);
  128. $divisor = $q->multiply($two);
  129. do {
  130. $x = BigInteger::random($L);
  131. list(, $c) = $x->divide($divisor);
  132. $p = $x->subtract($c->subtract(self::$one));
  133. } while ($p->getLength() != $L || !$p->isPrime());
  134. $p_1 = $p->subtract(self::$one);
  135. list($e) = $p_1->divide($q);
  136. // quoting http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf#page=50 ,
  137. // "h could be obtained from a random number generator or from a counter that
  138. // changes after each use". PuTTY (sshdssg.c) starts h off at 1 and increments
  139. // it on each loop. wikipedia says "commonly h = 2 is used" so we'll just do that
  140. $h = clone $two;
  141. while (true) {
  142. $g = $h->powMod($e, $p);
  143. if (!$g->equals(self::$one)) {
  144. break;
  145. }
  146. $h = $h->add(self::$one);
  147. }
  148. $dsa = new DSA();
  149. $dsa->p = $p;
  150. $dsa->q = $q;
  151. $dsa->g = $g;
  152. return $dsa;
  153. }
  154. /**
  155. * Create public / private key pair.
  156. *
  157. * This method is a bit polymorphic. It can take a DSA object (eg. pre-loaded with parameters),
  158. * L / N as two distinct parameters or no parameters (at which point L and N will be generated
  159. * with this method)
  160. *
  161. * Returns an array with the following two elements:
  162. * - 'privatekey': The private key.
  163. * - 'publickey': The public key.
  164. *
  165. * @access public
  166. * @return \phpseclib\Crypt\DSA
  167. */
  168. static function createKey()
  169. {
  170. self::initialize_static_variables();
  171. $args = func_get_args();
  172. if (count($args) == 2 && is_int($args[0]) && is_int($args[1])) {
  173. $private = self::createParameters($args[0], $args[1]);
  174. } else if (count($args) == 1 && $args[0] instanceof DSA) {
  175. $private = clone $args[0];
  176. } else if (!count($args)) {
  177. $private = self::createParameters();
  178. } else {
  179. throw new \InvalidArgumentException('Valid parameters are either two integers (L and N), a single DSA object or no parameters at all.');
  180. }
  181. $private->x = BigInteger::randomRange(self::$one, $private->q->subtract(self::$one));
  182. $private->y = $private->g->powMod($private->x, $private->p);
  183. $public = clone $private;
  184. unset($public->x);
  185. return ['privatekey' => $private, 'publickey' => $public];
  186. }
  187. /**
  188. * Loads a public or private key
  189. *
  190. * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
  191. *
  192. * @access public
  193. * @param string $key
  194. * @param int $type optional
  195. */
  196. public function load($key, $type = false)
  197. {
  198. if ($key instanceof DSA) {
  199. $this->privateKeyFormat = $key->privateKeyFormat;
  200. $this->publicKeyFormat = $key->publicKeyFormat;
  201. $this->format = $key->format;
  202. $this->p = $key->p;
  203. $this->q = $key->q;
  204. $this->g = $key->g;
  205. $this->x = $key->x;
  206. $this->y = $key->y;
  207. $this->parametersFormat = $key->parametersFormat;
  208. return true;
  209. }
  210. $components = parent::load($key, $type);
  211. if ($components === false) {
  212. return false;
  213. }
  214. if (isset($components['p'])) {
  215. switch (true) {
  216. case isset($this->p) && !$this->p->equals($components['p']):
  217. case isset($this->q) && !$this->q->equals($components['q']):
  218. case isset($this->g) && !$this->g->equals($components['g']):
  219. $this->x = $this->y = null;
  220. }
  221. $this->p = $components['p'];
  222. $this->q = $components['q'];
  223. $this->g = $components['g'];
  224. }
  225. if (isset($components['x'])) {
  226. $this->x = $components['x'];
  227. }
  228. if (isset($components['y'])) {
  229. $this->y = $components['y'];
  230. }
  231. //} else if (isset($components['x'])) {
  232. // $this->y = $this->g->powMod($this->x, $this->p);
  233. //}
  234. return true;
  235. }
  236. /**
  237. * Returns the key size
  238. *
  239. * More specifically, this L (the length of DSA Prime P) and N (the length of DSA Group Order q)
  240. *
  241. * @access public
  242. * @return array
  243. */
  244. public function getLength()
  245. {
  246. return isset($this->p) ?
  247. ['L' => $this->p->getLength(), 'N' => $this->q->getLength()] :
  248. ['L' => 0, 'N' => 0];
  249. }
  250. /**
  251. * __toString() magic method
  252. *
  253. * @access public
  254. * @return string
  255. */
  256. public function __toString()
  257. {
  258. $key = parent::__toString();
  259. if (!empty($key)) {
  260. return $key;
  261. }
  262. try {
  263. $key = $this->getParameters($this->parametersFormat);
  264. return is_string($key) ? $key : '';
  265. } catch (\Exception $e) {
  266. return '';
  267. }
  268. }
  269. /**
  270. * Returns the private key
  271. *
  272. * PKCS1 DSA private keys contain x and y. PKCS8 DSA private keys just contain x
  273. * but y can be derived from x.
  274. *
  275. * @see self::getPublicKey()
  276. * @access public
  277. * @param string $type optional
  278. * @return mixed
  279. */
  280. public function getPrivateKey($type = 'PKCS8')
  281. {
  282. $type = self::validatePlugin('Keys', $type, 'savePrivateKey');
  283. if ($type === false) {
  284. return false;
  285. }
  286. if (!isset($this->x)) {
  287. return false;
  288. }
  289. if (!isset($this->y)) {
  290. $this->y = $this->g->powMod($this->x, $this->p);
  291. }
  292. return $type::savePrivateKey($this->p, $this->q, $this->g, $this->y, $this->x, $this->password);
  293. }
  294. /**
  295. * Returns the public key
  296. *
  297. * If you do "openssl rsa -in private.rsa -pubout -outform PEM" you get a PKCS8 formatted key
  298. * that contains a publicKeyAlgorithm AlgorithmIdentifier and a publicKey BIT STRING.
  299. * An AlgorithmIdentifier contains an OID and a parameters field. With RSA public keys this
  300. * parameters field is NULL. With DSA PKCS8 public keys it is not - it contains the p, q and g
  301. * variables. The publicKey BIT STRING contains, simply, the y variable. This can be verified
  302. * by getting a DSA PKCS8 public key:
  303. *
  304. * "openssl dsa -in private.dsa -pubout -outform PEM"
  305. *
  306. * ie. just swap out rsa with dsa in the rsa command above.
  307. *
  308. * A PKCS1 public key corresponds to the publicKey portion of the PKCS8 key. In the case of RSA
  309. * the publicKey portion /is/ the key. In the case of DSA it is not. You cannot verify a signature
  310. * without the parameters and the PKCS1 DSA public key format does not include the parameters.
  311. *
  312. * @see self::getPrivateKey()
  313. * @access public
  314. * @param string $type optional
  315. * @return mixed
  316. */
  317. public function getPublicKey($type = 'PKCS8')
  318. {
  319. $type = self::validatePlugin('Keys', $type, 'savePublicKey');
  320. if ($type === false) {
  321. return false;
  322. }
  323. if (!isset($this->y)) {
  324. if (!isset($this->x) || !isset($this->p)) {
  325. return false;
  326. }
  327. $this->y = $this->g->powMod($this->x, $this->p);
  328. }
  329. return $type::savePublicKey($this->p, $this->q, $this->g, $this->y);
  330. }
  331. /**
  332. * Returns the parameters
  333. *
  334. * A public / private key is only returned if the currently loaded "key" contains an x or y
  335. * value.
  336. *
  337. * @see self::getPublicKey()
  338. * @see self::getPrivateKey()
  339. * @access public
  340. * @param string $type optional
  341. * @return mixed
  342. */
  343. public function getParameters($type = 'PKCS1')
  344. {
  345. $type = self::validatePlugin('Keys', $type, 'saveParameters');
  346. if ($type === false) {
  347. return false;
  348. }
  349. if (!isset($this->p) || !isset($this->q) || !isset($this->g)) {
  350. return false;
  351. }
  352. return $type::saveParameters($this->p, $this->q, $this->g);
  353. }
  354. /**
  355. * Create a signature
  356. *
  357. * @see self::verify()
  358. * @access public
  359. * @param string $message
  360. * @param string $format optional
  361. * @return mixed
  362. */
  363. function sign($message, $format = 'Raw')
  364. {
  365. $format = self::validatePlugin('Signature', $format);
  366. if ($format === false) {
  367. return false;
  368. }
  369. if (empty($this->x) || empty($this->p)) {
  370. return false;
  371. }
  372. while (true) {
  373. $k = BigInteger::randomRange(self::$one, $this->q->subtract(self::$one));
  374. $r = $this->g->powMod($k, $this->p);
  375. list(, $r) = $r->divide($this->q);
  376. if ($r->equals(self::$zero)) {
  377. continue;
  378. }
  379. $kinv = $k->modInverse($this->q);
  380. $h = $this->hash->hash($message);
  381. $h = $this->bits2int($h);
  382. $temp = $h->add($this->x->multiply($r));
  383. $temp = $kinv->multiply($temp);
  384. list(, $s) = $temp->divide($this->q);
  385. if (!$s->equals(self::$zero)) {
  386. break;
  387. }
  388. }
  389. // the following is an RFC6979 compliant implementation of deterministic DSA
  390. // it's unused because it's mainly intended for use when a good CSPRNG isn't
  391. // available. if phpseclib's CSPRNG isn't good then even key generation is
  392. // suspect
  393. /*
  394. $h1 = $this->hash->hash($message);
  395. $k = $this->computek($h1);
  396. $r = $this->g->powMod($k, $this->p);
  397. list(, $r) = $r->divide($this->q);
  398. $kinv = $k->modInverse($this->q);
  399. $h1 = $this->bits2int($h1);
  400. $temp = $h1->add($this->x->multiply($r));
  401. $temp = $kinv->multiply($temp);
  402. list(, $s) = $temp->divide($this->q);
  403. */
  404. return $format::save($r, $s);
  405. }
  406. /**
  407. * Verify a signature
  408. *
  409. * @see self::verify()
  410. * @access public
  411. * @param string $message
  412. * @param string $format optional
  413. * @return mixed
  414. */
  415. function verify($message, $signature, $format = 'Raw')
  416. {
  417. $format = self::validatePlugin('Signature', $format);
  418. if ($format === false) {
  419. return false;
  420. }
  421. $params = $format::load($signature);
  422. if ($params === false || count($params) != 2) {
  423. return false;
  424. }
  425. extract($params);
  426. if (empty($this->y) || empty($this->p)) {
  427. return false;
  428. }
  429. $q_1 = $this->q->subtract(self::$one);
  430. if (!$r->between(self::$one, $q_1) || !$s->between(self::$one, $q_1)) {
  431. return false;
  432. }
  433. $w = $s->modInverse($this->q);
  434. $h = $this->hash->hash($message);
  435. $h = $this->bits2int($h);
  436. list(, $u1) = $h->multiply($w)->divide($this->q);
  437. list(, $u2) = $r->multiply($w)->divide($this->q);
  438. $v1 = $this->g->powMod($u1, $this->p);
  439. $v2 = $this->y->powMod($u2, $this->p);
  440. list(, $v) = $v1->multiply($v2)->divide($this->p);
  441. list(, $v) = $v->divide($this->q);
  442. return Strings::equals($v->toBytes(), $r->toBytes());
  443. }
  444. }