1<?php 2 3define('SHA1_RESULTLEN', (160/8)); 4define('SHA256_RESULTLEN', (256 / 8)); 5define('CRAM_MD5_CONTEXTLEN', 32); 6define('MD5_RESULTLEN', (128/8)); 7define('MD4_RESULTLEN', (128/8)); 8define('LM_HASH_SIZE', 16); 9define('NTLMSSP_HASH_SIZE', 16); 10 11 12class DovecotCrypt extends Crypt 13{ 14 private $errormsg = []; 15 16 private $salt_chars = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 17 18 19 /** 20 * Array 21 * Crypt type and which function handles it. 22 * array('alogrithm' => array('encoding', 'length', 'verify', 'function')) 23 */ 24 public $password_schemes = array( 25 'CRYPT' => array('NONE', 0, 'crypt_verify', 'crypt_generate'), 26 'MD5' => array('NONE', 0, 'md5_verify', 'md5_generate'), 27 //'MD5-CRYPT' => array('NONE', 0, 'md5_crypt_verify', 'md5_crypt_generate'), 28 'SHA' => array('BASE64', SHA1_RESULTLEN, null, 'sha1_generate'), 29 'SHA1' => array('BASE64', SHA1_RESULTLEN, null, 'sha1_generate'), 30 //'SHA256' => array('BASE64', SHA256_RESULTLEN, NULL, 'sha256_generate'), 31 //'SMD5' => array('BASE64', 0, 'smd5_verify', 'smd5_generate'), 32 //'SSHA' => array('BASE64', 0, 'ssha_verify', 'ssha_generate'), 33 //'SSHA256' => array('BASE64', 0, 'ssha356_verify', 'ssha256_generate'), 34 'PLAIN' => array('NONE', 0, null, 'plain_generate'), 35 'CLEARTEXT' => array('NONE', 0, null, 'plain_generate'), 36 'CRAM-MD5' => array('HEX', CRAM_MD5_CONTEXTLEN, null, 'cram_md5_generate'), 37 //'HMAC-MD5' => array('HEX', CRAM_MD5_CONTEXTLEN, NULL, 'cram_md5_generate'), 38 //'DIGEST-MD5' => array('HEX', MD5_RESULTLEN, NULL, 'digest_md5_generate'), 39 //'PLAIN-MD4' => array('HEX', MD4_RESULTLEN, NULL, 'plain_md4_generate'), 40 //'PLAIN-MD5' => array('HEX', MD5_RESULTLEN, NULL, 'plain_md5_generate'), 41 //'LDAP-MD5' => array('BASE64', MD5_RESULTLEN, NULL, 'plain_md5_generate'), 42 //'LANMAN' => array('HEX', LM_HASH_SIZE, NULL, 'lm_generate'), 43 //'NTLM' => array('HEX', NTLMSSP_HASH_SIZE, NULL, 'ntlm_generate'), 44 //'OTP' => array('NONE', 0, 'otp_verify', 'otp_generate'), 45 //'SKEY' => array('NONE', 0, 'otp_verify', 'skey_generate'), 46 //'RPA' => array('HEX', MD5_RESULTLEN, NULL, 'rpa_generate'), 47 ); 48 49 50 51 public function crypt($algorithm) 52 { 53 if (!array_key_exists($algorithm, $this->password_schemes)) { 54 $this->errormsg[] = "This password scheme isn't supported. Check our Wiki!"; 55 return false; 56 } 57 58 $scheme = $this->password_schemes[$algorithm]; 59 $func = '__'.$scheme[3]; 60 61 $this->password = $this->$func($this->plain); 62 //$this->plain = ''; 63 return true; 64 } 65 66 public function verify($algorithm, $password) 67 { 68 if (!array_key_exists($algorithm, $this->password_schemes)) { 69 $this->errormsg[] = "This password scheme isn't supported. Check our Wiki!"; 70 return false; 71 } 72 73 $scheme = $this->password_schemes[$algorithm]; 74 if ($scheme[2] == null) { 75 $this->errormsg[] = "This password scheme doesn't support verification"; 76 return false; 77 } 78 79 $func = '__'.$scheme[2]; 80 return $this->$func($this->plain, $password); 81 } 82 83 private function __crypt_verify($plaintext, $password) 84 { 85 $crypted = crypt($plaintext, $password); 86 return strcmp($crypted, $password) == 0; 87 } 88 private function __crypt_generate($plaintext) 89 { 90 $password = crypt($plaintext); 91 return $password; 92 } 93 private function __md5_generate($plaintext) 94 { 95 return $plaintext; 96 } 97 private function __sha1_generate() 98 { 99 } 100 private function __plain_generate() 101 { 102 } 103 private function __cram_md5_generate($plaintext) 104 { 105 106 #http://hg.dovecot.org/dovecot-1.2/file/84373d238073/src/lib/hmac-md5.c 107 #http://hg.dovecot.org/dovecot-1.2/file/84373d238073/src/auth/password-scheme.c cram_md5_generate 108 #am i right that the hmac salt is the plaintext password itself? 109 $salt = $plaintext; 110 if (function_exists('hash_hmac')) { //Some providers doesn't offers hash access. 111 return hash_hmac('md5', $plaintext, $salt); 112 } else { 113 return custom_hmac('md5', $plaintext, $salt); 114 } 115 } 116 117 118 /** 119 * @return string 120 */ 121 public function custom_hmac($algo, $data, $key, $raw_output = false) 122 { 123 $algo = strtolower($algo); 124 $pack = 'H'.strlen($algo('test')); 125 $size = 64; 126 $opad = str_repeat(chr(0x5C), $size); 127 $ipad = str_repeat(chr(0x36), $size); 128 129 if (strlen($key) > $size) { 130 $key = str_pad(pack($pack, $algo($key)), $size, chr(0x00)); 131 } else { 132 $key = str_pad($key, $size, chr(0x00)); 133 } 134 135 for ($i = 0; $i < strlen($key) - 1; $i++) { 136 $opad[$i] = $opad[$i] ^ $key[$i]; 137 $ipad[$i] = $ipad[$i] ^ $key[$i]; 138 } 139 140 $output = $algo($opad.pack($pack, $algo($ipad.$data))); 141 142 return ($raw_output) ? pack($pack, $output) : $output; 143 } 144} 145