Continued a bit:
authorRoland Häder <roland@mxchange.org>
Fri, 19 May 2017 13:56:31 +0000 (15:56 +0200)
committerRoland Häder <roland@mxchange.org>
Fri, 19 May 2017 13:58:23 +0000 (15:58 +0200)
- 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

Signed-off-by: Roland Häder <roland@mxchange.org>
docs/TODOs.txt
framework/main/classes/crypto/class_CryptoHelper.php
framework/main/classes/streams/crypto/class_McryptStream.php
framework/main/classes/streams/crypto/class_OpenSslStream.php [new file with mode: 0644]
framework/main/interfaces/streams/crypto/class_EncryptableStream.php

index 9401e78..73ccfe8 100644 (file)
@@ -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
 ./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
 ./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
 ./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
index b404317..6ee9c17 100644 (file)
@@ -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');
                }
        }
 
index c0fa0d0..c6558c3 100644 (file)
@@ -30,11 +30,6 @@ use CoreFramework\Crypto\RandomNumber\RandomNumberGenerator;
  */
 class McryptStream extends BaseStream implements EncryptableStream {
        /**
-        * Separator on many places
-        */
-       const DATA_PAYLOAD_SEPARATOR = '|';
-
-       /**
         * Protected constructor
         *
         * @return      void
@@ -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 (file)
index 0000000..6ba8898
--- /dev/null
@@ -0,0 +1,180 @@
+<?php
+// Own namespace
+namespace CoreFramework\Stream\Crypto;
+
+// Import framework stuff
+use CoreFramework\Crypto\RandomNumber\RandomNumberGenerator;
+
+/**
+ * An OpenSSL-based encryption stream
+ *
+ * @author             Roland Haeder <webmaster@shipsimu.org>
+ * @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 <http://www.gnu.org/licenses/>.
+ */
+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);
+       }
+
+}
index c884966..ccfd91d 100644 (file)
@@ -3,7 +3,7 @@
 namespace CoreFramework\Stream\Crypto;
 
 /**
- * An EncryptableStream interface
+ * An interface for encrypted data streams
  *
  * @author             Roland Haeder <webmaster@shipsimu.org>
  * @version            0.0.0
@@ -26,6 +26,11 @@ namespace CoreFramework\Stream\Crypto;
  */
 interface EncryptableStream extends Stream {
        /**
+        * Separator on many places
+        */
+       const DATA_PAYLOAD_SEPARATOR = '|';
+
+       /**
         * Encrypt the string with fixed salt
         *
         * @param       $str            The unencrypted string