b1ce4776e16f563aad1ad36574aea06368659615
[Packages/TYPO3.CMS.git] / typo3 / sysext / saltedpasswords / Classes / Salt / Md5Salt.php
1 <?php
2 namespace TYPO3\CMS\Saltedpasswords\Salt;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2009-2013 Marcus Krause <marcus#exp2009@t3sec.info>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * 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 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * Contains class "tx_saltedpasswords_salts_md5"
31 * that provides MD5 salted hashing.
32 */
33 /**
34 * Class that implements MD5 salted hashing based on PHP's
35 * crypt() function.
36 *
37 * MD5 salted hashing with PHP's crypt() should be available
38 * on most of the systems.
39 *
40 * @author Marcus Krause <marcus#exp2009@t3sec.info>
41 * @since 2009-09-06
42 */
43 class Md5Salt extends \TYPO3\CMS\Saltedpasswords\Salt\AbstractSalt implements \TYPO3\CMS\Saltedpasswords\Salt\SaltInterface {
44
45 /**
46 * Keeps a string for mapping an int to the corresponding
47 * base 64 character.
48 */
49 const ITOA64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
50 /**
51 * Keeps length of a MD5 salt in bytes.
52 *
53 * @var integer
54 */
55 static protected $saltLengthMD5 = 6;
56
57 /**
58 * Keeps suffix to be appended to a salt.
59 *
60 * @var string
61 */
62 static protected $saltSuffixMD5 = '$';
63
64 /**
65 * Setting string to indicate type of hashing method (md5).
66 *
67 * @var string
68 */
69 static protected $settingMD5 = '$1$';
70
71 /**
72 * Method applies settings (prefix, suffix) to a salt.
73 *
74 * @param string $salt A salt to apply setting to
75 * @return string Salt with setting
76 */
77 protected function applySettingsToSalt($salt) {
78 $saltWithSettings = $salt;
79 $reqLenBase64 = $this->getLengthBase64FromBytes($this->getSaltLength());
80 // Salt without setting
81 if (strlen($salt) == $reqLenBase64) {
82 $saltWithSettings = $this->getSetting() . $salt . $this->getSaltSuffix();
83 }
84 return $saltWithSettings;
85 }
86
87 /**
88 * Method checks if a given plaintext password is correct by comparing it with
89 * a given salted hashed password.
90 *
91 * @param string $plainPW plain-text password to compare with salted hash
92 * @param string $saltedHashPW salted hash to compare plain-text password with
93 * @return boolean TRUE, if plain-text password matches the salted hash, otherwise FALSE
94 */
95 public function checkPassword($plainPW, $saltedHashPW) {
96 $isCorrect = FALSE;
97 if ($this->isValidSalt($saltedHashPW)) {
98 $isCorrect = crypt($plainPW, $saltedHashPW) == $saltedHashPW;
99 }
100 return $isCorrect;
101 }
102
103 /**
104 * Generates a random base 64-encoded salt prefixed and suffixed with settings for the hash.
105 *
106 * Proper use of salts may defeat a number of attacks, including:
107 * - The ability to try candidate passwords against multiple hashes at once.
108 * - The ability to use pre-hashed lists of candidate passwords.
109 * - The ability to determine whether two users have the same (or different)
110 * password without actually having to guess one of the passwords.
111 *
112 * @return string A character string containing settings and a random salt
113 */
114 protected function getGeneratedSalt() {
115 $randomBytes = \TYPO3\CMS\Core\Utility\GeneralUtility::generateRandomBytes($this->getSaltLength());
116 return $this->base64Encode($randomBytes, $this->getSaltLength());
117 }
118
119 /**
120 * Method creates a salted hash for a given plaintext password
121 *
122 * @param string $password plaintext password to create a salted hash from
123 * @param string $salt Optional custom salt with setting to use
124 * @return string Salted hashed password
125 */
126 public function getHashedPassword($password, $salt = NULL) {
127 $saltedPW = NULL;
128 if (!empty($password)) {
129 if (empty($salt) || !$this->isValidSalt($salt)) {
130 $salt = $this->getGeneratedSalt();
131 }
132 $saltedPW = crypt($password, $this->applySettingsToSalt($salt));
133 }
134 return $saltedPW;
135 }
136
137 /**
138 * Returns a string for mapping an int to the corresponding base 64 character.
139 *
140 * @return string String for mapping an int to the corresponding base 64 character
141 */
142 protected function getItoa64() {
143 return self::ITOA64;
144 }
145
146 /**
147 * Returns wether all prequesites for the hashing methods are matched
148 *
149 * @return boolean Method available
150 */
151 public function isAvailable() {
152 return CRYPT_MD5;
153 }
154
155 /**
156 * Returns length of a MD5 salt in bytes.
157 *
158 * @return integer Length of a MD5 salt in bytes
159 */
160 public function getSaltLength() {
161 return self::$saltLengthMD5;
162 }
163
164 /**
165 * Returns suffix to be appended to a salt.
166 *
167 * @return string Suffix of a salt
168 */
169 protected function getSaltSuffix() {
170 return self::$saltSuffixMD5;
171 }
172
173 /**
174 * Returns setting string of MD5 salted hashes.
175 *
176 * @return string Setting string of MD5 salted hashes
177 */
178 public function getSetting() {
179 return self::$settingMD5;
180 }
181
182 /**
183 * Checks whether a user's hashed password needs to be replaced with a new hash.
184 *
185 * This is typically called during the login process when the plain text
186 * password is available. A new hash is needed when the desired iteration
187 * count has changed through a change in the variable $hashCount or
188 * HASH_COUNT or if the user's password hash was generated in an bulk update
189 * with class ext_update.
190 *
191 * @param string $passString Salted hash to check if it needs an update
192 * @return boolean TRUE if salted hash needs an update, otherwise FALSE
193 */
194 public function isHashUpdateNeeded($passString) {
195 return FALSE;
196 }
197
198 /**
199 * Method determines if a given string is a valid salt
200 *
201 * @param string $salt String to check
202 * @return boolean TRUE if it's valid salt, otherwise FALSE
203 */
204 public function isValidSalt($salt) {
205 $isValid = ($skip = FALSE);
206 $reqLenBase64 = $this->getLengthBase64FromBytes($this->getSaltLength());
207 if (strlen($salt) >= $reqLenBase64) {
208 // Salt with prefixed setting
209 if (!strncmp('$', $salt, 1)) {
210 if (!strncmp($this->getSetting(), $salt, strlen($this->getSetting()))) {
211 $isValid = TRUE;
212 $salt = substr($salt, strlen($this->getSetting()));
213 } else {
214 $skip = TRUE;
215 }
216 }
217 // Checking base64 characters
218 if (!$skip && strlen($salt) >= $reqLenBase64) {
219 if (preg_match('/^[' . preg_quote($this->getItoa64(), '/') . ']{' . $reqLenBase64 . ',' . $reqLenBase64 . '}$/', substr($salt, 0, $reqLenBase64))) {
220 $isValid = TRUE;
221 }
222 }
223 }
224 return $isValid;
225 }
226
227 /**
228 * Method determines if a given string is a valid salted hashed password.
229 *
230 * @param string $saltedPW String to check
231 * @return boolean TRUE if it's valid salted hashed password, otherwise FALSE
232 */
233 public function isValidSaltedPW($saltedPW) {
234 $isValid = FALSE;
235 $isValid = !strncmp($this->getSetting(), $saltedPW, strlen($this->getSetting())) ? TRUE : FALSE;
236 if ($isValid) {
237 $isValid = $this->isValidSalt($saltedPW);
238 }
239 return $isValid;
240 }
241
242 }
243
244
245 ?>