]> git.mxchange.org Git - friendica.git/blobdiff - src/Util/Crypto.php
Issue 6438: Avoid fatal error
[friendica.git] / src / Util / Crypto.php
index d6dbbd8b6b0732e97f0f2f0019f2afdeb6893004..3426babe36e27aa2102bf6d36152f80a939903ed 100644 (file)
@@ -4,13 +4,13 @@
  */
 namespace Friendica\Util;
 
+use Friendica\Core\Addon;
 use Friendica\Core\Config;
+use Friendica\Core\Logger;
+use Friendica\Util\Strings;
 use ASN_BASE;
 use ASNValue;
 
-require_once 'library/ASNValue.class.php';
-require_once 'library/asn1.php';
-
 /**
  * @brief Crypto class
  */
@@ -96,7 +96,7 @@ class Crypto
                $modulus->SetIntBuffer($Modulus);
                $publicExponent = new ASNValue(ASNValue::TAG_INTEGER);
                $publicExponent->SetIntBuffer($PublicExponent);
-               $keySequenceItems = array($modulus, $publicExponent);
+               $keySequenceItems = [$modulus, $publicExponent];
                $keySequence = new ASNValue(ASNValue::TAG_SEQUENCE);
                $keySequence->SetSequence($keySequenceItems);
                //Encode bit string
@@ -125,7 +125,7 @@ class Crypto
                $modulus->SetIntBuffer($Modulus);
                $publicExponent = new ASNValue(ASNValue::TAG_INTEGER);
                $publicExponent->SetIntBuffer($PublicExponent);
-               $keySequenceItems = array($modulus, $publicExponent);
+               $keySequenceItems = [$modulus, $publicExponent];
                $keySequence = new ASNValue(ASNValue::TAG_SEQUENCE);
                $keySequence->SetSequence($keySequenceItems);
                //Encode bit string
@@ -160,8 +160,8 @@ class Crypto
 
                $r = ASN_BASE::parseASNString($x);
 
-               $m = base64url_decode($r[0]->asnData[0]->asnData);
-               $e = base64url_decode($r[0]->asnData[1]->asnData);
+               $m = Strings::base64UrlDecode($r[0]->asnData[0]->asnData);
+               $e = Strings::base64UrlDecode($r[0]->asnData[1]->asnData);
        }
 
        /**
@@ -190,7 +190,7 @@ class Crypto
         * @param string $e   exponent reference
         * @return void
         */
