Comment header cosmetics applied
[shipsimu.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, this is free software
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          * Protected constructor
46          *
47          * @return      void
48          */
49         protected function __construct () {
50                 // Call parent constructor
51                 parent::__construct(__CLASS__);
52
53                 // Set part description
54                 $this->setObjectDescription("Cryptographical helper");
55
56                 // Create unique ID number
57                 $this->generateUniqueId();
58
59                 // Clean up a little
60                 $this->removeNumberFormaters();
61                 $this->removeSystemArray();
62         }
63
64         /**
65          * Creates an instance of this class
66          *
67          * @return      $cryptoInstance         An instance of this crypto helper class
68          */
69         public final static function createCryptoHelper () {
70                 // Get a new instance
71                 $cryptoInstance = new CryptoHelper();
72
73                 // Initialize the hasher
74                 $cryptoInstance->initHasher();
75
76                 // Return the instance
77                 return $cryptoInstance;
78         }
79
80         /**
81          * Get a singleton instance of this class
82          *
83          * @return      $selfInstance   An instance of this crypto helper class
84          */
85         public final static function getInstance () {
86                 // Is no instance there?
87                 if (is_null(self::$selfInstance)) {
88                         // Then get a new one
89                         self::$selfInstance = self::createCryptoHelper();
90                 }
91
92                 // Return the instance
93                 return self::$selfInstance;
94         }
95
96         /**
97          * Initializes the hasher for different purposes.
98          *
99          * @return      void
100          */
101         protected function initHasher () {
102                 // Initialize the random number generator which is required by some crypto methods
103                 $this->rngInstance = ObjectFactory::createObjectByConfiguredName('rng_class');
104
105                 // Generate a salt for the hasher
106                 $this->generateSalt();
107         }
108
109         /**
110          * Generates the salt based on configured length
111          *
112          * @return      void
113          */
114         private function generateSalt () {
115                 // Get a random string from the RNG
116                 $randomString = $this->rngInstance->randomString();
117
118                 // Get config entry for salt length
119                 $length = $this->getConfigInstance()->readConfig('salt_length');
120
121                 // Keep only defined number of characters
122                 $this->salt = substr(sha1($randomString), -$length, $length);
123         }
124
125         /**
126          * Hashes a string with salt and returns the hash. If an old previous hash
127          * is supplied the method will use the first X chars of that hash for hashing
128          * the password. This is useful if you want to check if the password is
129          * identical for authorization purposes.
130          *
131          * @param       $str            Unhashed string
132          * @param       $oldHash        A hash from previous hashed string
133          * @return      $hashed         The hashed and salted string
134          */
135         public function hashString ($str, $oldHash = "") {
136                 // Cast the string
137                 $str = (string) $str;
138
139                 // Is the old password set?
140                 if (empty($oldHash)) {
141                         // No, then use the current salt
142                         $salt = $this->salt;
143                 } else {
144                         // Use the salt from hash, first get length
145                         $length = $this->getConfigInstance()->readConfig('salt_length');
146
147                         // Then extract the X first characters from the hash as our salt
148                         $salt = substr($oldHash, 0, $length);
149                 }
150
151                 // Hash the password with salt
152                 //* DEBUG: */ echo "salt=".$salt."/plain=".$str."<br />\n";
153                 $hashed = $salt . md5(sprintf($this->getConfigInstance()->readConfig('hash_mask'),
154                         $salt,
155                         $this->rngInstance->getFixedSalt(),
156                         $str
157                 ));
158
159                 // And return it
160                 return $hashed;
161         }
162
163         /**
164          * Encrypt the string with fixed salt
165          *
166          * @param       $str            The unencrypted string
167          * @return      $encrypted      Encrypted string
168          */
169         public function encryptString ($str) {
170                 // Init crypto module
171                 $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
172                 $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
173
174                 // Get key
175                 if ($this->getConfigInstance()->readConfig('crypt_fixed_salt') === "Y") {
176                         $key = md5($this->rngInstance->getFixedSalt());
177                 } else {
178                         $key = md5($this->rngInstance->getExtraSalt());
179                 }
180
181                 // Add some "garbage" to the string
182                 switch ($this->rngInstance->randomNumber(0, 8)) {
183                         case 0:
184                                 $garbageString = crc32($this->rngInstance->randomString(10))."|".base64_encode($str)."|".crc32($this->rngInstance->randomString(20));
185                                 break;
186
187                         case 1:
188                                 $garbageString = crc32($this->rngInstance->randomString(10))."|".base64_encode($str)."|".md5($this->rngInstance->randomString(20));
189                                 break;
190
191                         case 2:
192                                 $garbageString = crc32($this->rngInstance->randomString(10))."|".base64_encode($str)."|".sha1($this->rngInstance->randomString(20));
193                                 break;
194
195                         case 3:
196                                 $garbageString = md5($this->rngInstance->randomString(10))."|".base64_encode($str)."|".crc32($this->rngInstance->randomString(20));
197                                 break;
198
199                         case 4:
200                                 $garbageString = md5($this->rngInstance->randomString(10))."|".base64_encode($str)."|".md5($this->rngInstance->randomString(20));
201                                 break;
202
203                         case 5:
204                                 $garbageString = md5($this->rngInstance->randomString(10))."|".base64_encode($str)."|".sha1($this->rngInstance->randomString(20));
205                                 break;
206
207                         case 6:
208                                 $garbageString = sha1($this->rngInstance->randomString(10))."|".base64_encode($str)."|".crc32($this->rngInstance->randomString(20));
209                                 break;
210
211                         case 7:
212                                 $garbageString = sha1($this->rngInstance->randomString(10))."|".base64_encode($str)."|".md5($this->rngInstance->randomString(20));
213                                 break;
214
215                         case 8:
216                                 $garbageString = sha1($this->rngInstance->randomString(10))."|".base64_encode($str)."|".sha1($this->rngInstance->randomString(20));
217                                 break;
218                 }
219
220                 // Encrypt the string
221                 $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $garbageString, MCRYPT_MODE_ECB, $iv);
222
223                 // Return the string
224                 return $encrypted;
225         }
226
227         /**
228          * Decrypt the string with fixed salt
229          *
230          * @param       $encrypted      Encrypted string
231          * @return      $str            The unencrypted string
232          */
233         public function decryptString ($encrypted) {
234                 // Init crypto module
235                 $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
236                 $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
237
238                 // Get key
239                 if ($this->getConfigInstance()->readConfig('crypt_fixed_salt') === "Y") {
240                         $key = md5($this->rngInstance->getFixedSalt());
241                 } else {
242                         $key = md5($this->rngInstance->getExtraSalt());
243                 }
244
245                 // Decrypt the string
246                 $garbageString = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_ECB, $iv);
247
248                 // Get the real string out
249                 $strArray = explode("|", $garbageString);
250                 $str = base64_decode($strArray[1]);
251
252                 // Trim trailing nulls away
253                 $str = rtrim($str, "\0");
254
255                 // Return the string
256                 return $str;
257         }
258 }
259
260 // [EOF]
261 ?>