Use PHP polyfills
This commit is contained in:
parent
acce1638e5
commit
f3360d51c6
2
3rdparty
2
3rdparty
|
@ -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 = '';
|
||||
|
||||
while($length > 0) {
|
||||
$randomNumber = random_int(0, $maxCharIndex);
|
||||
$randomString .= $characters[$randomNumber];
|
||||
$length--;
|
||||
}
|
||||
|
||||
if(function_exists('random_int')) {
|
||||
$maxCharIndex = strlen($characters) - 1;
|
||||
$randomString = '';
|
||||
|
||||
while($length > 0) {
|
||||
$randomNumber = random_int(0, $maxCharIndex);
|
||||
$randomString .= $characters[$randomNumber];
|
||||
$length--;
|
||||
}
|
||||
return $randomString;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue