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 cipher for mcrypt algorithm encryption, decryption and key generation.
14 *
15 * @since 12.1
16 * @deprecated 4.0 Without replacment use JCryptCipherCrypto
17 */
18 abstract class JCryptCipherMcrypt implements JCryptCipher
19 {
20 /**
21 * @var integer The mcrypt cipher constant.
22 * @link https://secure.php.net/manual/en/mcrypt.ciphers.php
23 * @since 12.1
24 */
25 protected $type;
26
27 /**
28 * @var integer The mcrypt block cipher mode.
29 * @link https://secure.php.net/manual/en/mcrypt.constants.php
30 * @since 12.1
31 */
32 protected $mode;
33
34 /**
35 * @var string The JCrypt key type for validation.
36 * @since 12.1
37 */
38 protected $keyType;
39
40 /**
41 * Constructor.
42 *
43 * @since 12.1
44 * @throws RuntimeException
45 */
46 public function __construct()
47 {
48 if (!is_callable('mcrypt_encrypt'))
49 {
50 throw new RuntimeException('The mcrypt extension is not available.');
51 }
52 }
53
54 /**
55 * Method to decrypt a data string.
56 *
57 * @param string $data The encrypted string to decrypt.
58 * @param JCryptKey $key The key object to use for decryption.
59 *
60 * @return string The decrypted data string.
61 *
62 * @since 12.1
63 * @throws InvalidArgumentException
64 */
65 public function decrypt($data, JCryptKey $key)
66 {
67 // Validate key.
68 if ($key->type != $this->keyType)
69 {
70 throw new InvalidArgumentException('Invalid key of type: ' . $key->type . '. Expected ' . $this->keyType . '.');
71 }
72
73 // Decrypt the data.
74 $decrypted = trim(mcrypt_decrypt($this->type, $key->private, $data, $this->mode, $key->public));
75
76 return $decrypted;
77 }
78
79 /**
80 * Method to encrypt a data string.
81 *
82 * @param string $data The data string to encrypt.
83 * @param JCryptKey $key The key object to use for encryption.
84 *
85 * @return string The encrypted data string.
86 *
87 * @since 12.1
88 * @throws InvalidArgumentException
89 */
90 public function encrypt($data, JCryptKey $key)
91 {
92 // Validate key.
93 if ($key->type != $this->keyType)
94 {
95 throw new InvalidArgumentException('Invalid key of type: ' . $key->type . '. Expected ' . $this->keyType . '.');
96 }
97
98 // Encrypt the data.
99 $encrypted = mcrypt_encrypt($this->type, $key->private, $data, $this->mode, $key->public);
100
101 return $encrypted;
102 }
103
104 /**
105 * Method to generate a new encryption key object.
106 *
107 * @param array $options Key generation options.
108 *
109 * @return JCryptKey
110 *
111 * @since 12.1
112 * @throws InvalidArgumentException
113 */
114 public function generateKey(array $options = array())
115 {
116 // Create the new encryption key object.
117 $key = new JCryptKey($this->keyType);
118
119 // Generate an initialisation vector based on the algorithm.
120 $key->public = mcrypt_create_iv(mcrypt_get_iv_size($this->type, $this->mode), MCRYPT_DEV_URANDOM);
121
122 // Get the salt and password setup.
123 $salt = (isset($options['salt'])) ? $options['salt'] : substr(pack('h*', md5(JCrypt::genRandomBytes())), 0, 16);
124
125 if (!isset($options['password']))
126 {
127 throw new InvalidArgumentException('Password is not set.');
128 }
129
130 // Generate the derived key.
131 $key->private = $this->pbkdf2($options['password'], $salt, mcrypt_get_key_size($this->type, $this->mode));
132
133 return $key;
134 }
135
136 /**
137 * PBKDF2 Implementation for deriving keys.
138 *
139 * @param string $p Password
140 * @param string $s Salt
141 * @param integer $kl Key length
142 * @param integer $c Iteration count
143 * @param string $a Hash algorithm
144 *
145 * @return string The derived key.
146 *
147 * @link https://en.wikipedia.org/wiki/PBKDF2
148 * @link http://www.ietf.org/rfc/rfc2898.txt
149 * @since 12.1
150 */
151 public function pbkdf2($p, $s, $kl, $c = 10000, $a = 'sha256')
152 {
153 // Hash length.
154 $hl = strlen(hash($a, null, true));
155
156 // Key blocks to compute.
157 $kb = ceil($kl / $hl);
158
159 // Derived key.
160 $dk = '';
161
162 // Create the key.
163 for ($block = 1; $block <= $kb; $block++)
164 {
165 // Initial hash for this block.
166 $ib = $b = hash_hmac($a, $s . pack('N', $block), $p, true);
167
168 // Perform block iterations.
169 for ($i = 1; $i < $c; $i++)
170 {
171 $ib ^= ($b = hash_hmac($a, $b, $p, true));
172 }
173
174 // Append the iterated block.
175 $dk .= $ib;
176 }
177
178 // Return derived key of correct length.
179 return substr($dk, 0, $kl);
180 }
181 }
182