Subversion Repositories php_utils

Rev

Rev 2 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
<?php
2
 
3
// Mastercopy of this file:
4
// http://www.viathinksoft.de/~daniel-marschall/code/php/marschallHash.phps
5
 
6
function MHA($password, $iteratedSalt='', $iterations=1987, $binary_output=false) {
7
 
8
        // --------------------------------------------------------------------------------
9
        // MarschallHash: Uncrackable hash with multiple SHA1 iterations in base64 encoding
10
        // This function is pretty slow because of the iterations, but therefore secure
11
        // against offline attacks or rainbowtables. Also, the slowlyness of this hash
12
        // makes the creation of rainbow tables much harder.
13
        //
14
        // (C)Copyright 2011 Daniel Marschall, ViaThinkSoft. All rights reserved.
15
        // www.daniel-marschall.de / www.viathinksoft.de
16
        //
17
        // Notation of the hash name:
18
        // - MHA-1987 (resp. MHA-xxxx where xxxx stands for $iterations)
19
        // - MHAb-1987 is used for the binary output variant
20
        // - MD5MHA-1987 is used if $password is a (unsalted!) md5-hash
21
        // - MD5MHAb-1987 is used for the binary output variant.
22
        //
23
        // Default parameters:
24
        // iteratedSalt  = ''       --> you should change this value to something
25
        //                              user-specific (e.g. username) or something random
26
        // iterations    = 1987     --> you should ONLY change this value to a lower
27
        //                              one if you have performance issues
28
        // binary_output = no       --> base64 encoding is chosen by default
29
        //
30
        // Format:
31
        // - MHA has the same length as SHA1.
32
        // - MHA in base64 format has a constant length of 27 bytes and is case sensitive.
33
        // - MHA in binary format has a constant length of 20 bytes.
34
        //
35
        // Comparison 1:
36
        // x         = ''
37
        // SHA1(x)   = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'                         (Len = 40)
38
        // SHA256(x) = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' (Len = 64)
39
        // MD5(x)    = 'd41d8cd98f00b204e9800998ecf8427e'                                 (Len = 32)
40
        // MHA(x)    = 'UOLv7DgK5/4S7994FeSWZkHDJoQ'                                      (Len = 27)
41
        //
42
        // Comparison 2:
43
        // x         = 'The quick brown fox jumps over the lazy dog'
44
        // SHA1(x)   = '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12'                         (Len = 40)
45
        // SHA256(x) = 'd7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592' (Len = 64)
46
        // MD5(x)    = '9e107d9d372bb6826bd81d3542a419d6'                                 (Len = 32)
47
        // MHA(x)    = 'Bqdd38sigmurBt6kU/0q99GWSnE'                                      (Len = 27)
48
        //
49
        // Mechanism:
50
        // MHA(x, iteratedSalt, iterations) = optionalBase64(rec(iterations, x, iteratedSalt))
51
        // rec[n, x, iteratedSalt] = binarySHA1(iteratedSalt || rec[n-1, x, iteratedSalt] || iteratedSalt)
52
        // rec[0, x, iteratedSalt] = x
53
        //
54
        // Recommended usage:
55
        // - Use the username as iteratedSalt
56
        //      MHA($password, $username) == $database_hash
57
        // - If you want to upgrade your existing user-database, e.g. already hashed with md5():
58
        //   a) Update your database:
59
        //      $database_hash_new = MHA($database_hash_old, $username)
60
        //   b) Compare with this variant:
61
        //      MHA(md5($password), $username) == $database_hash_new
62
        //      or
63
        //      MD5_MHA($password, $username) == $database_hash_new
64
        //
65
        // Revision: 2011-07-21 (fixed typo in 2013-03-09)
66
        // --------------------------------------------------------------------------------
67
 
68
        if ($iterations < 1) {
69
                trigger_error('at function ' . __FUNCTION__ . ': $iterations has to be greater or equal 1', E_USER_ERROR);
70
                return false;
71
        }
72
 
73
        $m = $password;
74
 
75
        for ($i=1; $i<=$iterations; $i++) {
76
                $m = sha1($iteratedSalt.$m.$iteratedSalt, true); // SHA1 with binary output
77
        }
78
 
79
        if (!$binary_output) {
80
                $m = base64_encode($m);
81
 
82
                // Remove single "=" at the end
83
                # $m = str_replace('=', '', $m);
84
                $m = substr($m, 0, 27);
85
        }
86
 
87
        return $m;
88
}
89
 
90
// --- The following functions are useable for database migration ---
91
 
92
function MD5_TO_MD5_MHA($md5_hash, $iteratedSalt='', $iterations=1987, $binary_output=false) {
93
        // Use this function to migrate a (unsalted!) md5 hash into a MD5MHA hash
94
        //
95
        // Actually, this is just an alias of MHA()
96
 
97
        return marschallHash($md5_hash, $iteratedSalt, $iterations, $binary_output);
98
}
99
 
100
function MD5_MHA($password, $iteratedSalt='', $iterations=1987, $binary_output=false) {
101
        // Use this function if you have a MD5MHA hash instead of a MHA hash
102
        //
103
        // MD5MHA() is equal to MHA(MD5()) where MD5() is unsalted!
104
 
105
        return MHA(md5($password), $iteratedSalt, $iterations, $binary_output);
106
}
107
 
108
function MD5MHA($password, $iteratedSalt='', $iterations=1987, $binary_output=false) {
109
        // Alias of MD5_MHA()
110
 
111
        return MD5_MHA($password, $iteratedSalt, $iterations, $binary_output);
112
}
113
 
114
function MHA_AddIterations($mha, $iteratedSalt='', $additionalIterations, $binary_output=false) {
115
        // This function converts a MHA with x itertions into a MHA with
116
        // x+additionalIterations iterations, if the iteratedSalt is equal.
117
        // Use this function if you want to upgrade your database to a higher MHA strength.
118
        //
119
        // Example:
120
        // MHA_AddIterations(MHA('test', 'salt', 1987), 'salt', 13) == MHA('test', 'salt', 1987+13);
121
        //
122
        // Of course, you cannot lower the strength of a MHA, so additionalIterations has to be >= 0.
123
 
124
        // Is it Base64 input?
125
        # if (strlen($mha) == 28) $mha = base64_decode($mha);
126
        if (strlen($mha) == 27) $mha = base64_decode($mha);
127
 
128
        // Is it now binary input?
129
        // (Que) Will there be problems if the input string looks like multibyte?
130
        if (strlen($mha) != 20) {
131
                trigger_error('at function ' . __FUNCTION__ . ': does not seem to be a MHA', E_USER_ERROR);
132
                return false;
133
        }
134
 
135
        if ($additionalIterations == 0) return $mha;
136
 
137
        if ($additionalIterations < 0) {
138
                trigger_error('at function ' . __FUNCTION__ . ': additionalIterations has to be 0 or higher.', E_USER_ERROR);
139
                return false;
140
        }
141
 
142
        return marschallHash($mha, $iteratedSalt, $additionalIterations, $binary_output);
143
}
144
 
145
?>