34480b49343afd8e52472a48688a13b5a59c074b
[core.git] / inc / classes / main / crypto / class_CryptoHelper.php
1 <?php
2 /**
3  * A helper class for cryptographical things like hashing passwords and so on
4  *
5  * @author              Roland Haeder <webmaster@ship-simu.org>
6  * @version             0.0.0
7  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 Core Developer Team
8  * @license             GNU GPL 3.0 or any newer version
9  * @link                http://www.ship-simu.org
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <http://www.gnu.org/licenses/>.
23  */
24 class CryptoHelper extends BaseFrameworkSystem implements Cryptable {
25         // Exception constants
26         const EXCEPTION_ENCRYPT_MISSING = 0x1f0;
27         const EXCEPTION_ENCRYPT_INVALID = 0x1f1;
28
29         /**
30          * An instance of this own clas
31          */
32         private static $selfInstance = null;
33
34         /**
35          * Instance of the random number generator
36          */
37         private $rngInstance = null;
38
39         /**
40          * Salt for hashing operations
41          */
42         private $salt = '';
43
44         /**
45          * Seperator on many places
46          */
47         private $seperator = '|';
48
49         /**
50          * Protected constructor
51          *
52          * @return      void
53          */
54         protected function __construct () {
55                 // Call parent constructor
56                 parent::__construct(__CLASS__);
57
58                 // Clean up a little
59                 $this->removeNumberFormaters();
60                 $this->removeSystemArray();
61         }
62
63         /**
64          * Creates an instance of this class
65          *
66          * @return      $cryptoInstance         An instance of this crypto helper class
67          */
68         public final static function createCryptoHelper () {
69                 // Get a new instance
70                 $cryptoInstance = new CryptoHelper();
71
72                 // Initialize the hasher
73                 $cryptoInstance->initHasher();
74
75                 // Return the instance
76                 return $cryptoInstance;
77         }
78
79         /**
80          * Get a singleton instance of this class
81          *
82          * @return      $selfInstance   An instance of this crypto helper class
83          */
84         public final static function getInstance () {
85                 // Is no instance there?
86                 if (is_null(self::$selfInstance)) {
87                         // Then get a new one
88                         self::$selfInstance = self::createCryptoHelper();
89                 }
90
91                 // Return the instance
92                 return self::$selfInstance;
93         }
94
95         /**
96          * Initializes the hasher for different purposes.
97          *
98          * @return      void
99          */
100         protected function initHasher () {
101                 // Initialize the random number generator which is required by some crypto methods
102                 $this->rngInstance = ObjectFactory::createObjectByConfiguredName('rng_class');
103
104                 // Generate a salt for the hasher
105                 $this->generateSalt();
106         }
107
108         /**
109          * Generates the salt based on configured length
110          *
111          * @return      void
112          */
113         private function generateSalt () {
114                 // Get a random string from the RNG
115                 $randomString = $this->rngInstance->randomString();
116
117                 // Get config entry for salt length
118                 $length = $this->getConfigInstance()->getConfigEntry('salt_length');
119
120                 // Keep only defined number of characters
121                 $this->salt = substr(sha1($randomString), -$length, $length);
122         }
123
124         /**
125          * Hashes a string with salt and returns the hash. If an old previous hash
126          * is supplied the method will use the first X chars of that hash for hashing
127          * the password. This is useful if you want to check if password is identical
128          * for authorization purposes.
129          *
130          * @param       $str            Unhashed string
131          * @param       $oldHash        A hash from previous hashed string
132          * @return      $hashed         The hashed and salted string
133          */
134         public function hashString ($str, $oldHash = '') {
135                 // Cast the string
136                 $str = (string) $str;
137
138                 // Default is the default salt ;-)
139                 $salt = $this->salt;
140
141                 // Is the old password set?
142                 if (!empty($oldHash)) {
143                         // Use the salt from hash, first get length
144                         $length = $this->getConfigInstance()->getConfigEntry('salt_length');
145
146                         // Then extract the X first characters from the hash as our salt
147                         $salt = substr($oldHash, 0, $length);
148                 } // END - if
149
150                 // Hash the password with salt
151                 //* DEBUG: */ echo "salt=".$salt."/plain=".$str."<br />\n";
152                 $hashed = $salt . md5(sprintf($this->getConfigInstance()->getConfigEntry('hash_mask'),
153                         $salt,
154                         $this->rngInstance->getFixedSalt(),
155                         $str
156                 ));
157
158                 // And return it
159                 return $hashed;
160         }
161
162         /**
163          * Encrypt the string with fixed salt
164          *
165          * @param       $str            The unencrypted string
166          * @return      $encrypted      Encrypted string
167          */
168         public function encryptString ($str) {
169                 // Init crypto module
170                 $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
171                 $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
172
173                 // Get key
174                 if ($this->getConfigInstance()->getConfigEntry('crypt_fixed_salt') == 'Y') {
175                         $key = md5($this->rngInstance->getFixedSalt());
176                 } else {
177                         $key = md5($this->rngInstance->getExtraSalt());
178                 }
179
180                 // Add some "garbage" to the string
181                 switch ($this->rngInstance->randomNumber(0, 8)) {
182                         case 0:
183                                 $garbageString = crc32($this->rngInstance->randomString(10)) . $this->seperator . base64_encode($str) . $this->seperator . crc32($this->rngInstance->randomString(20));
184                                 break;
185
186                         case 1:
187                                 $garbageString = crc32($this->rngInstance->randomString(10)) . $this->seperator . base64_encode($str) . $this->seperator . md5($this->rngInstance->randomString(20));
188                                 break;
189
190                         case 2:
191                                 $garbageString = crc32($this->rngInstance->randomString(10)) . $this->seperator . base64_encode($str) . $this->seperator . sha1($this->rngInstance->randomString(20));
192                                 break;
193
194                         case 3:
195                                 $garbageString = md5($this->rngInstance->randomString(10)) . $this->seperator . base64_encode($str) . $this->seperator . crc32($this->rngInstance->randomString(20));
196                                 break;
197
198                         case 4:
199                                 $garbageString = md5($this->rngInstance->randomString(10)) . $this->seperator . base64_encode($str) . $this->seperator . md5($this->rngInstance->randomString(20));
200                                 break;
201
202                         case 5:
203                                 $garbageString = md5($this->rngInstance->randomString(10)) . $this->seperator . base64_encode($str) . $this->seperator . sha1($this->rngInstance->randomString(20));
204                                 break;
205
206                         case 6:
207                                 $garbageString = sha1($this->rngInstance->randomString(10)) . $this->seperator . base64_encode($str) . $this->seperator . crc32($this->rngInstance->randomString(20));
208                                 break;
209
210                         case 7:
211                                 $garbageString = sha1($this->rngInstance->randomString(10)) . $this->seperator . base64_encode($str) . $this->seperator . md5($this->rngInstance->randomString(20));
212                                 break;
213
214                         case 8:
215                                 $garbageString = sha1($this->rngInstance->randomString(10)) . $this->seperator . base64_encode($str) . $this->seperator . sha1($this->rngInstance->randomString(20));
216                                 break;
217                 }
218
219                 // Encrypt the string
220                 $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $garbageString, MCRYPT_MODE_ECB, $iv);
221
222                 // Return the string
223                 return $encrypted;
224         }
225
226         /**
227          * Decrypt the string with fixed salt
228          *
229          * @param       $encrypted      Encrypted string
230          * @return      $str            The unencrypted string
231          */
232         public function decryptString ($encrypted) {
233                 // Init crypto module
234                 $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
235                 $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
236
237                 // Get key
238                 if ($this->getConfigInstance()->getConfigEntry('crypt_fixed_salt') == 'Y') {
239                         $key = md5($this->rngInstance->getFixedSalt());
240                 } else {
241                         $key = md5($this->rngInstance->getExtraSalt());
242                 }
243
244                 // Decrypt the string
245                 $garbageString = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_ECB, $iv);
246
247                 // Get the real string out
248                 $strArray = explode($this->seperator, $garbageString);
249
250                 // Does the element count match?
251                 assert(count($strArray) == 3);
252
253                 // Decode the string
254                 $str = base64_decode($strArray[1]);
255
256                 // Trim trailing nulls away
257                 $str = rtrim($str, "\0");
258
259                 // Return the string
260                 return $str;
261         }
262 }
263
264 // [EOF]
265 ?>