830c23cc52c660326a047c629c6e320567abcf90
[core.git] / framework / main / classes / crypto / class_CryptoHelper.php
1 <?php
2 // Own namespace
3 namespace Org\Mxchange\CoreFramework\Helper\Crypto;
4
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Crypto\Cryptable;
7 use Org\Mxchange\CoreFramework\Factory\ObjectFactory;
8 use Org\Mxchange\CoreFramework\Object\BaseFrameworkSystem;
9
10 /**
11  * A helper class for cryptographical things like hashing passwords and so on
12  *
13  * @author              Roland Haeder <webmaster@shipsimu.org>
14  * @version             0.0.0
15 <<<<<<< HEAD:framework/main/classes/crypto/class_CryptoHelper.php
16  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2017 Core Developer Team
17 =======
18  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2016 Core Developer Team
19 >>>>>>> Some updates::inc/main/classes/crypto/class_CryptoHelper.php
20  * @license             GNU GPL 3.0 or any newer version
21  * @link                http://www.shipsimu.org
22  *
23  * This program is free software: you can redistribute it and/or modify
24  * it under the terms of the GNU General Public License as published by
25  * the Free Software Foundation, either version 3 of the License, or
26  * (at your option) any later version.
27  *
28  * This program is distributed in the hope that it will be useful,
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31  * GNU General Public License for more details.
32  *
33  * You should have received a copy of the GNU General Public License
34  * along with this program. If not, see <http://www.gnu.org/licenses/>.
35  */
36 class CryptoHelper extends BaseFrameworkSystem implements Cryptable {
37         // Exception constants
38         const EXCEPTION_ENCRYPT_MISSING = 0x1f0;
39         const EXCEPTION_ENCRYPT_INVALID = 0x1f1;
40
41         /**
42          * An instance of this own clas
43          */
44         private static $selfInstance = NULL;
45
46         /**
47          * Instance of the crypto stream
48          */
49         private $cryptoStreamInstance = NULL;
50
51         /**
52          * Salt for hashing operations
53          */
54         private $salt = '';
55
56         /**
57          * Protected constructor
58          *
59          * @return      void
60          */
61         protected function __construct () {
62                 // Call parent constructor
63                 parent::__construct(__CLASS__);
64         }
65
66         /**
67          * Creates an instance of this class
68          *
69          * @return      $cryptoInstance         An instance of this crypto helper class
70          */
71         public static final function createCryptoHelper () {
72                 // Get a new instance
73                 $cryptoInstance = new CryptoHelper();
74
75                 // Initialize the hasher
76                 $cryptoInstance->initHasher();
77
78                 // Attach a crypto stream
79                 $cryptoInstance->attachCryptoStream();
80
81                 // Return the instance
82                 return $cryptoInstance;
83         }
84
85         /**
86          * Get a singleton instance of this class
87          *
88          * @return      $selfInstance   An instance of this crypto helper class
89          */
90         public static final function getSelfInstance () {
91                 // Is no instance there?
92                 if (is_null(self::$selfInstance)) {
93                         // Then get a new one
94                         self::$selfInstance = self::createCryptoHelper();
95                 } // END - if
96
97                 // Return the instance
98                 return self::$selfInstance;
99         }
100
101         /**
102          * Attaches a crypto stream to this crypto helper by detecting loaded
103          * modules.
104          *
105          * @return      void
106          */
107         protected function attachCryptoStream () {
108                 // @TODO Maybe rewrite this with DirectoryIterator, similar to Compressor thing?
109                 // Do we have openssl/mcrypt loaded?
110                 if ($this->isPhpExtensionLoaded('mcrypt')) {
111                         // Then use it
112                         $this->cryptoStreamInstance = ObjectFactory::createObjectByName('Org\Mxchange\CoreFramework\Stream\Crypto\McryptStream', array($this->getRngInstance()));
113                 } elseif ($this->isPhpExtensionLoaded('openssl')) {
114                         // Then use it
115                         $this->cryptoStreamInstance = ObjectFactory::createObjectByName('Org\Mxchange\CoreFramework\Stream\Crypto\OpenSslStream', array($this->getRngInstance()));
116                 } else {
117                         // If nothing works ...
118                         $this->cryptoStreamInstance = ObjectFactory::createObjectByName('Org\Mxchange\CoreFramework\Stream\Crypto\NullCryptoStream');
119                 }
120         }
121
122         /**
123          * Initializes the hasher for different purposes.
124          *
125          * @return      void
126          */
127         protected function initHasher () {
128                 // Initialize the random number generator which is required by some crypto methods
129                 $this->setRngInstance(ObjectFactory::createObjectByConfiguredName('rng_class'));
130
131                 // Generate a salt for the hasher
132                 $this->generateSalt();
133         }
134
135         /**
136          * Generates the salt based on configured length
137          *
138          * @return      void
139          */
140         private function generateSalt () {
141                 // Get a random string from the RNG
142                 $randomString = $this->getRngInstance()->randomString() . $this->createUuid();
143
144                 // Get config entry for salt length
145                 $length = $this->getConfigInstance()->getConfigEntry('salt_length');
146
147                 // Keep only defined number of characters
148                 $this->salt = substr(sha1($randomString), -$length, $length);
149         }
150
151         /**
152          * Returns a UUID (Universal Unique IDentifier) if PECL extension uuid was
153          * found or an empty string it not.
154          *
155          * @return      $uuid   UUID with leading dash or empty string
156          */
157         public function createUuid () {
158                 // Init empty UUID
159                 $uuid = '';
160
161                 // Is the UUID extension loaded and enabled? (see pecl)
162                 if ($this->getConfigInstance()->getConfigEntry('extension_uuid_loaded') === true) {
163                         // Then add it as well
164                         $uuid = uuid_create();
165                 } // END - if
166
167                 // Return it
168                 return $uuid;
169         }
170
171         /**
172          * Hashes a string with salt and returns the hash. If an old previous hash
173          * is supplied the method will use the first X chars of that hash for hashing
174          * the password. This is useful if you want to check if password is identical
175          * for authorization purposes.
176          *
177          * @param       $str            Unhashed string
178          * @param       $oldHash        A hash from previous hashed string
179          * @param       $withFixed      Whether to include a fixed salt (not recommended in p2p applications)
180          * @return      $hashed         The hashed and salted string
181          */
182         public function hashString ($str, $oldHash = '', $withFixed = true) {
183                 // Cast the string
184                 $str = (string) $str;
185
186                 // Default is the default salt ;-)
187                 $salt = $this->salt;
188
189                 // Is the old password set?
190                 if (!empty($oldHash)) {
191                         // Use the salt from hash, first get length
192                         $length = $this->getConfigInstance()->getConfigEntry('salt_length');
193
194                         // Then extract the X first characters from the hash as our salt
195                         $salt = substr($oldHash, 0, $length);
196                 } // END - if
197
198                 // Hash the password with salt
199                 //* DEBUG: */ echo "salt=".$salt."/plain=".$str."<br />\n";
200                 if ($withFixed === true) {
201                         // Use additional fixed salt
202                         $hashed = $salt . md5(sprintf($this->getConfigInstance()->getConfigEntry('hash_extra_mask'),
203                                 $salt,
204                                 $this->getRngInstance()->getFixedSalt(),
205                                 $str
206                         ));
207                 } else {
208                         // Use salt+string to hash
209                         $hashed = $salt . md5(sprintf($this->getConfigInstance()->getConfigEntry('hash_normal_mask'),
210                                 $salt,
211                                 $str
212                         ));
213                 }
214
215                 // And return it
216                 return $hashed;
217         }
218
219         /**
220          * Encrypt the string with fixed salt
221          *
222          * @param       $str            The unencrypted string
223          * @param       $key            Optional key, if none provided, a random key will be generated
224          * @return      $encrypted      Encrypted string
225          */
226         public function encryptString ($str, $key = NULL) {
227                 // Encrypt the string through the stream
228                 $encrypted = $this->cryptoStreamInstance->encryptStream($str, $key);
229
230                 // Return the string
231                 return $encrypted;
232         }
233
234         /**
235          * Decrypt the string with fixed salt
236          *
237          * @param       $encrypted      Encrypted string
238          * @return      $str            The unencrypted string
239          */
240         public function decryptString ($encrypted) {
241                 // Encrypt the string through the stream
242                 $str = $this->cryptoStreamInstance->decryptStream($encrypted);
243
244                 // Return the string
245                 return $str;
246         }
247
248 }