@@ -1 +1 @@ | |||
Subproject commit a7b34d6f831c8fa363f389d27acd0150128fc0b9 | |||
Subproject commit 56934b1fc0f15760690c7a28c6c6429ce6ce6bef |
@@ -30,7 +30,6 @@ use OC\Encryption\Exceptions\DecryptionFailedException; | |||
use OC\Encryption\Exceptions\EncryptionFailedException; | |||
use OCA\Encryption\Exceptions\MultiKeyDecryptException; | |||
use OCA\Encryption\Exceptions\MultiKeyEncryptException; | |||
use OCA\Encryption\Vendor\PBKDF2Fallback; | |||
use OCP\Encryption\Exceptions\GenericEncryptionException; | |||
use OCP\IConfig; | |||
use OCP\ILogger; | |||
@@ -293,28 +292,14 @@ class Crypt { | |||
$salt = hash('sha256', $uid . $instanceId . $instanceSecret, true); | |||
$keySize = $this->getKeySize($cipher); | |||
if (function_exists('hash_pbkdf2')) { | |||
$hash = hash_pbkdf2( | |||
'sha256', | |||
$password, | |||
$salt, | |||
100000, | |||
$keySize, | |||
true | |||
); | |||
} else { | |||
// fallback to 3rdparty lib for PHP <= 5.4. | |||
// FIXME: Can be removed as soon as support for PHP 5.4 was dropped | |||
$fallback = new PBKDF2Fallback(); | |||
$hash = $fallback->pbkdf2( | |||
'sha256', | |||
$password, | |||
$salt, | |||
100000, | |||
$keySize, | |||
true | |||
); | |||
} | |||
$hash = hash_pbkdf2( | |||
'sha256', | |||
$password, | |||
$salt, | |||
100000, | |||
$keySize, | |||
true | |||
); | |||
return $hash; | |||
} |
@@ -1,87 +0,0 @@ | |||
<?php | |||
/* Note; This class can be removed as soon as we drop PHP 5.4 support. | |||
* | |||
* | |||
* Password Hashing With PBKDF2 (http://crackstation.net/hashing-security.htm). | |||
* Copyright (c) 2013, Taylor Hornby | |||
* All rights reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright notice, | |||
* this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions in binary form must reproduce the above copyright notice, | |||
* this list of conditions and the following disclaimer in the documentation | |||
* and/or other materials provided with the distribution. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
* POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
namespace OCA\Encryption\Vendor; | |||
class PBKDF2Fallback { | |||
/* | |||
* PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt | |||
* $algorithm - The hash algorithm to use. Recommended: SHA256 | |||
* $password - The password. | |||
* $salt - A salt that is unique to the password. | |||
* $count - Iteration count. Higher is better, but slower. Recommended: At least 1000. | |||
* $key_length - The length of the derived key in bytes. | |||
* $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise. | |||
* Returns: A $key_length-byte key derived from the password and salt. | |||
* | |||
* Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt | |||
* | |||
* This implementation of PBKDF2 was originally created by https://defuse.ca | |||
* With improvements by http://www.variations-of-shadow.com | |||
*/ | |||
public function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false) { | |||
$algorithm = strtolower($algorithm); | |||
if (!in_array($algorithm, hash_algos(), true)) | |||
trigger_error('PBKDF2 ERROR: Invalid hash algorithm.', E_USER_ERROR); | |||
if ($count <= 0 || $key_length <= 0) | |||
trigger_error('PBKDF2 ERROR: Invalid parameters.', E_USER_ERROR); | |||
if (function_exists("hash_pbkdf2")) { | |||
// The output length is in NIBBLES (4-bits) if $raw_output is false! | |||
if (!$raw_output) { | |||
$key_length = $key_length * 2; | |||
} | |||
return hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output); | |||
} | |||
$hash_length = strlen(hash($algorithm, "", true)); | |||
$block_count = ceil($key_length / $hash_length); | |||
$output = ""; | |||
for ($i = 1; $i <= $block_count; $i++) { | |||
// $i encoded as 4 bytes, big endian. | |||
$last = $salt . pack("N", $i); | |||
// first iteration | |||
$last = $xorsum = hash_hmac($algorithm, $last, $password, true); | |||
// perform the other $count - 1 iterations | |||
for ($j = 1; $j < $count; $j++) { | |||
$xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true)); | |||
} | |||
$output .= $xorsum; | |||
} | |||
if ($raw_output) | |||
return substr($output, 0, $key_length); | |||
else | |||
return bin2hex(substr($output, 0, $key_length)); | |||
} | |||
} |
@@ -139,7 +139,7 @@ class OCSAuthAPI { | |||
protected function isValidToken($url, $token) { | |||
$storedToken = $this->dbHandler->getToken($url); | |||
return StringUtils::equals($storedToken, $token); | |||
return hash_equals($storedToken, $token); | |||
} | |||
} |
@@ -447,7 +447,7 @@ class Request implements \ArrayAccess, \Countable, IRequest { | |||
$deobfuscatedToken = base64_decode($obfuscatedToken) ^ $secret; | |||
// Check if the token is valid | |||
if(\OCP\Security\StringUtils::equals($deobfuscatedToken, $this->items['requesttoken'])) { | |||
if(hash_equals($deobfuscatedToken, $this->items['requesttoken'])) { | |||
return true; | |||
} else { | |||
return false; |
@@ -227,7 +227,7 @@ class Log implements ILogger { | |||
$request = \OC::$server->getRequest(); | |||
// if token is found in the request change set the log condition to satisfied | |||
if($request && StringUtils::equals($request->getParam('log_secret'), $logCondition['shared_secret'])) { | |||
if($request && hash_equals($logCondition['shared_secret'], $request->getParam('log_secret'))) { | |||
$this->logConditionSatisfied = true; | |||
} | |||
} |
@@ -123,7 +123,7 @@ class Crypto implements ICrypto { | |||
$this->cipher->setIV($iv); | |||
if(!\OCP\Security\StringUtils::equals($this->calculateHMAC($parts[0].$parts[1], $password), $hmac)) { | |||
if(!hash_equals($this->calculateHMAC($parts[0].$parts[1], $password), $hmac)) { | |||
throw new \Exception('HMAC does not match.'); | |||
} | |||
@@ -109,7 +109,7 @@ class Hasher implements IHasher { | |||
// Verify whether it matches a legacy PHPass or SHA1 string | |||
$hashLength = strlen($hash); | |||
if($hashLength === 60 && password_verify($message.$this->legacySalt, $hash) || | |||
$hashLength === 40 && StringUtils::equals($hash, sha1($message))) { | |||
$hashLength === 40 && hash_equals($hash, sha1($message))) { | |||
$newHash = $this->hash($message); | |||
return true; | |||
} |
@@ -27,25 +27,15 @@ use Sabre\DAV\Exception; | |||
use OCP\Security\ISecureRandom; | |||
/** | |||
* Class SecureRandom provides a layer around RandomLib to generate | |||
* secure random strings. For PHP 7 the native CSPRNG is used. | |||
* Class SecureRandom provides a wrapper around the random_int function to generate | |||
* secure random strings. For PHP 7 the native CSPRNG is used, older versions do | |||
* use a fallback. | |||
* | |||
* Usage: | |||
* \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(10); | |||
* | |||
* \OC::$server->getSecureRandom()->generate(10); | |||
* @package OC\Security | |||
*/ | |||
class SecureRandom implements ISecureRandom { | |||
/** @var \RandomLib\Factory */ | |||
var $factory; | |||
/** @var \RandomLib\Generator */ | |||
var $generator; | |||
function __construct() { | |||
$this->factory = new RandomLib\Factory; | |||
} | |||
/** | |||
* Convenience method to get a low strength random number generator. | |||
* | |||
@@ -53,10 +43,10 @@ class SecureRandom implements ISecureRandom { | |||
* in a non-cryptographical setting. They are not strong enough to be | |||
* used as keys or salts. They are however useful for one-time use tokens. | |||
* | |||
* @deprecated 9.0.0 Use \OC\Security\SecureRandom::generate directly or random_bytes() / random_int() | |||
* @return $this | |||
*/ | |||
public function getLowStrengthGenerator() { | |||
$this->generator = $this->factory->getLowStrengthGenerator(); | |||
return $this; | |||
} | |||
@@ -67,10 +57,10 @@ class SecureRandom implements ISecureRandom { | |||
* They are strong enough to be used as keys and salts. However, they do | |||
* take some time and resources to generate, so they should not be over-used | |||
* | |||
* @deprecated 9.0.0 Use \OC\Security\SecureRandom::generate directly or random_bytes() / random_int() | |||
* @return $this | |||
*/ | |||
public function getMediumStrengthGenerator() { | |||
$this->generator = $this->factory->getMediumStrengthGenerator(); | |||
return $this; | |||
} | |||
@@ -80,26 +70,17 @@ class SecureRandom implements ISecureRandom { | |||
* @param string $characters An optional list of characters to use if no character list is | |||
* specified all valid base64 characters are used. | |||
* @return string | |||
* @throws \Exception If the generator is not initialized. | |||
*/ | |||
public function generate($length, | |||
$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/') { | |||
if(is_null($this->generator)) { | |||
throw new \Exception('Generator is not initialized.'); | |||
} | |||
$maxCharIndex = strlen($characters) - 1; | |||
$randomString = ''; | |||
if(function_exists('random_int')) { | |||
$maxCharIndex = strlen($characters) - 1; | |||
$randomString = ''; | |||
while($length > 0) { | |||
$randomNumber = random_int(0, $maxCharIndex); | |||
$randomString .= $characters[$randomNumber]; | |||
$length--; | |||
} | |||
return $randomString; | |||
while($length > 0) { | |||
$randomNumber = random_int(0, $maxCharIndex); | |||
$randomString .= $characters[$randomNumber]; | |||
$length--; | |||
} | |||
return $this->generator->generateString($length, $characters); | |||
return $randomString; | |||
} | |||
} |
@@ -1,60 +0,0 @@ | |||
<?php | |||
/** | |||
* @author Lukas Reschke <lukas@owncloud.com> | |||
* @author Morris Jobke <hey@morrisjobke.de> | |||
* | |||
* @copyright Copyright (c) 2015, ownCloud, Inc. | |||
* @license AGPL-3.0 | |||
* | |||
* This code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License, version 3, | |||
* as published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public License, version 3, | |||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
namespace OC\Security; | |||
class StringUtils { | |||
/** | |||
* Compares whether two strings are equal. To prevent guessing of the string | |||
* length this is done by comparing two hashes against each other and afterwards | |||
* a comparison of the real string to prevent against the unlikely chance of | |||
* collisions. | |||
* | |||
* Be aware that this function may leak whether the string to compare have a different | |||
* length. | |||
* | |||
* @param string $expected The expected value | |||
* @param string $input The input to compare against | |||
* @return bool True if the two strings are equal, otherwise false. | |||
*/ | |||
public static function equals($expected, $input) { | |||
if(!is_string($expected) || !is_string($input)) { | |||
return false; | |||
} | |||
if(function_exists('hash_equals')) { | |||
return hash_equals($expected, $input); | |||
} | |||
$randomString = \OC::$server->getSecureRandom()->getLowStrengthGenerator()->generate(10); | |||
if(hash('sha512', $expected.$randomString) === hash('sha512', $input.$randomString)) { | |||
if($expected === $input) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
} |
@@ -23,12 +23,12 @@ | |||
namespace OCP\Security; | |||
/** | |||
* Class SecureRandom provides a layer around RandomLib to generate | |||
* secure random strings. For PHP 7 the native CSPRNG is used. | |||
* Class SecureRandom provides a wrapper around the random_int function to generate | |||
* secure random strings. For PHP 7 the native CSPRNG is used, older versions do | |||
* use a fallback. | |||
* | |||
* Usage: | |||
* $rng = new \OC\Security\SecureRandom(); | |||
* $randomString = $rng->getMediumStrengthGenerator()->generateString(30); | |||
* \OC::$server->getSecureRandom()->generate(10); | |||
* | |||
* @package OCP\Security | |||
* @since 8.0.0 | |||
@@ -52,6 +52,7 @@ interface ISecureRandom { | |||
* | |||
* @return $this | |||
* @since 8.0.0 | |||
* @deprecated 9.0.0 Use \OC\Security\SecureRandom::generate directly or random_bytes() / random_int() | |||
*/ | |||
public function getLowStrengthGenerator(); | |||
@@ -64,6 +65,7 @@ interface ISecureRandom { | |||
* | |||
* @return $this | |||
* @since 8.0.0 | |||
* @deprecated 9.0.0 Use \OC\Security\SecureRandom::generate directly or random_bytes() / random_int() | |||
*/ | |||
public function getMediumStrengthGenerator(); | |||
@@ -73,7 +75,6 @@ interface ISecureRandom { | |||
* @param string $characters An optional list of characters to use if no character list is | |||
* specified all valid base64 characters are used. | |||
* @return string | |||
* @throws \Exception If the generator is not initialized. | |||
* @since 8.0.0 | |||
*/ | |||
public function generate($length, |
@@ -39,8 +39,9 @@ class StringUtils { | |||
* @param string $input The input to compare against | |||
* @return bool True if the two strings are equal, otherwise false. | |||
* @since 8.0.0 | |||
* @deprecated 9.0.0 Use hash_equals | |||
*/ | |||
public static function equals($expected, $input) { | |||
return \OC\Security\StringUtils::equals($expected, $input); | |||
return hash_equals($expected, $input); | |||
} | |||
} |
@@ -57,11 +57,10 @@ class SecureRandomTest extends \Test\TestCase { | |||
} | |||
/** | |||
* @expectedException \Exception | |||
* @expectedExceptionMessage Generator is not initialized | |||
* @dataProvider stringGenerationProvider | |||
*/ | |||
function testUninitializedGenerate() { | |||
$this->rng->generate(30); | |||
function testUninitializedGenerate($length, $expectedLength) { | |||
$this->assertEquals($expectedLength, strlen($this->rng->generate($length))); | |||
} | |||
/** |
@@ -1,38 +0,0 @@ | |||
<?php | |||
/** | |||
* Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or | |||
* later. | |||
* See the COPYING-README file. | |||
*/ | |||
use \OC\Security\StringUtils; | |||
class StringUtilsTest extends \Test\TestCase { | |||
public function dataProvider() | |||
{ | |||
return array( | |||
array('Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.', 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.'), | |||
array('', ''), | |||
array('我看这本书。 我看這本書', '我看这本书。 我看這本書'), | |||
array('GpKY9fSnWNJbES99zVGvA', 'GpKY9fSnWNJbES99zVGvA') | |||
); | |||
} | |||
/** | |||
* @dataProvider dataProvider | |||
*/ | |||
function testWrongEquals($string) { | |||
$this->assertFalse(StringUtils::equals($string, 'A Completely Wrong String')); | |||
$this->assertFalse(StringUtils::equals($string, null)); | |||
} | |||
/** | |||
* @dataProvider dataProvider | |||
*/ | |||
function testTrueEquals($string, $expected) { | |||
$this->assertTrue(StringUtils::equals($string, $expected)); | |||
} | |||
} |