From 70ec39842bea8dca606bcc513f7d905dfcecacac Mon Sep 17 00:00:00 2001 From: =?utf8?q?Roland=20H=C3=A4der?= Date: Fri, 19 May 2017 15:56:31 +0200 Subject: [PATCH] Continued a bit: - in the wake of mcrypt being deprecated, an OpenSSL-based implementation needs to be written. This commit marks the start for it. Please note, that currently you don't have *ANY* encryption as the methods are unfinished - moved DATA_PAYLOAD_SEPARATOR to EncryptableStream - updated TODOs.txt MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- docs/TODOs.txt | 24 +-- .../classes/crypto/class_CryptoHelper.php | 10 +- .../streams/crypto/class_McryptStream.php | 25 +-- .../streams/crypto/class_OpenSslStream.php | 180 ++++++++++++++++++ .../crypto/class_EncryptableStream.php | 7 +- 5 files changed, 215 insertions(+), 31 deletions(-) create mode 100644 framework/main/classes/streams/crypto/class_OpenSslStream.php diff --git a/docs/TODOs.txt b/docs/TODOs.txt index 9401e784..73ccfe84 100644 --- a/docs/TODOs.txt +++ b/docs/TODOs.txt @@ -6,14 +6,14 @@ ./framework/loader/class_ClassLoader.php:232: // @TODO Throw exception instead of break ./framework/loader/class_ClassLoader.php:423: /* @TODO: Do not exit here. */ ./framework/main/classes/cache/class_MemoryCache.php:17: * @todo Rename to InProgressCache -./framework/main/classes/class_BaseFrameworkSystem.php:2136: // @TODO Move the constant to e.g. BaseDatabaseResult when there is a non-cached database result available -./framework/main/classes/class_BaseFrameworkSystem.php:2251: * @todo Write a logging mechanism for productive mode -./framework/main/classes/class_BaseFrameworkSystem.php:2266: // @TODO Finish this part! -./framework/main/classes/class_BaseFrameworkSystem.php:3266: * @todo Improve documentation -./framework/main/classes/class_BaseFrameworkSystem.php:3376: * @todo Move all this socket-related stuff into own class, most of it resides in BaseListener -./framework/main/classes/class_BaseFrameworkSystem.php:345: // @todo Try to clean these constants up -./framework/main/classes/class_BaseFrameworkSystem.php:590: // @TODO __CLASS__ does always return BaseFrameworkSystem but not the extending (=child) class -./framework/main/classes/class_BaseFrameworkSystem.php:694: * @todo SearchableResult and UpdateableResult shall have a super interface to use here +./framework/main/classes/class_BaseFrameworkSystem.php:2137: // @TODO Move the constant to e.g. BaseDatabaseResult when there is a non-cached database result available +./framework/main/classes/class_BaseFrameworkSystem.php:2252: * @todo Write a logging mechanism for productive mode +./framework/main/classes/class_BaseFrameworkSystem.php:2267: // @TODO Finish this part! +./framework/main/classes/class_BaseFrameworkSystem.php:3267: * @todo Improve documentation +./framework/main/classes/class_BaseFrameworkSystem.php:3377: * @todo Move all this socket-related stuff into own class, most of it resides in BaseListener +./framework/main/classes/class_BaseFrameworkSystem.php:346: // @todo Try to clean these constants up +./framework/main/classes/class_BaseFrameworkSystem.php:591: // @TODO __CLASS__ does always return BaseFrameworkSystem but not the extending (=child) class +./framework/main/classes/class_BaseFrameworkSystem.php:695: * @todo SearchableResult and UpdateableResult shall have a super interface to use here ./framework/main/classes/commands/console/class_ConsoleFuseCommand.php:83: // @TODO Unfinished ./framework/main/classes/commands/html/class_HtmlLoginAreaCommand.php:78: * @todo Add some stuff here: Some personal data, app/game related data ./framework/main/classes/commands/html/class_HtmlProblemCommand.php:70: * @todo 0% done @@ -36,6 +36,7 @@ ./framework/main/classes/criteria/dataset/class_DataSetCriteria.php:157: // @TODO Issue a warning ./framework/main/classes/criteria/search/class_SearchCriteria.php:109: * @todo Find a nice casting here. (int) allows until and including 32766. ./framework/main/classes/criteria/search/class_SearchCriteria.php:77: * @todo Find a nice casting here. (int) allows until and including 32766. +./framework/main/classes/crypto/class_CryptoHelper.php:104: // @TODO Maybe rewrite this with DirectoryIterator, similar to Compressor thing? ./framework/main/classes/database/backend/class_CachedLocalFileDatabase.php:339: * @todo Do some checks on the database directory and files here ./framework/main/classes/database/backend/class_CachedLocalFileDatabase.php:628: * @todo Add more generic non-public data for removal ./framework/main/classes/database/class_BaseDatabaseWrapper.php:214: // @TODO Minor: Update above comment to e.g. BaseDatabaseResult @@ -111,6 +112,8 @@ ./framework/main/classes/stacker/file/class_BaseFileStack.php:345: // @TODO Please implement this, returning false ./framework/main/classes/stacker/file/class_BaseFileStack.php:68: * @todo To hard assertions here, better rewrite them to exceptions ./framework/main/classes/streams/crypto/class_McryptStream.php:16: * @todo mcrypt will become deprecated, rewrite to OpenSSL +./framework/main/classes/streams/crypto/class_OpenSslStream.php:136: // @TODO unfinished +./framework/main/classes/streams/crypto/class_OpenSslStream.php:66: // @TODO unfinished ./framework/main/classes/template/class_BaseTemplateEngine.php:1065: // @TODO This silent abort should be logged, maybe. ./framework/main/classes/template/class_BaseTemplateEngine.php:1073: // @TODO Old behaviour, will become obsolete! ./framework/main/classes/template/class_BaseTemplateEngine.php:1076: // @TODO Yet another old way @@ -164,7 +167,7 @@ ./framework/database/lib-lfdb.php:2:// @DEPRECATED ./framework/database.php:2:// @DEPRECATED ./framework/includes.php:2:// @DEPRECATED -./framework/main/classes/class_BaseFrameworkSystem.php:1885: * @deprecated Not fully, as the new Logger facilities are not finished yet. +./framework/main/classes/class_BaseFrameworkSystem.php:1886: * @deprecated Not fully, as the new Logger facilities are not finished yet. ./framework/main/exceptions/base64/class_Base64EncodingBadException.php:17: * @deprecated Don't use this anymore ./framework/main/exceptions/base64/class_Base64EncodingModuloException.php:16: * @deprecated Don't use this anymore ./framework/main/exceptions/crypto/class_EncryptInvalidLengthException.php:17: * @deprecated Don't use this anymore @@ -174,13 +177,10 @@ ./framework/main/exceptions/database/local_file/class_SavePathReadProtectedException.php:13: * @deprecated Please don't use this ./framework/main/exceptions/database/local_file/class_SavePathWriteProtectedException.php:13: * @deprecated Please don't use this ./framework/main/exceptions/file_directory/class_FileIsEmptyException.php:16: * @deprecated Don't use this anymore -./framework/main/exceptions/file_directory/class_FileReadProtectedException.php:16: * @deprecated Don't read this anymore -./framework/main/exceptions/file_directory/class_FileWriteProtectedException.php:16: * @deprecated Don't use this anymore ./framework/main/exceptions/file_directory/class_InvalidDataLengthException.php:16: * @deprecated Don't use this anymore ./framework/main/exceptions/file_directory/class_InvalidMD5ChecksumException.php:16: * @deprecated Don't use this anymore ./framework/main/exceptions/file_directory/class_PathIsNoDirectoryException.php:16: * @deprecated Don't use this anymore ./framework/main/exceptions/file_directory/class_PathReadProtectedException.php:16: * @deprecated Don't use this anymore -./framework/main/exceptions/file_directory/class_PathWriteProtectedException.php:16: * @deprecated Don't use this anymore ./framework/main/exceptions/filter/class_InvalidFilterChainException.php:16: * @deprecated Don't use this anymore ./framework/main/exceptions/helper/class_FormClosedException.php:17: * @deprecated Don't use this anymore ./framework/main/exceptions/helper/class_FormGroupClosedException.php:16: * @deprecated Don't use this anymore diff --git a/framework/main/classes/crypto/class_CryptoHelper.php b/framework/main/classes/crypto/class_CryptoHelper.php index b4043172..6ee9c171 100644 --- a/framework/main/classes/crypto/class_CryptoHelper.php +++ b/framework/main/classes/crypto/class_CryptoHelper.php @@ -101,13 +101,17 @@ class CryptoHelper extends BaseFrameworkSystem implements Cryptable { * @return void */ protected function attachCryptoStream () { - // Do we have mcrypt loaded? + // @TODO Maybe rewrite this with DirectoryIterator, similar to Compressor thing? + // Do we have openssl/mcrypt loaded? if ($this->isPhpExtensionLoaded('mcrypt')) { // Then use it - $this->cryptoStreamInstance = ObjectFactory::createObjectByName('McryptStream', array($this->getRngInstance())); + $this->cryptoStreamInstance = ObjectFactory::createObjectByName('CoreFramework\Stream\Crypto\McryptStream', array($this->getRngInstance())); + } elseif ($this->isPhpExtensionLoaded('openssl')) { + // Then use it + $this->cryptoStreamInstance = ObjectFactory::createObjectByName('CoreFramework\Stream\Crypto\OpenSslStream', array($this->getRngInstance())); } else { // If nothing works ... - $this->cryptoStreamInstance = ObjectFactory::createObjectByName('NullCryptoStream'); + $this->cryptoStreamInstance = ObjectFactory::createObjectByName('CoreFramework\Stream\Crypto\NullCryptoStream'); } } diff --git a/framework/main/classes/streams/crypto/class_McryptStream.php b/framework/main/classes/streams/crypto/class_McryptStream.php index c0fa0d0f..c6558c35 100644 --- a/framework/main/classes/streams/crypto/class_McryptStream.php +++ b/framework/main/classes/streams/crypto/class_McryptStream.php @@ -29,11 +29,6 @@ use CoreFramework\Crypto\RandomNumber\RandomNumberGenerator; * along with this program. If not, see . */ class McryptStream extends BaseStream implements EncryptableStream { - /** - * Separator on many places - */ - const DATA_PAYLOAD_SEPARATOR = '|'; - /** * Protected constructor * @@ -85,39 +80,39 @@ class McryptStream extends BaseStream implements EncryptableStream { // Add some "payload" to the string switch ($this->getRngInstance()->randomNumber(0, 8)) { case 0: - $payloadString = crc32($this->getRngInstance()->randomString(10)) . self::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . self::DATA_PAYLOAD_SEPARATOR . crc32($this->getRngInstance()->randomString(20)); + $payloadString = crc32($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . crc32($this->getRngInstance()->randomString(20)); break; case 1: - $payloadString = crc32($this->getRngInstance()->randomString(10)) . self::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . self::DATA_PAYLOAD_SEPARATOR . md5($this->getRngInstance()->randomString(20)); + $payloadString = crc32($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . md5($this->getRngInstance()->randomString(20)); break; case 2: - $payloadString = crc32($this->getRngInstance()->randomString(10)) . self::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . self::DATA_PAYLOAD_SEPARATOR . sha1($this->getRngInstance()->randomString(20)); + $payloadString = crc32($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . sha1($this->getRngInstance()->randomString(20)); break; case 3: - $payloadString = md5($this->getRngInstance()->randomString(10)) . self::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . self::DATA_PAYLOAD_SEPARATOR . crc32($this->getRngInstance()->randomString(20)); + $payloadString = md5($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . crc32($this->getRngInstance()->randomString(20)); break; case 4: - $payloadString = md5($this->getRngInstance()->randomString(10)) . self::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . self::DATA_PAYLOAD_SEPARATOR . md5($this->getRngInstance()->randomString(20)); + $payloadString = md5($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . md5($this->getRngInstance()->randomString(20)); break; case 5: - $payloadString = md5($this->getRngInstance()->randomString(10)) . self::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . self::DATA_PAYLOAD_SEPARATOR . sha1($this->getRngInstance()->randomString(20)); + $payloadString = md5($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . sha1($this->getRngInstance()->randomString(20)); break; case 6: - $payloadString = sha1($this->getRngInstance()->randomString(10)) . self::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . self::DATA_PAYLOAD_SEPARATOR . crc32($this->getRngInstance()->randomString(20)); + $payloadString = sha1($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . crc32($this->getRngInstance()->randomString(20)); break; case 7: - $payloadString = sha1($this->getRngInstance()->randomString(10)) . self::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . self::DATA_PAYLOAD_SEPARATOR . md5($this->getRngInstance()->randomString(20)); + $payloadString = sha1($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . md5($this->getRngInstance()->randomString(20)); break; case 8: - $payloadString = sha1($this->getRngInstance()->randomString(10)) . self::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . self::DATA_PAYLOAD_SEPARATOR . sha1($this->getRngInstance()->randomString(20)); + $payloadString = sha1($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . sha1($this->getRngInstance()->randomString(20)); break; } @@ -150,7 +145,7 @@ class McryptStream extends BaseStream implements EncryptableStream { $payloadString = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_ECB, $iv); // Get the real string out - $strArray = explode(self::DATA_PAYLOAD_SEPARATOR, $payloadString); + $strArray = explode(EncryptableStream::DATA_PAYLOAD_SEPARATOR, $payloadString); // Does the element count match? assert(count($strArray) == 3); diff --git a/framework/main/classes/streams/crypto/class_OpenSslStream.php b/framework/main/classes/streams/crypto/class_OpenSslStream.php new file mode 100644 index 00000000..6ba8898e --- /dev/null +++ b/framework/main/classes/streams/crypto/class_OpenSslStream.php @@ -0,0 +1,180 @@ + + * @version 0.0.0 + * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2017 Core Developer Team + * @license GNU GPL 3.0 or any newer version + * @link http://www.shipsimu.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +class OpenSslStream extends BaseStream implements EncryptableStream { + /** + * Protected constructor + * + * @return void + */ + protected function __construct () { + // Call parent constructor + parent::__construct(__CLASS__); + } + + /** + * Creates an instance of this node class + * + * @param $rngInstance An RNG instance + * @return $streamInstance An instance of this node class + */ + public static final function createOpenSslStream (RandomNumberGenerator $rngInstance) { + // Get a new instance + $streamInstance = new OpenSslStream(); + + // Set the RNG instance + $streamInstance->setRngInstance($rngInstance); + + // Return the instance + return $streamInstance; + } + + /** + * Encrypt the string with fixed salt + * + * @param $str The unencrypted string + * @param $key Optional key, if none provided, a random key will be generated + * @return $encrypted Encrypted string + */ + public function encryptStream ($str, $key = NULL) { + // @TODO unfinished + return $str; + + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: key[' . gettype($key) . ']=' . $key); + + // Init crypto module + $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB); + $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); + + // Generate key, if none provided + if (is_null($key)) { + // None provided + $key = $this->getRngInstance()->generateKey(); + } // END - if + + // Add some "payload" to the string + switch ($this->getRngInstance()->randomNumber(0, 8)) { + case 0: + $payloadString = crc32($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . crc32($this->getRngInstance()->randomString(20)); + break; + + case 1: + $payloadString = crc32($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . md5($this->getRngInstance()->randomString(20)); + break; + + case 2: + $payloadString = crc32($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . sha1($this->getRngInstance()->randomString(20)); + break; + + case 3: + $payloadString = md5($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . crc32($this->getRngInstance()->randomString(20)); + break; + + case 4: + $payloadString = md5($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . md5($this->getRngInstance()->randomString(20)); + break; + + case 5: + $payloadString = md5($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . sha1($this->getRngInstance()->randomString(20)); + break; + + case 6: + $payloadString = sha1($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . crc32($this->getRngInstance()->randomString(20)); + break; + + case 7: + $payloadString = sha1($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . md5($this->getRngInstance()->randomString(20)); + break; + + case 8: + $payloadString = sha1($this->getRngInstance()->randomString(10)) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . base64_encode($str) . EncryptableStream::DATA_PAYLOAD_SEPARATOR . sha1($this->getRngInstance()->randomString(20)); + break; + } + + // Encrypt the string + $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $payloadString, MCRYPT_MODE_ECB, $iv); + + // Return the string + return $encrypted; + } + + /** + * Decrypt the string with fixed salt + * + * @param $encrypted Encrypted string + * @param $key Optional key, if none provided, a random key will be generated + * @return $str The unencrypted string + */ + public function decryptStream ($encrypted, $key = NULL) { + // @TODO unfinished + return $encrypted; + + // Init crypto module + $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB); + $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); + + // Shall we use a default key or custom? + if (is_null($key)) { + // Generate (default) key + $key = $this->getRngInstance()->generateKey(); + } // END - if + + // Decrypt the string + $payloadString = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_ECB, $iv); + + // Get the real string out + $strArray = explode(EncryptableStream::DATA_PAYLOAD_SEPARATOR, $payloadString); + + // Does the element count match? + assert(count($strArray) == 3); + + // Decode the string + $str = base64_decode($strArray[1]); + + // Trim trailing nulls away + $str = rtrim($str, "\0"); + + // Return the string + return $str; + } + + /** + * Streams the data and maybe does something to it + * + * @param $data The data (string mostly) to "stream" + * @return $data The data (string mostly) to "stream" + * @throws UnsupportedOperationException If this method is called (which is a mistake) + */ + public function streamData ($data) { + self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('Unhandled ' . strlen($data) . ' bytes in this stream.'); + throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION); + } + +} diff --git a/framework/main/interfaces/streams/crypto/class_EncryptableStream.php b/framework/main/interfaces/streams/crypto/class_EncryptableStream.php index c8849660..ccfd91db 100644 --- a/framework/main/interfaces/streams/crypto/class_EncryptableStream.php +++ b/framework/main/interfaces/streams/crypto/class_EncryptableStream.php @@ -3,7 +3,7 @@ namespace CoreFramework\Stream\Crypto; /** - * An EncryptableStream interface + * An interface for encrypted data streams * * @author Roland Haeder * @version 0.0.0 @@ -25,6 +25,11 @@ namespace CoreFramework\Stream\Crypto; * along with this program. If not, see . */ interface EncryptableStream extends Stream { + /** + * Separator on many places + */ + const DATA_PAYLOAD_SEPARATOR = '|'; + /** * Encrypt the string with fixed salt * -- 2.39.2