Skip to content

Commit

Permalink
Drops mcrypt (Azure#991)
Browse files Browse the repository at this point in the history
* Adds support for random_bytes (PHP>=7.0)

* Remove mcrypt usage from getGuid

* Replace mt_rand with random_int implementation

- This implementation is same as https://github.com/paragonie/random_compat/blob/master/lib/random_int.php
- Fixes Azure#918

* Replace mcrypt_encrypt with openssl_encrypt
  • Loading branch information
captn3m0 authored and sergey-shandar committed Dec 3, 2018
1 parent 30d469c commit 1e4eb9d
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 55 deletions.
125 changes: 81 additions & 44 deletions src/Common/Internal/Utilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -532,35 +532,31 @@ public static function tryGetValueInsensitive($key, array $haystack, $default =
*
* See http://tools.ietf.org/html/rfc4122 for more information.
*
* Note: This function is available on all platforms, while the
* com_create_guid() is only available for Windows.
* Note: See https://stackoverflow.com/a/15875555
*
* @static
*
* @return string A new GUID
*/
public static function getGuid()
{
// @codingStandardsIgnoreStart

return sprintf(
'%04x%04x-%04x-%04x-%02x%02x-%04x%04x%04x',
mt_rand(0, 65535),
mt_rand(0, 65535), // 32 bits for "time_low"
mt_rand(0, 65535), // 16 bits for "time_mid"
mt_rand(0, 4096) + 16384, // 16 bits for "time_hi_and_version", with
// the most significant 4 bits being 0100
// to indicate randomly generated version
mt_rand(0, 64) + 128, // 8 bits for "clock_seq_hi", with
// the most significant 2 bits being 10,
// required by version 4 GUIDs.
mt_rand(0, 256), // 8 bits for "clock_seq_low"
mt_rand(0, 65535), // 16 bits for "node 0" and "node 1"
mt_rand(0, 65535), // 16 bits for "node 2" and "node 3"
mt_rand(0, 65535) // 16 bits for "node 4" and "node 5"
);
$data = self::generateCryptoKey(16);

$data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100b = 4
$data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10

return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}


// @codingStandardsIgnoreEnd
/**
* Generates a GUID provided a 16 byte pseudo random string
* @param string $data 16 bytes long data string
* @return string A new GUID
*/
private static function generateGuid($data)
{
return $guid;
}

/**
Expand Down Expand Up @@ -645,7 +641,59 @@ public static function getEntityId($entity, $type, $method = 'getId')
*/
public static function generateCryptoKey($length)
{
return openssl_random_pseudo_bytes($length);
// PHP>=7.0
if (function_exists('random_bytes')) {
return random_bytes($length);
}

$buf = openssl_random_pseudo_bytes($length, $secure);

if ($buf !== false) {
return $buf;
}

throw new \Exception('PRNG failure');
}

/**
* Fetch a random integer between $min and $max inclusive
* @param int $min
* @param int $max
* @return int
*/
public static function generateRandomInt($min, $max)
{
$range = $max - $min;
$bits = $bytes = $mask = $val = 0;
while ($range > 0) {
if ($bits % 8 === 0) {
++$bytes;
}
++$bits;
$range >>= 1;
$mask = $mask << 1 | 1;
}
$valueShift = $min;

do {
if ($attempts > 128) {
throw new \Exception('Could not generate valid random integer');
}
$randomByteString = self::generateCryptoKey($bytes);

$val = 0;
for ($i = 0; $i < $bytes; ++$i) {
$val |= ord($randomByteString[$i]) << ($i * 8);
}

$val &= $mask;
$val += $valueShift;

++$attempts;

} while (!is_int($val) || $val > $max || $val < $min);

return (int) $val;
}

/**
Expand Down Expand Up @@ -673,30 +721,13 @@ public static function ctrCrypt($data, $key, $initializationVector)
sprintf(Resources::INVALID_STRING_LENGTH, 'initializationVector', '16')
);

$blockCount = ceil(strlen($data) / 16);

$ctrData = '';
for ($i = 0; $i < $blockCount; ++$i) {
$ctrData .= $initializationVector;

// increment Initialization Vector
$j = 15;
do {
$digit = ord($initializationVector[$j]) + 1;
$initializationVector[$j] = chr($digit & 0xFF);

--$j;
} while (($digit == 0x100) && ($j >= 0));
}

$encryptCtrData = mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
return openssl_encrypt(
$data,
'aes-256-ctr',
$key,
$ctrData,
MCRYPT_MODE_ECB
OPENSSL_RAW_DATA,
$initializationVector
);

return $data ^ $encryptCtrData;
}

/**
Expand All @@ -720,6 +751,12 @@ public static function base256ToDec($number)
return $result;
}

/**
* Replace all hex characters in a string with lowercase
* and URL encode the resulting string.
* @param string $str input string
* @return string URL Encoded string with 00-FF replaced with 00-ff
*/
public static function lowerUrlencode($str)
{
return preg_replace_callback('/%[0-9A-F]{2}/',
Expand Down
7 changes: 1 addition & 6 deletions src/MediaServices/Models/ContentKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -402,12 +402,7 @@ private function _generateChecksum($aesKey, $usePadding = false)
$aesKey = $this->pkcs5_pad($aesKey, 16);
}

$encrypted = mcrypt_encrypt(
MCRYPT_RIJNDAEL_128, // AES
$aesKey,
$this->_id,
MCRYPT_MODE_ECB
);
$encrypted = openssl_encrypt($this->_id, 'aes-256-ecb', $aesKey, OPENSSL_RAW_DATA);

$this->_checksum = base64_encode(substr($encrypted, 0, 8));
}
Expand Down
3 changes: 2 additions & 1 deletion tests/framework/MediaServicesRestProxyTestBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
use WindowsAzure\Common\Internal\Http\Url;
use WindowsAzure\Common\Internal\Http\HttpClient;
use WindowsAzure\Common\Internal\Resources;
use WindowsAzure\Common\Internal\Utilities;

/**
* TestBase class for each unit test class.
Expand Down Expand Up @@ -419,7 +420,7 @@ function startsWith($haystack, $needle) {

protected function createSuffix()
{
return sprintf('-%04x', mt_rand(0, 65535));
return sprintf('-%04x', Utilities::generateRandomInt(0, 65535));
}

protected function createLargeFile()
Expand Down
3 changes: 2 additions & 1 deletion tests/framework/RestProxyTestBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

use WindowsAzure\Common\Internal\Logger;
use WindowsAzure\Common\Internal\Serialization\XmlSerializer;
use WindowsAzure\Common\Internal\Utilities;
use WindowsAzure\Common\ServicesBuilder;
use PHPUnit\Framework\TestCase;

Expand All @@ -52,7 +53,7 @@ class RestProxyTestBase extends TestCase

protected function getTestName()
{
return sprintf('onesdkphp%04x', mt_rand(0, 65535));
return sprintf('onesdkphp%04x', Utilities::generateRandomInt(0, 65535));
}

public static function assertHandler($file, $line, $code)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
use MicrosoftAzure\Storage\Common\Models\Metrics;
use MicrosoftAzure\Storage\Common\Models\RetentionPolicy;
use MicrosoftAzure\Storage\Common\Models\ServiceProperties;
use WindowsAzure\Common\Internal\Utilities;

class BlobServiceFunctionalTestData
{
Expand All @@ -61,7 +62,7 @@ class BlobServiceFunctionalTestData

public static function setupData($accountName)
{
$rInt = mt_rand(0, 1000000);
$rInt = Utilities::generateRandomInt(0, 1000000);
self::$_accountName = $accountName;
self::$testUniqueId = 'qa-'.$rInt.'-';
self::$nonExistContainerPrefix = 'qa-'.($rInt. 1).'-';
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/WindowsAzure/Common/Internal/UtilitiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -605,8 +605,8 @@ public function testCtrCrypt()
$initializationVector = str_pad($efectiveInitializationVector, 16, chr(255));

// Test
$ecnrypted = Utilities::ctrCrypt($data, $key, $initializationVector);
$decrypted = Utilities::ctrCrypt($ecnrypted, $key, $initializationVector);
$encrypted = Utilities::ctrCrypt($data, $key, $initializationVector);
$decrypted = Utilities::ctrCrypt($encrypted, $key, $initializationVector);

// Assert
$this->assertEquals($data, $decrypted);
Expand Down

0 comments on commit 1e4eb9d

Please sign in to comment.