File: dovecot_crypt.php

package info (click to toggle)
postfixadmin 3.3.15%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,816 kB
  • sloc: php: 10,120; perl: 1,069; sh: 643; python: 169; xml: 62; sql: 3; makefile: 2
file content (134 lines) | stat: -rw-r--r-- 5,178 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
<?php

define('SHA1_RESULTLEN', (160/8));
define('SHA256_RESULTLEN', (256 / 8));
define('CRAM_MD5_CONTEXTLEN', 32);
define('MD5_RESULTLEN', (128/8));
define('MD4_RESULTLEN', (128/8));
define('LM_HASH_SIZE', 16);
define('NTLMSSP_HASH_SIZE', 16);


class DovecotCrypt extends Crypt {
    private $errormsg = [];

    private $salt_chars = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";


    /**
     * Array
     * Crypt type and which function handles it.
     * array('alogrithm' => array('encoding', 'length', 'verify', 'function'))
     */
    public $password_schemes = array(
        'CRYPT'      => array('NONE', 0, 'crypt_verify', 'crypt_generate'),
        'MD5'        => array('NONE', 0, 'md5_verify', 'md5_generate'),
        //'MD5-CRYPT'  => array('NONE', 0, 'md5_crypt_verify', 'md5_crypt_generate'),
        'SHA'        => array('BASE64', SHA1_RESULTLEN, null, 'sha1_generate'),
        'SHA1'       => array('BASE64', SHA1_RESULTLEN, null, 'sha1_generate'),
        //'SHA256'     => array('BASE64', SHA256_RESULTLEN, NULL, 'sha256_generate'),
        //'SMD5'       => array('BASE64', 0, 'smd5_verify', 'smd5_generate'),
        //'SSHA'       => array('BASE64', 0, 'ssha_verify', 'ssha_generate'),
        //'SSHA256'    => array('BASE64', 0, 'ssha356_verify', 'ssha256_generate'),
        'PLAIN'      => array('NONE', 0, null, 'plain_generate'),
        'CLEARTEXT'  => array('NONE', 0, null, 'plain_generate'),
        'CRAM-MD5'   => array('HEX', CRAM_MD5_CONTEXTLEN, null, 'cram_md5_generate'),
        //'HMAC-MD5'   => array('HEX', CRAM_MD5_CONTEXTLEN, NULL, 'cram_md5_generate'),
        //'DIGEST-MD5' => array('HEX', MD5_RESULTLEN, NULL, 'digest_md5_generate'),
        //'PLAIN-MD4'  => array('HEX', MD4_RESULTLEN, NULL, 'plain_md4_generate'),
        //'PLAIN-MD5'  => array('HEX', MD5_RESULTLEN, NULL, 'plain_md5_generate'),
        //'LDAP-MD5'   => array('BASE64', MD5_RESULTLEN, NULL, 'plain_md5_generate'),
        //'LANMAN'     => array('HEX', LM_HASH_SIZE, NULL, 'lm_generate'),
        //'NTLM'       => array('HEX', NTLMSSP_HASH_SIZE, NULL, 'ntlm_generate'),
        //'OTP'        => array('NONE', 0, 'otp_verify', 'otp_generate'),
        //'SKEY'       => array('NONE', 0, 'otp_verify', 'skey_generate'),
        //'RPA'        => array('HEX', MD5_RESULTLEN, NULL, 'rpa_generate'),
    );



    public function crypt($algorithm) {
        if (!array_key_exists($algorithm, $this->password_schemes)) {
            $this->errormsg[] = "This password scheme isn't supported. Check our Wiki!";
            return false;
        }

        $scheme = $this->password_schemes[$algorithm];
        $func = '__'.$scheme[3];

        $this->password = $this->$func($this->plain);
        //$this->plain = '';
        return true;
    }

    public function verify($algorithm, $password) {
        if (!array_key_exists($algorithm, $this->password_schemes)) {
            $this->errormsg[] = "This password scheme isn't supported. Check our Wiki!";
            return false;
        }

        $scheme = $this->password_schemes[$algorithm];
        if ($scheme[2] == null) {
            $this->errormsg[] = "This password scheme doesn't support verification";
            return false;
        }

        $func = '__'.$scheme[2];
        return  $this->$func($this->plain, $password);
    }

    private function __crypt_verify($plaintext, $password) {
        $crypted = crypt($plaintext, $password);
        return strcmp($crypted, $password) == 0;
    }
    private function __crypt_generate($plaintext) {
        $password = crypt($plaintext);
        return $password;
    }
    private function __md5_generate($plaintext) {
        return $plaintext;
    }
    private function __sha1_generate() {
    }
    private function __plain_generate() {
    }
    private function __cram_md5_generate($plaintext) {

        #http://hg.dovecot.org/dovecot-1.2/file/84373d238073/src/lib/hmac-md5.c
        #http://hg.dovecot.org/dovecot-1.2/file/84373d238073/src/auth/password-scheme.c cram_md5_generate
        #am i right that the hmac salt is the plaintext password itself?
        $salt = $plaintext;
        if (function_exists('hash_hmac')) {  //Some providers doesn't offers hash access.
            return hash_hmac('md5', $plaintext, $salt);
        } else {
            return custom_hmac('md5', $plaintext, $salt);
        }
    }


    /**
     * @return string
     */
    public function custom_hmac($algo, $data, $key, $raw_output = false) {
        $algo = strtolower($algo);
        $pack = 'H'.strlen($algo('test'));
        $size = 64;
        $opad = str_repeat(chr(0x5C), $size);
        $ipad = str_repeat(chr(0x36), $size);

        if (strlen($key) > $size) {
            $key = str_pad(pack($pack, $algo($key)), $size, chr(0x00));
        } else {
            $key = str_pad($key, $size, chr(0x00));
        }

        for ($i = 0; $i < strlen($key) - 1; $i++) {
            $opad[$i] = $opad[$i] ^ $key[$i];
            $ipad[$i] = $ipad[$i] ^ $key[$i];
        }

        $output = $algo($opad.pack($pack, $algo($ipad.$data)));

        return ($raw_output) ? pack($pack, $output) : $output;
    }
}