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