mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-12 23:14:18 +01:00
426 lines
12 KiB
PHP
426 lines
12 KiB
PHP
<?php
|
|
// Copyright (C) 2010-2024 Combodo SAS
|
|
//
|
|
// This file is part of iTop.
|
|
//
|
|
// iTop is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// iTop 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
|
|
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
|
|
|
/**
|
|
* SimpleCrypt Class - crypto helpers
|
|
* Simple encryption of strings, uses mcrypt or degrades to a pure PHP
|
|
* implementation when mcrypt is not present.
|
|
* Based on Miguel Ros' work found at:
|
|
* http://rossoft.wordpress.com/2006/05/22/simple-encryption-class/
|
|
*
|
|
* Usage:
|
|
* $oSimpleCrypt = new SimpleCrypt();
|
|
* $encrypted = $oSimpleCrypt->encrypt('a_key','the_text');
|
|
* $sClearText = $oSimpleCrypt->decrypt('a_key',$encrypted);
|
|
*
|
|
* The result is $plain equals to 'the_text'
|
|
*
|
|
* You can use a different engine if you don't have Mcrypt:
|
|
* $oSimpleCrypt = new SimpleCrypt('Simple');
|
|
*
|
|
* A string encrypted with one engine can't be decrypted with
|
|
* a different one even if the key is the same.
|
|
*
|
|
* @author Miguel Ros <rossoft@gmail.com>
|
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
|
* @license http://opensource.org/licenses/AGPL-3.0
|
|
*/
|
|
|
|
class SimpleCrypt
|
|
{
|
|
/**
|
|
* @var \SimpleCrypt
|
|
* @since 3.1.0 N°5388
|
|
*/
|
|
protected $oEngine;
|
|
|
|
public static function GetNewDefaultParams()
|
|
{
|
|
if(function_exists('sodium_crypto_secretbox_open') && function_exists('random_bytes')){
|
|
$sEngineName = 'Sodium';
|
|
}
|
|
else if (function_exists('openssl_decrypt'))
|
|
{
|
|
$sEngineName = 'OpenSSL';
|
|
}
|
|
else if(function_exists('mcrypt_module_open')){
|
|
$sEngineName = 'Mcrypt';
|
|
}
|
|
else
|
|
{
|
|
$sEngineName = 'Simple';
|
|
}
|
|
$sEngineName = 'SimpleCrypt' . $sEngineName . 'Engine';
|
|
return $sEngineName::GetNewDefaultParams();
|
|
}
|
|
|
|
/**
|
|
* Constructor
|
|
* @param string $sEngineName Engine for encryption. Values: Simple, Mcrypt, Sodium or OpenSSL
|
|
* @throws Exception This library is unkown
|
|
*/
|
|
function __construct($sEngineName = 'Mcrypt')
|
|
{
|
|
switch($sEngineName){
|
|
case 'Sodium':
|
|
if(!function_exists('sodium_crypto_secretbox_open')){
|
|
$sEngineName = 'Simple';
|
|
}
|
|
break;
|
|
case 'Mcrypt':
|
|
if(!function_exists('mcrypt_module_open')){
|
|
if (function_exists('openssl_decrypt'))
|
|
{
|
|
$sEngineName = 'OpenSSLMcryptCompatibility';
|
|
}
|
|
else
|
|
{
|
|
$sEngineName = 'Simple';
|
|
}
|
|
}
|
|
break;
|
|
case 'OpenSSL':
|
|
case 'OpenSSLMcryptCompatibility':
|
|
if(!function_exists('openssl_decrypt')){
|
|
$sEngineName = 'Simple';
|
|
}
|
|
break;
|
|
case 'Simple':
|
|
break;
|
|
default:
|
|
throw new Exception(Dict::Format("Core:AttributeEncryptUnknownLibrary", $sEngineName));
|
|
}
|
|
|
|
$sEngineName = 'SimpleCrypt' . $sEngineName . 'Engine';
|
|
$this->oEngine = new $sEngineName;
|
|
}
|
|
|
|
/**
|
|
* Encrypts the string with the given key
|
|
* @param string $key
|
|
* @param string $sString Plaintext string
|
|
* @return string Ciphered string
|
|
*/
|
|
function Encrypt($key, $sString)
|
|
{
|
|
return $this->oEngine->Encrypt($key,$sString);
|
|
}
|
|
|
|
|
|
/**
|
|
* Decrypts the string by the given key
|
|
* @param string $key
|
|
* @param string $string Ciphered string
|
|
* @return string Plaintext string
|
|
*/
|
|
function Decrypt($key, $string)
|
|
{
|
|
return $this->oEngine->Decrypt($key,$string);
|
|
}
|
|
|
|
/**
|
|
* Returns a random "salt" value, to be used when "hashing" a password
|
|
* using a one-way encryption algorithm, to prevent an attack using a "rainbow table"
|
|
* Tryes to use the best available random number generator
|
|
* @return string The generated random "salt"
|
|
*/
|
|
static function GetNewSalt()
|
|
{
|
|
// Copied from http://www.php.net/manual/en/function.mt-rand.php#83655
|
|
// get 128 pseudorandom bits in a string of 16 bytes
|
|
|
|
$sRandomBits = null;
|
|
|
|
// Unix/Linux platform?
|
|
$fp = @fopen('/dev/urandom','rb');
|
|
if ($fp !== FALSE)
|
|
{
|
|
//echo "Random bits pulled from /dev/urandom<br/>\n";
|
|
$sRandomBits .= @fread($fp,16);
|
|
@fclose($fp);
|
|
}
|
|
else
|
|
{
|
|
// MS-Windows platform?
|
|
if (@class_exists('COM'))
|
|
{
|
|
// http://msdn.microsoft.com/en-us/library/aa388176(VS.85).aspx
|
|
try
|
|
{
|
|
$CAPI_Util = new COM('CAPICOM.Utilities.1');
|
|
$sBase64RandomBits = ''.$CAPI_Util->GetRandom(16,0);
|
|
|
|
// if we ask for binary data PHP munges it, so we
|
|
// request base64 return value. We squeeze out the
|
|
// redundancy and useless ==CRLF by hashing...
|
|
if ($sBase64RandomBits)
|
|
{
|
|
//echo "Random bits got from CAPICOM.Utilities.1<br/>\n";
|
|
$sRandomBits = md5($sBase64RandomBits, TRUE);
|
|
}
|
|
}
|
|
catch (Exception $ex)
|
|
{
|
|
// echo 'Exception: ' . $ex->getMessage();
|
|
}
|
|
}
|
|
}
|
|
if ($sRandomBits == null)
|
|
{
|
|
// No "strong" random generator available, use PHP's built-in mechanism
|
|
//echo "Random bits generated from mt_rand<br/>\n";
|
|
mt_srand(crc32(microtime()));
|
|
$sRandomBits = '';
|
|
for($i = 0; $i < 4; $i++)
|
|
{
|
|
$sRandomBits .= sprintf('%04x', mt_rand(0, 65535));
|
|
}
|
|
|
|
|
|
}
|
|
return $sRandomBits;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Interface for encryption engines
|
|
*/
|
|
interface CryptEngine
|
|
{
|
|
public static function GetNewDefaultParams();
|
|
function Encrypt($key, $sString);
|
|
function Decrypt($key, $encrypted_data);
|
|
}
|
|
|
|
/**
|
|
* Simple Engine doesn't need any PHP extension.
|
|
* Every encryption of the same string with the same key
|
|
* will return the same encrypted string
|
|
*/
|
|
class SimpleCryptSimpleEngine implements CryptEngine
|
|
{
|
|
public static function GetNewDefaultParams()
|
|
{
|
|
return array( 'lib' => 'Simple', 'key' => null);
|
|
}
|
|
|
|
public function Encrypt($key, $sString)
|
|
{
|
|
$result = '';
|
|
for($i=1; $i<=strlen($sString); $i++)
|
|
{
|
|
$char = substr($sString, $i-1, 1);
|
|
$keychar = substr($key, ($i % strlen($key))-1, 1);
|
|
$char = chr(ord($char)+ord($keychar));
|
|
$result.=$char;
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
public function Decrypt($key, $encrypted_data)
|
|
{
|
|
$result = '';
|
|
for($i=1; $i<=strlen($encrypted_data); $i++)
|
|
{
|
|
$char = substr($encrypted_data, $i-1, 1);
|
|
$keychar = substr($key, ($i % strlen($key))-1, 1);
|
|
$char = chr(ord($char)-ord($keychar));
|
|
$result.=$char;
|
|
}
|
|
return $result;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* McryptEngine requires Mcrypt extension
|
|
* Every encryption of the same string with the same key
|
|
* will return a different encrypted string.
|
|
*/
|
|
class SimpleCryptMcryptEngine implements CryptEngine
|
|
{
|
|
var $alg = MCRYPT_BLOWFISH;
|
|
var $td = null;
|
|
|
|
public static function GetNewDefaultParams()
|
|
{
|
|
return array('lib' => 'Mcrypt', 'key' => null);
|
|
}
|
|
|
|
|
|
public function __construct()
|
|
{
|
|
$this->td = mcrypt_module_open($this->alg,'','cbc','');
|
|
}
|
|
|
|
public function Encrypt($key, $sString)
|
|
{
|
|
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($this->td), MCRYPT_DEV_URANDOM); // MCRYPT_DEV_URANDOM is now useable since itop requires php >= 5.6
|
|
if (false === $iv) {
|
|
throw new Exception('IV generation failed');
|
|
}
|
|
mcrypt_generic_init($this->td, $key, $iv);
|
|
if (empty($sString))
|
|
{
|
|
$sString = str_repeat("\0", 8);
|
|
}
|
|
$encrypted_data = mcrypt_generic($this->td, $sString);
|
|
mcrypt_generic_deinit($this->td);
|
|
return $iv.$encrypted_data;
|
|
}
|
|
|
|
public function Decrypt($key, $encrypted_data)
|
|
{
|
|
$iv = substr($encrypted_data, 0, mcrypt_enc_get_iv_size($this->td));
|
|
$string = substr($encrypted_data, mcrypt_enc_get_iv_size($this->td));
|
|
$r = mcrypt_generic_init($this->td, $key, $iv);
|
|
if (($r < 0) || ($r === false))
|
|
{
|
|
$decrypted_data = Dict::S("Core:AttributeEncryptFailedToDecrypt");
|
|
}
|
|
else
|
|
{
|
|
$decrypted_data = rtrim(mdecrypt_generic($this->td, $string), "\0");
|
|
mcrypt_generic_deinit($this->td);
|
|
}
|
|
return $decrypted_data;
|
|
}
|
|
|
|
public function __destruct()
|
|
{
|
|
mcrypt_module_close($this->td);
|
|
}
|
|
}
|
|
/**
|
|
* SodiumEngine requires Sodium extension
|
|
* Every encryption of the same string with the same key
|
|
* will return a different encrypted string.
|
|
* The key has to be SODIUM_CRYPTO_SECRETBOX_KEYBYTES bytes long.
|
|
*/
|
|
class SimpleCryptSodiumEngine implements CryptEngine
|
|
{
|
|
public static function GetNewDefaultParams()
|
|
{
|
|
return array('lib' => 'Sodium', 'key' => bin2hex(sodium_crypto_secretbox_keygen()));
|
|
}
|
|
|
|
public function Encrypt($key, $sString)
|
|
{
|
|
$key = hex2bin($key);
|
|
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
|
|
$encrypted_string = sodium_crypto_secretbox($sString, $nonce, $key);
|
|
sodium_memzero($sString);
|
|
sodium_memzero($key);
|
|
return base64_encode($nonce.$encrypted_string);
|
|
}
|
|
|
|
public function Decrypt($key, $encrypted_data)
|
|
{
|
|
$key = hex2bin($key);
|
|
$encrypted_data = base64_decode($encrypted_data);
|
|
$nonce = mb_substr($encrypted_data, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
|
|
$encrypted_data = mb_substr($encrypted_data, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
|
|
$plaintext = sodium_crypto_secretbox_open($encrypted_data, $nonce, $key);
|
|
if ($plaintext === false)
|
|
{
|
|
$plaintext = Dict::S("Core:AttributeEncryptFailedToDecrypt");
|
|
}
|
|
sodium_memzero($encrypted_data);
|
|
sodium_memzero($key);
|
|
return $plaintext;
|
|
}
|
|
|
|
}
|
|
class SimpleCryptOpenSSLEngine implements CryptEngine
|
|
{
|
|
public static function GetNewDefaultParams()
|
|
{
|
|
return array('lib' => 'OpenSSL', 'key' => bin2hex(openssl_random_pseudo_bytes(32)));
|
|
}
|
|
|
|
public function Encrypt($key, $sString)
|
|
{
|
|
$key = hex2bin($key);
|
|
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length("AES-256-CBC"));
|
|
$encrypted_string = openssl_encrypt($sString, "AES-256-CBC", $key, 0 , $iv);
|
|
return $iv.$encrypted_string;
|
|
}
|
|
|
|
public function Decrypt($key, $encrypted_data)
|
|
{
|
|
$key = hex2bin($key);
|
|
$iv = mb_substr($encrypted_data, 0, openssl_cipher_iv_length("AES-256-CBC"), '8bit');
|
|
$encrypted_data = mb_substr($encrypted_data, openssl_cipher_iv_length("AES-256-CBC"), null, '8bit');
|
|
$plaintext = openssl_decrypt($encrypted_data,"AES-256-CBC", $key, 0 , $iv);
|
|
if ($plaintext === false)
|
|
{
|
|
$plaintext = Dict::S("Core:AttributeEncryptFailedToDecrypt");
|
|
}
|
|
return trim($plaintext);
|
|
}
|
|
|
|
}
|
|
|
|
class SimpleCryptOpenSSLMcryptCompatibilityEngine implements CryptEngine
|
|
{
|
|
public static function GetNewDefaultParams()
|
|
{
|
|
return array('lib' => 'OpenSSLMcryptCompatibility', 'key' => null);
|
|
}
|
|
//fix for php < 7.1.8 (keys are Zero padded instead of cycle padded)
|
|
static private function MakeOpenSSLBlowfishKey($key)
|
|
{
|
|
if("$key" === '')
|
|
{
|
|
return $key;
|
|
}
|
|
$len = (16+2)*4;
|
|
while(strlen($key) < $len)
|
|
{
|
|
$key .= $key;
|
|
}
|
|
$key = substr($key, 0, $len);
|
|
return $key;
|
|
}
|
|
public function Encrypt($key, $sString)
|
|
{
|
|
$key = SimpleCryptOpenSSLMcryptCompatibilityEngine::MakeOpenSSLBlowfishKey($key);
|
|
$blockSize = 8;
|
|
$len = strlen($sString);
|
|
$paddingLen = intval (($len + $blockSize -1) / $blockSize) * $blockSize - $len;
|
|
$padding = str_repeat("\0", $paddingLen);
|
|
$sData = $sString . $padding;
|
|
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length("BF-CBC"));
|
|
$encrypted_string = openssl_encrypt($sData, "BF-CBC", $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
|
|
return $iv.$encrypted_string;
|
|
}
|
|
|
|
public function Decrypt($key, $encrypted_data)
|
|
{
|
|
$key = SimpleCryptOpenSSLMcryptCompatibilityEngine::MakeOpenSSLBlowfishKey($key);
|
|
$iv = mb_substr($encrypted_data, 0, openssl_cipher_iv_length("BF-CBC"), '8bit');
|
|
$encrypted_data = mb_substr($encrypted_data, openssl_cipher_iv_length("BF-CBC"), null, '8bit');
|
|
$plaintext = openssl_decrypt($encrypted_data,"BF-CBC", $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
|
|
if ($plaintext === false)
|
|
{
|
|
$plaintext = Dict::S("Core:AttributeEncryptFailedToDecrypt");
|
|
}
|
|
return trim($plaintext);
|
|
}
|
|
|
|
}
|