--- /dev/null
+<?php
+/**
+ * The Secret:: class provides an API for encrypting and decrypting
+ * small pieces of data with the use of a shared key.
+ *
+ * The Secret:: functions use the Horde Cipher:: class if mcrypt is not
+ * available.
+ *
+ * Copyright 1999-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @package Horde_Secret
+ */
+class Horde_Secret
+{
+ /**
+ * Cipher cache.
+ *
+ * @var array
+ */
+ static protected $_cipherCache = array();
+
+ /**
+ * Key cache.
+ *
+ * @var array
+ */
+ static protected $_keyCache = array();
+
+ /**
+ * Take a small piece of data and encrypt it with a key.
+ *
+ * @param string $key The key to use for encryption.
+ * @param string $message The plaintext message.
+ *
+ * @return string The ciphertext message.
+ */
+ static public function write($key, $message)
+ {
+ if (!strlen($key)) {
+ return false;
+ }
+
+ $ret = Secret::_getMcryptData($key, $message, 'encrypt');
+ if ($ret !== false) {
+ return $ret;
+ }
+
+ $ptr = Secret::_getCipherOb($key);
+ return $ptr->encrypt($message);
+ }
+
+ /**
+ * Decrypt a message encrypted with Secret::write().
+ *
+ * @param string $key The key to use for decryption.
+ * @param string $message The ciphertext message.
+ *
+ * @return string The plaintext message.
+ */
+ static public function read($key, $ciphertext)
+ {
+ $ret = Secret::_getMcryptData($key, $ciphertext, 'decrypt');
+ if ($ret !== false) {
+ return rtrim($ret, "\0");
+ }
+
+ $ptr = Secret::_getCipherOb($key);
+ return $ptr->decrypt($ciphertext);
+ }
+
+ /**
+ * TODO
+ */
+ static protected function _getMcryptData($key, $text, $type)
+ {
+ $ret = false;
+
+ require_once 'Horde/Util.php';
+ if (Util::extensionExists('mcrypt')) {
+ $old_error = error_reporting(0);
+ $td = mcrypt_module_open(MCRYPT_GOST, '', MCRYPT_MODE_ECB, '');
+ if ($td) {
+ $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
+ mcrypt_generic_init($td, $key, $iv);
+ $ret = ($type == 'encrypt') ? mcrypt_generic($td, $text) : mdecrypt_generic($td, $text);
+ mcrypt_generic_deinit($td);
+ }
+ error_reporting($old_error);
+ }
+
+ return $ret;
+ }
+
+ /**
+ * TODO
+ */
+ static protected function _getCipherOb($key)
+ {
+ $idx = md5($key);
+
+ if (!isset(self::$_cipherCache[$idx])) {
+ self::$_cipherCache[$idx] = &Horde_Cipher::factory('blowfish');
+ self::$_cipherCache[$idx]->setBlockMode('ofb64');
+ self::$_cipherCache[$idx]->setKey($key);
+ }
+
+ return self::$_cipherCache[$idx];
+ }
+
+ /**
+ * Generate a secret key (for encryption), either using a random
+ * md5 string and storing it in a cookie if the user has cookies
+ * enabled, or munging some known values if they don't.
+ *
+ * @param string $keyname The name of the key to set.
+ *
+ * @return string The secret key that has been generated.
+ */
+ static public function setKey($keyname = 'generic')
+ {
+ if (isset($_COOKIE[$GLOBALS['conf']['session']['name']])) {
+ if (isset($_COOKIE[$keyname . '_key'])) {
+ $key = $_COOKIE[$keyname . '_key'];
+ } else {
+ $key = md5(mt_rand());
+ $_COOKIE[$keyname . '_key'] = $key;
+ Secret::_setCookie($keyname, $key);
+ }
+ } else {
+ $key = session_id();
+ Secret::_setCookie($keyname, $key);
+ }
+
+ return $key;
+ }
+
+ /**
+ * Return a secret key, either from a cookie, or if the cookie
+ * isn't there, assume we are using a munged version of a known
+ * base value.
+ *
+ * @param string $keyname The name of the key to get.
+ *
+ * @return string The secret key.
+ */
+ static public function getKey($keyname = 'generic')
+ {
+ if (!isset(self::$_keyCache[$keyname])) {
+ if (isset($_COOKIE[$keyname . '_key'])) {
+ self::$_keyCache[$keyname] = $_COOKIE[$keyname . '_key'];
+ } else {
+ self::$_keyCache[$keyname] = session_id();
+ Secret::_setCookie($keyname, self::$_keyCache[$keyname]);
+ }
+ }
+
+ return self::$_keyCache[$keyname];
+ }
+
+ /**
+ * TODO
+ */
+ static protected function _setCookie($keyname, $key)
+ {
+ global $conf;
+
+ $old_error = error_reporting(0);
+ setcookie(
+ $keyname . '_key',
+ $key,
+ $conf['session']['timeout'] ? time() + $conf['session']['timeout'] : 0,
+ $conf['cookie']['path'],
+ $conf['cookie']['domain'],
+ $conf['use_ssl'] == 1 ? 1 : 0
+ );
+ error_reporting($old_error);
+ }
+
+ /**
+ * Clears a secret key entry from the current cookie.
+ *
+ * @param string $keyname The name of the key to clear.
+ *
+ * @return boolean True if key existed, false if not.
+ */
+ static public function clearKey($keyname = 'generic')
+ {
+ if (isset($_COOKIE[$GLOBALS['conf']['session']['name']]) &&
+ isset($_COOKIE[$keyname . '_key'])) {
+ unset($_COOKIE[$keyname . '_key']);
+ return true;
+ }
+ return false;
+ }
+
+}
+
+// TODO - Remove once apps are transitioned to Horde 4
+class Secret extends Horde_Secret {}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.4.9" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd">
+ <name>Horde_Secret</name>
+ <channel>pear.horde.org</channel>
+ <summary>Secret Encryption API</summary>
+ <description>The Horde_Secret:: class provides an API for encrypting and decrypting small pieces of data with the use of a shared key.
+ </description>
+ <lead>
+ <name>Chuck Hagenbuch</name>
+ <user>chuck</user>
+ <email>chuck@horde.org</email>
+ <active>yes</active>
+ </lead>
+ <date>2008-12-11</date>
+ <version>
+ <release>0.0.3</release>
+ <api>0.0.2</api>
+ </version>
+ <stability>
+ <release>alpha</release>
+ <api>alpha</api>
+ </stability>
+ <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
+ <notes>* Initial Horde 4 package.</notes>
+ <contents>
+ <dir name="/">
+ <dir name="lib">
+ <dir name="Horde">
+ <file name="Secret.php" role="php" />
+ </dir> <!-- /lib/Horde -->
+ </dir> <!-- /lib -->
+ </dir> <!-- / -->
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>5.2.0</min>
+ </php>
+ <pearinstaller>
+ <min>1.5.0</min>
+ </pearinstaller>
+ <package>
+ <name>Horde_Cipher</name>
+ <channel>pear.horde.org</channel>
+ </package>
+ <package>
+ <name>Util</name>
+ <channel>pear.horde.org</channel>
+ </package>
+ </required>
+ <optional>
+ <extension>
+ <name>mcrypt</name>
+ </extension>
+ </optional>
+ </dependencies>
+ <phprelease>
+ <filelist>
+ <install name="lib/Horde/Secret.php" as="Horde/Secret.php" />
+ </filelist>
+ </phprelease>
+ <changelog>
+ <release>
+ <date>2006-05-08</date>
+ <time>23:10:28</time>
+ <version>
+ <release>0.0.2</release>
+ <api>0.0.2</api>
+ </version>
+ <stability>
+ <release>alpha</release>
+ <api>alpha</api>
+ </stability>
+ <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
+ <notes>- Converted to package.xml 2.0 for pear.horde.org
+- Return false instead of generating encryption errors if $key is empty (Bug #5925).
+ </notes>
+ </release>
+ <release>
+ <version>
+ <release>0.0.1</release>
+ <api>0.0.1</api>
+ </version>
+ <stability>
+ <release>alpha</release>
+ <api>alpha</api>
+ </stability>
+ <date>2003-07-05</date>
+ <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
+ <notes>Initial release as a PEAR package
+ </notes>
+ </release>
+ </changelog>
+</package>