TYPO3 CMS  TYPO3_8-7
Pbkdf2SaltTest.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
19 
23 class Pbkdf2SaltTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
24 {
30  protected $objectInstance = null;
31 
35  protected function setUp()
36  {
37  $this->objectInstance = $this->getMockBuilder(Pbkdf2Salt::class)
38  ->setMethods(['dummy'])
39  ->getMock();
40  // Speed up the tests by reducing the iteration count
41  $this->objectInstance->setHashCount(1000);
42  }
43 
47  public function hasCorrectBaseClass()
48  {
49  $hasCorrectBaseClass = get_class($this->objectInstance) === Pbkdf2Salt::class;
50  // XCLASS ?
51  if (!$hasCorrectBaseClass && false != get_parent_class($this->objectInstance)) {
52  $hasCorrectBaseClass = is_subclass_of($this->objectInstance, Pbkdf2Salt::class);
53  }
54  $this->assertTrue($hasCorrectBaseClass);
55  }
56 
60  public function nonZeroSaltLength()
61  {
62  $this->assertTrue($this->objectInstance->getSaltLength() > 0);
63  }
64 
69  {
70  $password = '';
71  $this->assertNull($this->objectInstance->getHashedPassword($password));
72  }
73 
78  {
79  $password = 'a';
80  $this->assertNotNull($this->objectInstance->getHashedPassword($password));
81  }
82 
87  {
88  $password = 'password';
89  $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
90  $this->assertTrue($this->objectInstance->isValidSaltedPW($saltedHashPassword));
91  }
92 
97  {
98  $password = 'password';
99  // custom salt without setting
100  $randomBytes = (new Random())->generateRandomBytes($this->objectInstance->getSaltLength());
101  $salt = $this->objectInstance->base64Encode($randomBytes, $this->objectInstance->getSaltLength());
102  $this->assertTrue($this->objectInstance->isValidSalt($salt));
103  $saltedHashPassword = $this->objectInstance->getHashedPassword($password, $salt);
104  $this->assertTrue($this->objectInstance->isValidSaltedPW($saltedHashPassword));
105  }
106 
111  {
112  $password = 'password';
113  $minHashCount = $this->objectInstance->getMinHashCount();
114  $this->objectInstance->setHashCount($minHashCount);
115  $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
116  $this->assertTrue($this->objectInstance->isValidSaltedPW($saltedHashPassword));
117  // reset hashcount
118  $this->objectInstance->setHashCount(null);
119  }
120 
130  {
131  $password = 'password';
132  $saltedHashPassword = '$pbkdf2-sha256$1000$woPhT0yoWm3AXJXSjuxJ3w$iZ6EvTulMqXlzr0NO8z5EyrklFcJk5Uw2Fqje68FfaQ';
133  $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword));
134  }
135 
142  {
143  $password = 'password';
144  $saltedHashPassword = '$pbkdf2-sha256$1000$woPhT0yoWm3AXJXSjuxJ3w$iZ6EvTulMqXlzr0NO8z5EyrklFcJk5Uw2Fqje68Ffa';
145  $this->assertFalse($this->objectInstance->checkPassword($password, $saltedHashPassword));
146  }
147 
157  {
158  $password = 'aEjOtY';
159  $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
160  $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword));
161  }
162 
172  {
173  $password = '01369';
174  $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
175  $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword));
176  }
177 
187  {
188  $password = ' !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~';
189  $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
190  $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword));
191  }
192 
202  {
203  $password = '';
204  for ($i = 160; $i <= 191; $i++) {
205  $password .= chr($i);
206  }
207  $password .= chr(215) . chr(247);
208  $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
209  $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword));
210  }
211 
221  {
222  $password = '';
223  for ($i = 192; $i <= 214; $i++) {
224  $password .= chr($i);
225  }
226  for ($i = 216; $i <= 246; $i++) {
227  $password .= chr($i);
228  }
229  for ($i = 248; $i <= 255; $i++) {
230  $password .= chr($i);
231  }
232  $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
233  $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword));
234  }
235 
240  {
241  $password = 'password';
242  $password1 = $password . 'INVALID';
243  $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
244  $this->assertFalse($this->objectInstance->checkPassword($password1, $saltedHashPassword));
245  }
246 
251  {
252  $pad = 'a';
253  $criticalPwLength = 0;
254  // We're using a constant salt.
255  $saltedHashPasswordCurrent = $salt = $this->objectInstance->getHashedPassword($pad);
256  for ($i = 0; $i <= 128; $i += 8) {
257  $password = str_repeat($pad, max($i, 1));
258  $saltedHashPasswordPrevious = $saltedHashPasswordCurrent;
259  $saltedHashPasswordCurrent = $this->objectInstance->getHashedPassword($password, $salt);
260  if ($i > 0 && $saltedHashPasswordPrevious === $saltedHashPasswordCurrent) {
261  $criticalPwLength = $i;
262  break;
263  }
264  }
265  $this->assertTrue($criticalPwLength == 0 || $criticalPwLength > 32, 'Duplicates of hashed passwords with plaintext password of length ' . $criticalPwLength . '+.');
266  }
267 
271  public function modifiedMinHashCount()
272  {
273  $minHashCount = $this->objectInstance->getMinHashCount();
274  $this->objectInstance->setMinHashCount($minHashCount - 1);
275  $this->assertTrue($this->objectInstance->getMinHashCount() < $minHashCount);
276  $this->objectInstance->setMinHashCount($minHashCount + 1);
277  $this->assertTrue($this->objectInstance->getMinHashCount() > $minHashCount);
278  }
279 
283  public function modifiedMaxHashCount()
284  {
285  $maxHashCount = $this->objectInstance->getMaxHashCount();
286  $this->objectInstance->setMaxHashCount($maxHashCount + 1);
287  $this->assertTrue($this->objectInstance->getMaxHashCount() > $maxHashCount);
288  $this->objectInstance->setMaxHashCount($maxHashCount - 1);
289  $this->assertTrue($this->objectInstance->getMaxHashCount() < $maxHashCount);
290  }
291 
295  public function modifiedHashCount()
296  {
297  $hashCount = $this->objectInstance->getHashCount();
298  $this->objectInstance->setMaxHashCount($hashCount + 1);
299  $this->objectInstance->setHashCount($hashCount + 1);
300  $this->assertTrue($this->objectInstance->getHashCount() > $hashCount);
301  $this->objectInstance->setMinHashCount($hashCount - 1);
302  $this->objectInstance->setHashCount($hashCount - 1);
303  $this->assertTrue($this->objectInstance->getHashCount() < $hashCount);
304  // reset hashcount
305  $this->objectInstance->setHashCount(null);
306  }
307 
312  {
313  $password = 'password';
314  $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
315  $this->assertFalse($this->objectInstance->isHashUpdateNeeded($saltedHashPassword));
316  }
317 
322  {
323  $password = 'password';
324  $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
325  $increasedHashCount = $this->objectInstance->getHashCount() + 1;
326  $this->objectInstance->setMaxHashCount($increasedHashCount);
327  $this->objectInstance->setHashCount($increasedHashCount);
328  $this->assertTrue($this->objectInstance->isHashUpdateNeeded($saltedHashPassword));
329  // reset hashcount
330  $this->objectInstance->setHashCount(null);
331  }
332 
337  {
338  $password = 'password';
339  $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
340  $decreasedHashCount = $this->objectInstance->getHashCount() - 1;
341  $this->objectInstance->setMinHashCount($decreasedHashCount);
342  $this->objectInstance->setHashCount($decreasedHashCount);
343  $this->assertFalse($this->objectInstance->isHashUpdateNeeded($saltedHashPassword));
344  // reset hashcount
345  $this->objectInstance->setHashCount(null);
346  }
347 
352  {
353  $this->objectInstance->setMinHashCount(1000);
354  $passlibSaltedHash= '$pbkdf2-sha256$6400$.6UI/S.nXIk8jcbdHx3Fhg$98jZicV16ODfEsEZeYPGHU3kbrUrvUEXOPimVSQDD44';
355  $saltedHashPassword = $this->objectInstance->getHashedPassword('password', $passlibSaltedHash);
356 
357  $this->assertSame($passlibSaltedHash, $saltedHashPassword);
358  }
359 }