1 <?php 2 /** 3 * Provides an API for encrypting and decrypting small pieces of data with the 4 * use of a shared key stored in a cookie. 5 * 6 * Copyright 1999-2017 Horde LLC (http://www.horde.org/) 7 * 8 * See the enclosed file LICENSE for license information (LGPL). If you 9 * did not receive this file, see http://www.horde.org/licenses/lgpl21. 10 * 11 * @author Chuck Hagenbuch <chuck@horde.org> 12 * @author Michael Slusarz <slusarz@horde.org> 13 * @category Horde 14 * @license http://www.horde.org/licenses/lgpl21 LGPL 15 * @package Secret 16 */ 17 class Horde_Secret 18 { 19 /** Generic, default keyname. */ 20 const DEFAULT_KEY = 'generic'; 21 22 /** 23 * Configuration parameters. 24 * 25 * @var array 26 */ 27 protected $_params = array( 28 'cookie_domain' => '', 29 'cookie_path' => '', 30 'cookie_ssl' => false, 31 'session_name' => 'horde_secret' 32 ); 33 34 /** 35 * Cipher cache. 36 * 37 * @var array 38 */ 39 protected $_cipherCache = array(); 40 41 /** 42 * Key cache. 43 * 44 * @var array 45 */ 46 protected $_keyCache = array(); 47 48 /** 49 * Constructor. 50 * 51 * @param array $params Configuration parameters: 52 * - cookie_domain: (string) The cookie domain. 53 * - cookie_path: (string) The cookie path. 54 * - cookie_ssl: (boolean) Only transmit cookie securely? 55 * - session_name: (string) The cookie session name. 56 */ 57 public function __construct($params = array()) 58 { 59 $this->_params = array_merge($this->_params, $params); 60 } 61 62 /** 63 * Take a small piece of data and encrypt it with a key. 64 * 65 * @param string $key The key to use for encryption. 66 * @param string $message The plaintext message. 67 * 68 * @return string The ciphertext message. 69 * @throws Horde_Secret_Exception 70 */ 71 public function write($key, $message) 72 { 73 $message = strval($message); 74 return (strlen($key) && strlen($message)) 75 ? $this->_getCipherOb($key)->encrypt($message) 76 : ''; 77 } 78 79 /** 80 * Decrypt a message encrypted with write(). 81 * 82 * @param string $key The key to use for decryption. 83 * @param string $message The ciphertext message. 84 * 85 * @return string The plaintext message. 86 * @throws Horde_Secret_Exception 87 */ 88 public function read($key, $ciphertext) 89 { 90 $ciphertext = strval($ciphertext); 91 return (strlen($key) && strlen($ciphertext)) 92 ? $this->_getCipherOb($key)->decrypt($ciphertext) 93 : ''; 94 } 95 96 /** 97 * Returns the cached crypt object. 98 * 99 * @param string $key The key to use for [de|en]cryption. Only the first 100 * 56 bytes of this string is used. 101 * 102 * @return Horde_Crypt_Blowfish The crypt object. 103 * @throws Horde_Secret_Exception 104 */ 105 protected function _getCipherOb($key) 106 { 107 if (!is_string($key)) { 108 throw new Horde_Secret_Exception('Key must be a string', Horde_Secret_Exception::KEY_NOT_STRING); 109 } 110 111 if (!strlen($key)) { 112 throw new Horde_Secret_Exception('Key must be non-zero.', Horde_Secret_Exception::KEY_ZERO_LENGTH); 113 } 114 115 $key = substr($key, 0, 56); 116 117 $idx = hash('md5', $key); 118 if (!isset($this->_cipherCache[$idx])) { 119 $this->_cipherCache[$idx] = new Horde_Crypt_Blowfish($key); 120 } 121 122 return $this->_cipherCache[$idx]; 123 } 124 125 /** 126 * Generate a secret key (for encryption), either using a random 127 * string and storing it in a cookie if the user has cookies 128 * enabled, or munging some known values if they don't. 129 * 130 * @param string $keyname The name of the key to set. 131 * 132 * @return string The secret key that has been generated. 133 */ 134 public function setKey($keyname = self::DEFAULT_KEY) 135 { 136 $set = true; 137 138 if (isset($_COOKIE[$this->_params['session_name']])) { 139 if (isset($_COOKIE[$keyname . '_key'])) { 140 $key = $_COOKIE[$keyname . '_key']; 141 $set = false; 142 } else { 143 $key = $_COOKIE[$keyname . '_key'] = strval(new Horde_Support_Randomid()); 144 } 145 } else { 146 $key = session_id(); 147 } 148 149 if ($set) { 150 $this->_setCookie($keyname, $key); 151 } 152 153 return $key; 154 } 155 156 /** 157 * Return a secret key, either from a cookie, or if the cookie 158 * isn't there, assume we are using a munged version of a known 159 * base value. 160 * 161 * @param string $keyname The name of the key to get. 162 * 163 * @return string The secret key. 164 */ 165 public function getKey($keyname = self::DEFAULT_KEY) 166 { 167 if (!isset($this->_keyCache[$keyname])) { 168 if (isset($_COOKIE[$keyname . '_key'])) { 169 $key = $_COOKIE[$keyname . '_key']; 170 } else { 171 $key = session_id(); 172 $this->_setCookie($keyname, $key); 173 } 174 175 $this->_keyCache[$keyname] = $key; 176 } 177 178 return $this->_keyCache[$keyname]; 179 } 180 181 /** 182 * Clears a secret key entry from the current cookie. 183 * 184 * @param string $keyname The name of the key to clear. 185 * 186 * @return boolean True if key existed, false if not. 187 */ 188 public function clearKey($keyname = self::DEFAULT_KEY) 189 { 190 if (isset($_COOKIE[$this->_params['session_name']]) && 191 isset($_COOKIE[$keyname . '_key'])) { 192 $this->_setCookie($keyname, false); 193 return true; 194 } 195 196 return false; 197 } 198 199 /** 200 * Sets the cookie with the given keyname/key. 201 * 202 * @param string $keyname The name of the key to set. 203 * @param string $key The key to use for encryption. 204 */ 205 protected function _setCookie($keyname, $key) 206 { 207 @setcookie( 208 $keyname . '_key', 209 $key, 210 0, 211 $this->_params['cookie_path'], 212 $this->_params['cookie_domain'], 213 $this->_params['cookie_ssl'], 214 true 215 ); 216 217 if ($key === false) { 218 unset($_COOKIE[$keyname . '_key'], $this->_keyCache[$keyname]); 219 } else { 220 $_COOKIE[$keyname . '_key'] = $this->_keyCache[$keyname] = $key; 221 } 222 } 223 224 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body