-       private static function pemToMe($key, &$m, &$e)
+       public static function pemToMe($key, &$m, &$e)
        {
                $lines = explode("\n", $key);
                unset($lines[0]);
@@ -199,8 +199,8 @@ class Crypto
 
                $r = ASN_BASE::parseASNString($x);
 
-               $m = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[0]->asnData);
-               $e = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[1]->asnData);
+               $m = Strings::base64UrlDecode($r[0]->asnData[1]->asnData[0]->asnData[0]->asnData);
+               $e = Strings::base64UrlDecode($r[0]->asnData[1]->asnData[0]->asnData[1]->asnData);
        }
 
        /**
@@ -221,11 +221,11 @@ class Crypto
         */
        public static function newKeypair($bits)
        {
-               $openssl_options = array(
+               $openssl_options = [
                        'digest_alg'       => 'sha1',
                        'private_key_bits' => $bits,
                        'encrypt_key'      => false
-               );
+               ];
 
                $conf = Config::get('system', 'openssl_conf_file');
                if ($conf) {
@@ -234,12 +234,12 @@ class Crypto
                $result = openssl_pkey_new($openssl_options);
 
                if (empty($result)) {
-                       logger('new_keypair: failed');
+                       Logger::log('new_keypair: failed');
                        return false;
                }
 
                // Get private key
-               $response = array('prvkey' => '', 'pubkey' => '');
+               $response = ['prvkey' => '', 'pubkey' => ''];
 
                openssl_pkey_export($result, $response['prvkey']);
 
@@ -249,4 +249,253 @@ class Crypto
 
                return $response;
        }
+
+       /**
+        * Encrypt a string with 'aes-256-cbc' cipher method.
+        * 
+        * Ported from Hubzilla: https://framagit.org/hubzilla/core/blob/master/include/crypto.php
+        * 
+        * @param string $data
+        * @param string $key   The key used for encryption.
+        * @param string $iv    A non-NULL Initialization Vector.
+        * 
+        * @return string|boolean Encrypted string or false on failure.
+        */
+       private static function encryptAES256CBC($data, $key, $iv)
+       {
+               return openssl_encrypt($data, 'aes-256-cbc', str_pad($key, 32, "\0"), OPENSSL_RAW_DATA, str_pad($iv, 16, "\0"));
+       }
+
+       /**
+        * Decrypt a string with 'aes-256-cbc' cipher method.
+        * 
+        * Ported from Hubzilla: https://framagit.org/hubzilla/core/blob/master/include/crypto.php
+        * 
+        * @param string $data
+        * @param string $key   The key used for decryption.
+        * @param string $iv    A non-NULL Initialization Vector.
+        * 
+        * @return string|boolean Decrypted string or false on failure.
+        */
+       private static function decryptAES256CBC($data, $key, $iv)
+       {
+               return openssl_decrypt($data, 'aes-256-cbc', str_pad($key, 32, "\0"), OPENSSL_RAW_DATA, str_pad($iv, 16, "\0"));
+       }
+
+       /**
+        * Encrypt a string with 'aes-256-ctr' cipher method.
+        * 
+        * Ported from Hubzilla: https://framagit.org/hubzilla/core/blob/master/include/crypto.php
+        * 
+        * @param string $data
+        * @param string $key   The key used for encryption.
+        * @param string $iv    A non-NULL Initialization Vector.
+        * 
+        * @return string|boolean Encrypted string or false on failure.
+        */
+       private static function encryptAES256CTR($data, $key, $iv)
+       {
+               $key = substr($key, 0, 32);
+               $iv = substr($iv, 0, 16);
+               return openssl_encrypt($data, 'aes-256-ctr', str_pad($key, 32, "\0"), OPENSSL_RAW_DATA, str_pad($iv, 16, "\0"));
+       }
+
+       /**
+        * Decrypt a string with 'aes-256-ctr' cipher method.
+        * 
+        * Ported from Hubzilla: https://framagit.org/hubzilla/core/blob/master/include/crypto.php
+        * 
+        * @param string $data
+        * @param string $key   The key used for decryption.
+        * @param string $iv    A non-NULL Initialization Vector.
+        * 
+        * @return string|boolean Decrypted string or false on failure.
+        */
+       private static function decryptAES256CTR($data, $key, $iv)
+       {
+               $key = substr($key, 0, 32);
+               $iv = substr($iv, 0, 16);
+               return openssl_decrypt($data, 'aes-256-ctr', str_pad($key, 32, "\0"), OPENSSL_RAW_DATA, str_pad($iv, 16, "\0"));
+       }
+
+       /**
+        * 
+        * Ported from Hubzilla: https://framagit.org/hubzilla/core/blob/master/include/crypto.php
+        * 
+        * @param string $data
+        * @param string $pubkey The public key.
+        * @param string $alg    The algorithm used for encryption.
+        * 
+        * @return array
+        */
+       public static function encapsulate($data, $pubkey, $alg = 'aes256cbc')
+       {
+               if ($alg === 'aes256cbc') {
+                       return self::encapsulateAes($data, $pubkey);
+               }
+               return self::encapsulateOther($data, $pubkey, $alg);
+       }
+
+       /**
+        * 
+        * Ported from Hubzilla: https://framagit.org/hubzilla/core/blob/master/include/crypto.php
+        * 
+        * @param type $data
+        * @param type $pubkey The public key.
+        * @param type $alg    The algorithm used for encryption.
+        * 
+        * @return array
+        */
+       private static function encapsulateOther($data, $pubkey, $alg)
+       {
+               if (!$pubkey) {
+                       Logger::log('no key. data: '.$data);
+               }
+               $fn = 'encrypt' . strtoupper($alg);
+               if (method_exists(__CLASS__, $fn)) {
+                       $result = ['encrypted' => true];
+                       $key = random_bytes(256);
+                       $iv  = random_bytes(256);
+                       $result['data'] = Strings::base64UrlEncode(self::$fn($data, $key, $iv), true);
+
+                       // log the offending call so we can track it down
+                       if (!openssl_public_encrypt($key, $k, $pubkey)) {
+                               $x = debug_backtrace();
+                               Logger::log('RSA failed. ' . print_r($x[0], true));
+                       }
+
+                       $result['alg'] = $alg;
+                       $result['key'] = Strings::base64UrlEncode($k, true);
+                       openssl_public_encrypt($iv, $i, $pubkey);
+                       $result['iv'] = Strings::base64UrlEncode($i, true);
+
+                       return $result;
+               } else {
+                       $x = ['data' => $data, 'pubkey' => $pubkey, 'alg' => $alg, 'result' => $data];
+                       Addon::callHooks('other_encapsulate', $x);
+
+                       return $x['result'];
+               }
+       }
+
+       /**
+        * 
+        * Ported from Hubzilla: https://framagit.org/hubzilla/core/blob/master/include/crypto.php
+        * 
+        * @param string $data
+        * @param string $pubkey
+        * 
+        * @return array
+        */
+       private static function encapsulateAes($data, $pubkey)
+       {
+               if (!$pubkey) {
+                       Logger::log('aes_encapsulate: no key. data: ' . $data);
+               }
+
+               $key = random_bytes(32);
+               $iv  = random_bytes(16);
+               $result = ['encrypted' => true];
+               $result['data'] = Strings::base64UrlEncode(self::encryptAES256CBC($data, $key, $iv), true);
+
+               // log the offending call so we can track it down
+               if (!openssl_public_encrypt($key, $k, $pubkey)) {
+                       $x = debug_backtrace();
+                       Logger::log('aes_encapsulate: RSA failed. ' . print_r($x[0], true));
+               }
+
+               $result['alg'] = 'aes256cbc';
+               $result['key'] = Strings::base64UrlEncode($k, true);
+               openssl_public_encrypt($iv, $i, $pubkey);
+               $result['iv'] = Strings::base64UrlEncode($i, true);
+
+               return $result;
+       }
+
+       /**
+        * 
+        * Ported from Hubzilla: https://framagit.org/hubzilla/core/blob/master/include/crypto.php
+        * 
+        * @param string $data
+        * @param string $prvkey  The private key used for decryption.
+        * 
+        * @return string|boolean The decrypted string or false on failure.
+        */
+       public static function unencapsulate($data, $prvkey)
+       {
+               if (!$data) {
+                       return;
+               }
+
+               $alg = ((array_key_exists('alg', $data)) ? $data['alg'] : 'aes256cbc');
+               if ($alg === 'aes256cbc') {
+                       return self::encapsulateAes($data, $prvkey);
+               }
+               return self::encapsulateOther($data, $prvkey, $alg);
+       }
+
+       /**
+        * 
+        * Ported from Hubzilla: https://framagit.org/hubzilla/core/blob/master/include/crypto.php
+        * 
+        * @param string $data
+        * @param string $prvkey  The private key used for decryption.
+        * @param string $alg
+        * 
+        * @return string|boolean The decrypted string or false on failure.
+        */
+       private static function unencapsulateOther($data, $prvkey, $alg)
+       {
+               $fn = 'decrypt' . strtoupper($alg);
+
+               if (method_exists(__CLASS__, $fn)) {
+                       openssl_private_decrypt(Strings::base64UrlDecode($data['key']), $k, $prvkey);
+                       openssl_private_decrypt(Strings::base64UrlDecode($data['iv']), $i, $prvkey);
+
+                       return self::$fn(Strings::base64UrlDecode($data['data']), $k, $i);
+               } else {
+                       $x = ['data' => $data, 'prvkey' => $prvkey, 'alg' => $alg, 'result' => $data];
+                       Addon::callHooks('other_unencapsulate', $x);
+
+                       return $x['result'];
+               }
+       }
+
+       /**
+        * 
+        * Ported from Hubzilla: https://framagit.org/hubzilla/core/blob/master/include/crypto.php
+        * 
+        * @param array  $data
+        * @param string $prvkey  The private key used for decryption.
+        * 
+        * @return string|boolean The decrypted string or false on failure.
+        */
+       private static function unencapsulateAes($data, $prvkey)
+       {
+               openssl_private_decrypt(Strings::base64UrlDecode($data['key']), $k, $prvkey);
+               openssl_private_decrypt(Strings::base64UrlDecode($data['iv']), $i, $prvkey);
+
+               return self::decryptAES256CBC(Strings::base64UrlDecode($data['data']), $k, $i);
+       }
+
+
+       /**
+        * Creates cryptographic secure random digits
+        *
+        * @param string $digits The count of digits
+        * @return int The random Digits
+        *
+        * @throws \Exception In case 'random_int' isn't usable
+        */
+       public static function randomDigits($digits)
+       {
+               $rn = '';
+
+               // generating cryptographically secure pseudo-random integers
+               for ($i = 0; $i < $digits; $i++) {
+                       $rn .= random_int(0, 9);
+               }
+
+               return $rn;
+       }
 }