1 <?php
2 /**
3 * @package Joomla.Platform
4 * @subpackage Crypt
5 *
6 * @copyright Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE
8 */
9
10 defined('JPATH_PLATFORM') or die;
11
12 /**
13 * JCrypt is a Joomla Platform class for handling basic encryption/decryption of data.
14 *
15 * @since 12.1
16 */
17 class JCrypt
18 {
19 /**
20 * @var JCryptCipher The encryption cipher object.
21 * @since 12.1
22 */
23 private $_cipher;
24
25 /**
26 * @var JCryptKey The encryption key[/pair)].
27 * @since 12.1
28 */
29 private $_key;
30
31 /**
32 * Object Constructor takes an optional key to be used for encryption/decryption. If no key is given then the
33 * secret word from the configuration object is used.
34 *
35 * @param JCryptCipher $cipher The encryption cipher object.
36 * @param JCryptKey $key The encryption key[/pair)].
37 *
38 * @since 12.1
39 */
40 public function __construct(JCryptCipher $cipher = null, JCryptKey $key = null)
41 {
42 // Set the encryption key[/pair)].
43 $this->_key = $key;
44
45 // Set the encryption cipher.
46 $this->_cipher = isset($cipher) ? $cipher : new JCryptCipherSimple;
47 }
48
49 /**
50 * Method to decrypt a data string.
51 *
52 * @param string $data The encrypted string to decrypt.
53 *
54 * @return string The decrypted data string.
55 *
56 * @since 12.1
57 * @throws InvalidArgumentException
58 */
59 public function decrypt($data)
60 {
61 try
62 {
63 return $this->_cipher->decrypt($data, $this->_key);
64 }
65 catch (InvalidArgumentException $e)
66 {
67 return false;
68 }
69 }
70
71 /**
72 * Method to encrypt a data string.
73 *
74 * @param string $data The data string to encrypt.
75 *
76 * @return string The encrypted data string.
77 *
78 * @since 12.1
79 */
80 public function encrypt($data)
81 {
82 return $this->_cipher->encrypt($data, $this->_key);
83 }
84
85 /**
86 * Method to generate a new encryption key[/pair] object.
87 *
88 * @param array $options Key generation options.
89 *
90 * @return JCryptKey
91 *
92 * @since 12.1
93 */
94 public function generateKey(array $options = array())
95 {
96 return $this->_cipher->generateKey($options);
97 }
98
99 /**
100 * Method to set the encryption key[/pair] object.
101 *
102 * @param JCryptKey $key The key object to set.
103 *
104 * @return JCrypt
105 *
106 * @since 12.1
107 */
108 public function setKey(JCryptKey $key)
109 {
110 $this->_key = $key;
111
112 return $this;
113 }
114
115 /**
116 * Generate random bytes.
117 *
118 * @param integer $length Length of the random data to generate
119 *
120 * @return string Random binary data
121 *
122 * @since 12.1
123 */
124 public static function genRandomBytes($length = 16)
125 {
126 return random_bytes($length);
127 }
128
129 /**
130 * A timing safe comparison method.
131 *
132 * This defeats hacking attempts that use timing based attack vectors.
133 *
134 * NOTE: Length will leak.
135 *
136 * @param string $known A known string to check against.
137 * @param string $unknown An unknown string to check.
138 *
139 * @return boolean True if the two strings are exactly the same.
140 *
141 * @since 3.2
142 */
143 public static function timingSafeCompare($known, $unknown)
144 {
145 // This function is native in PHP as of 5.6 and backported via the symfony/polyfill-56 library
146 return hash_equals((string) $known, (string) $unknown);
147 }
148
149 /**
150 * Tests for the availability of updated crypt().
151 * Based on a method by Anthony Ferrera
152 *
153 * @return boolean Always returns true since 3.3
154 *
155 * @note To be removed when PHP 5.3.7 or higher is the minimum supported version.
156 * @link https://github.com/ircmaxell/password_compat/blob/master/version-test.php
157 * @since 3.2
158 * @deprecated 4.0
159 */
160 public static function hasStrongPasswordSupport()
161 {
162 // Log usage of deprecated function
163 JLog::add(__METHOD__ . '() is deprecated without replacement.', JLog::WARNING, 'deprecated');
164
165 if (!defined('PASSWORD_DEFAULT'))
166 {
167 // Always make sure that the password hashing API has been defined.
168 include_once JPATH_ROOT . '/vendor/ircmaxell/password-compat/lib/password.php';
169 }
170
171 return true;
172 }
173
174 /**
175 * Safely detect a string's length
176 *
177 * This method is derived from \ParagonIE\Halite\Util::safeStrlen()
178 *
179 * @param string $str String to check the length of
180 *
181 * @return integer
182 *
183 * @since 3.5
184 * @ref mbstring.func_overload
185 * @throws RuntimeException
186 */
187 public static function safeStrlen($str)
188 {
189 static $exists = null;
190
191 if ($exists === null)
192 {
193 $exists = function_exists('mb_strlen');
194 }
195
196 if ($exists)
197 {
198 $length = mb_strlen($str, '8bit');
199
200 if ($length === false)
201 {
202 throw new RuntimeException('mb_strlen() failed unexpectedly');
203 }
204
205 return $length;
206 }
207
208 // If we reached here, we can rely on strlen to count bytes:
209 return \strlen($str);
210 }
211
212 /**
213 * Safely extract a substring
214 *
215 * This method is derived from \ParagonIE\Halite\Util::safeSubstr()
216 *
217 * @param string $str The string to extract the substring from
218 * @param integer $start The starting position to extract from
219 * @param integer $length The length of the string to return
220 *
221 * @return string
222 *
223 * @since 3.5
224 */
225 public static function safeSubstr($str, $start, $length = null)
226 {
227 static $exists = null;
228
229 if ($exists === null)
230 {
231 $exists = function_exists('mb_substr');
232 }
233
234 if ($exists)
235 {
236 // In PHP 5.3 mb_substr($str, 0, NULL, '8bit') returns an empty string, so we have to find the length ourselves.
237 if ($length === null)
238 {
239 if ($start >= 0)
240 {
241 $length = static::safeStrlen($str) - $start;
242 }
243 else
244 {
245 $length = -$start;
246 }
247 }
248
249 return mb_substr($str, $start, $length, '8bit');
250 }
251
252 // Unlike mb_substr(), substr() doesn't accept NULL for length
253 if ($length !== null)
254 {
255 return substr($str, $start, $length);
256 }
257
258 return substr($str, $start);
259 }
260 }
261