You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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