PageRenderTime 65ms CodeModel.GetById 35ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/pear/Crypt/CHAP.php

https://bitbucket.org/ngmares/moodle
PHP | 464 lines | 185 code | 45 blank | 234 comment | 11 complexity | e551e94fe3fd370a6ad389cb26cf3658 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-3.0, MPL-2.0-no-copyleft-exception, GPL-3.0, Apache-2.0, BSD-3-Clause
  1. <?php
  2. /*
  3. Copyright (c) 2002-2003, Michael Bretterklieber <michael@bretterklieber.com>
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions
  7. are met:
  8. 1. Redistributions of source code must retain the above copyright
  9. notice, this list of conditions and the following disclaimer.
  10. 2. Redistributions in binary form must reproduce the above copyright
  11. notice, this list of conditions and the following disclaimer in the
  12. documentation and/or other materials provided with the distribution.
  13. 3. The names of the authors may not be used to endorse or promote products
  14. derived from this software without specific prior written permission.
  15. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  16. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  17. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  19. INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  20. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  22. OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  23. NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  24. EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. This code cannot simply be copied and put under the GNU Public License or
  26. any other GPL-like (LGPL, GPL2) License.
  27. $Id$
  28. */
  29. require_once 'PEAR.php';
  30. /**
  31. * Classes for generating packets for various CHAP Protocols:
  32. * CHAP-MD5: RFC1994
  33. * MS-CHAPv1: RFC2433
  34. * MS-CHAPv2: RFC2759
  35. *
  36. * @package Crypt_CHAP
  37. * @author Michael Bretterklieber <michael@bretterklieber.com>
  38. * @access public
  39. * @version $Revision$
  40. */
  41. /**
  42. * class Crypt_CHAP
  43. *
  44. * Abstract base class for CHAP
  45. *
  46. * @package Crypt_CHAP
  47. */
  48. class Crypt_CHAP extends PEAR
  49. {
  50. /**
  51. * Random binary challenge
  52. * @var string
  53. */
  54. var $challenge = null;
  55. /**
  56. * Binary response
  57. * @var string
  58. */
  59. var $response = null;
  60. /**
  61. * User password
  62. * @var string
  63. */
  64. var $password = null;
  65. /**
  66. * Id of the authentication request. Should incremented after every request.
  67. * @var integer
  68. */
  69. var $chapid = 1;
  70. /**
  71. * Constructor
  72. *
  73. * Generates a random challenge
  74. * @return void
  75. */
  76. function Crypt_CHAP()
  77. {
  78. $this->PEAR();
  79. $this->generateChallenge();
  80. }
  81. /**
  82. * Generates a random binary challenge
  83. *
  84. * @param string $varname Name of the property
  85. * @param integer $size Size of the challenge in Bytes
  86. * @return void
  87. */
  88. function generateChallenge($varname = 'challenge', $size = 8)
  89. {
  90. $this->$varname = '';
  91. mt_srand(hexdec(substr(md5(microtime()), -8)) & 0x7fffffff);
  92. for ($i = 0; $i < $size; $i++) {
  93. $this->$varname .= pack('C', 1 + mt_rand() % 255);
  94. }
  95. return $this->$varname;
  96. }
  97. /**
  98. * Generates the response. Overwrite this.
  99. *
  100. * @return void
  101. */
  102. function challengeResponse()
  103. {
  104. }
  105. }
  106. /**
  107. * class Crypt_CHAP_MD5
  108. *
  109. * Generate CHAP-MD5 Packets
  110. *
  111. * @package Crypt_CHAP
  112. */
  113. class Crypt_CHAP_MD5 extends Crypt_CHAP
  114. {
  115. /**
  116. * Generates the response.
  117. *
  118. * CHAP-MD5 uses MD5-Hash for generating the response. The Hash consists
  119. * of the chapid, the plaintext password and the challenge.
  120. *
  121. * @return string
  122. */
  123. function challengeResponse()
  124. {
  125. return pack('H*', md5(pack('C', $this->chapid) . $this->password . $this->challenge));
  126. }
  127. }
  128. /**
  129. * class Crypt_CHAP_MSv1
  130. *
  131. * Generate MS-CHAPv1 Packets. MS-CHAP doesen't use the plaintext password, it uses the
  132. * NT-HASH wich is stored in the SAM-Database or in the smbpasswd, if you are using samba.
  133. * The NT-HASH is MD4(str2unicode(plaintextpass)).
  134. * You need the mhash extension for this class.
  135. *
  136. * @package Crypt_CHAP
  137. */
  138. class Crypt_CHAP_MSv1 extends Crypt_CHAP
  139. {
  140. /**
  141. * Wether using deprecated LM-Responses or not.
  142. * 0 = use LM-Response, 1 = use NT-Response
  143. * @var bool
  144. */
  145. var $flags = 1;
  146. /**
  147. * Constructor
  148. *
  149. * Loads the mhash extension
  150. * @return void
  151. */
  152. function Crypt_CHAP_MSv1()
  153. {
  154. $this->Crypt_CHAP();
  155. $this->loadExtension('mhash');
  156. }
  157. /**
  158. * Generates the NT-HASH from the given plaintext password.
  159. *
  160. * @access public
  161. * @return string
  162. */
  163. function ntPasswordHash($password = null)
  164. {
  165. if (isset($password)) {
  166. return mhash(MHASH_MD4, $this->str2unicode($password));
  167. } else {
  168. return mhash(MHASH_MD4, $this->str2unicode($this->password));
  169. }
  170. }
  171. /**
  172. * Converts ascii to unicode.
  173. *
  174. * @access public
  175. * @return string
  176. */
  177. function str2unicode($str)
  178. {
  179. $uni = '';
  180. $str = (string) $str;
  181. for ($i = 0; $i < strlen($str); $i++) {
  182. $a = ord($str{$i}) << 8;
  183. $uni .= sprintf("%X", $a);
  184. }
  185. return pack('H*', $uni);
  186. }
  187. /**
  188. * Generates the NT-Response.
  189. *
  190. * @access public
  191. * @return string
  192. */
  193. function challengeResponse()
  194. {
  195. return $this->_challengeResponse();
  196. }
  197. /**
  198. * Generates the NT-Response.
  199. *
  200. * @access public
  201. * @return string
  202. */
  203. function ntChallengeResponse()
  204. {
  205. return $this->_challengeResponse(false);
  206. }
  207. /**
  208. * Generates the LAN-Manager-Response.
  209. *
  210. * @access public
  211. * @return string
  212. */
  213. function lmChallengeResponse()
  214. {
  215. return $this->_challengeResponse(true);
  216. }
  217. /**
  218. * Generates the response.
  219. *
  220. * Generates the response using DES.
  221. *
  222. * @param bool $lm wether generating LAN-Manager-Response
  223. * @access private
  224. * @return string
  225. */
  226. function _challengeResponse($lm = false)
  227. {
  228. if ($lm) {
  229. $hash = $this->lmPasswordHash();
  230. } else {
  231. $hash = $this->ntPasswordHash();
  232. }
  233. while (strlen($hash) < 21) {
  234. $hash .= "\0";
  235. }
  236. $td = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, '');
  237. $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
  238. $key = $this->_desAddParity(substr($hash, 0, 7));
  239. mcrypt_generic_init($td, $key, $iv);
  240. $resp1 = mcrypt_generic($td, $this->challenge);
  241. mcrypt_generic_deinit($td);
  242. $key = $this->_desAddParity(substr($hash, 7, 7));
  243. mcrypt_generic_init($td, $key, $iv);
  244. $resp2 = mcrypt_generic($td, $this->challenge);
  245. mcrypt_generic_deinit($td);
  246. $key = $this->_desAddParity(substr($hash, 14, 7));
  247. mcrypt_generic_init($td, $key, $iv);
  248. $resp3 = mcrypt_generic($td, $this->challenge);
  249. mcrypt_generic_deinit($td);
  250. mcrypt_module_close($td);
  251. return $resp1 . $resp2 . $resp3;
  252. }
  253. /**
  254. * Generates the LAN-Manager-HASH from the given plaintext password.
  255. *
  256. * @access public
  257. * @return string
  258. */
  259. function lmPasswordHash($password = null)
  260. {
  261. $plain = isset($password) ? $password : $this->password;
  262. $plain = substr(strtoupper($plain), 0, 14);
  263. while (strlen($plain) < 14) {
  264. $plain .= "\0";
  265. }
  266. return $this->_desHash(substr($plain, 0, 7)) . $this->_desHash(substr($plain, 7, 7));
  267. }
  268. /**
  269. * Generates an irreversible HASH.
  270. *
  271. * @access private
  272. * @return string
  273. */
  274. function _desHash($plain)
  275. {
  276. $key = $this->_desAddParity($plain);
  277. $td = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, '');
  278. $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
  279. mcrypt_generic_init($td, $key, $iv);
  280. $hash = mcrypt_generic($td, 'KGS!@#$%');
  281. mcrypt_generic_deinit($td);
  282. mcrypt_module_close($td);
  283. return $hash;
  284. }
  285. /**
  286. * Adds the parity bit to the given DES key.
  287. *
  288. * @access private
  289. * @param string $key 7-Bytes Key without parity
  290. * @return string
  291. */
  292. function _desAddParity($key)
  293. {
  294. static $odd_parity = array(
  295. 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
  296. 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
  297. 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
  298. 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
  299. 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
  300. 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
  301. 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
  302. 112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
  303. 128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
  304. 145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
  305. 161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
  306. 176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
  307. 193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
  308. 208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
  309. 224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
  310. 241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254);
  311. $bin = '';
  312. for ($i = 0; $i < strlen($key); $i++) {
  313. $bin .= sprintf('%08s', decbin(ord($key{$i})));
  314. }
  315. $str1 = explode('-', substr(chunk_split($bin, 7, '-'), 0, -1));
  316. $x = '';
  317. foreach($str1 as $s) {
  318. $x .= sprintf('%02s', dechex($odd_parity[bindec($s . '0')]));
  319. }
  320. return pack('H*', $x);
  321. }
  322. /**
  323. * Generates the response-packet.
  324. *
  325. * @param bool $lm wether including LAN-Manager-Response
  326. * @access private
  327. * @return string
  328. */
  329. function response($lm = false)
  330. {
  331. $ntresp = $this->ntChallengeResponse();
  332. if ($lm) {
  333. $lmresp = $this->lmChallengeResponse();
  334. } else {
  335. $lmresp = str_repeat ("\0", 24);
  336. }
  337. // Response: LM Response, NT Response, flags (0 = use LM Response, 1 = use NT Response)
  338. return $lmresp . $ntresp . pack('C', !$lm);
  339. }
  340. }
  341. /**
  342. * class Crypt_CHAP_MSv2
  343. *
  344. * Generate MS-CHAPv2 Packets. This version of MS-CHAP uses a 16 Bytes authenticator
  345. * challenge and a 16 Bytes peer Challenge. LAN-Manager responses no longer exists
  346. * in this version. The challenge is already a SHA1 challenge hash of both challenges
  347. * and of the username.
  348. *
  349. * @package Crypt_CHAP
  350. */
  351. class Crypt_CHAP_MSv2 extends Crypt_CHAP_MSv1
  352. {
  353. /**
  354. * The username
  355. * @var string
  356. */
  357. var $username = null;
  358. /**
  359. * The 16 Bytes random binary peer challenge
  360. * @var string
  361. */
  362. var $peerChallenge = null;
  363. /**
  364. * The 16 Bytes random binary authenticator challenge
  365. * @var string
  366. */
  367. var $authChallenge = null;
  368. /**
  369. * Constructor
  370. *
  371. * Generates the 16 Bytes peer and authentication challenge
  372. * @return void
  373. */
  374. function Crypt_CHAP_MSv2()
  375. {
  376. $this->Crypt_CHAP_MSv1();
  377. $this->generateChallenge('peerChallenge', 16);
  378. $this->generateChallenge('authChallenge', 16);
  379. }
  380. /**
  381. * Generates a hash from the NT-HASH.
  382. *
  383. * @access public
  384. * @param string $nthash The NT-HASH
  385. * @return string
  386. */
  387. function ntPasswordHashHash($nthash)
  388. {
  389. return mhash(MHASH_MD4, $nthash);
  390. }
  391. /**
  392. * Generates the challenge hash from the peer and the authenticator challenge and
  393. * the username. SHA1 is used for this, but only the first 8 Bytes are used.
  394. *
  395. * @access public
  396. * @return string
  397. */
  398. function challengeHash()
  399. {
  400. return substr(mhash(MHASH_SHA1, $this->peerChallenge . $this->authChallenge . $this->username), 0, 8);
  401. }
  402. /**
  403. * Generates the response.
  404. *
  405. * @access public
  406. * @return string
  407. */
  408. function challengeResponse()
  409. {
  410. $this->challenge = $this->challengeHash();
  411. return $this->_challengeResponse();
  412. }
  413. }
  414. ?>