Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * TSecurityManager class file
4
 *
5
 * @author Qiang Xue <qiang.xue@gmail.com>
6
 * @link http://www.pradosoft.com/
7
 * @copyright Copyright &copy; 2005-2008 PradoSoft
8
 * @license http://www.pradosoft.com/license/
9
 * @version $Id: TSecurityManager.php 2541 2008-10-21 15:05:13Z qiang.xue $
10
 * @package System.Security
11
 */
12
 
13
/**
14
 * TSecurityManager class
15
 *
16
 * TSecurityManager provides private keys, hashing and encryption
17
 * functionalities that may be used by other PRADO components,
18
 * such as viewstate persister, cookies.
19
 *
20
 * TSecurityManager is mainly used to protect data from being tampered
21
 * and viewed. It can generate HMAC and encrypt the data.
22
 * The private key used to generate HMAC is set by {@link setValidationKey ValidationKey}.
23
 * The key used to encrypt data is specified by {@link setEncryptionKey EncryptionKey}.
24
 * If the above keys are not explicitly set, random keys will be generated
25
 * and used.
26
 *
27
 * To prefix data with an HMAC, call {@link hashData()}.
28
 * To validate if data is tampered, call {@link validateData()}, which will
29
 * return the real data if it is not tampered.
30
 * The algorithm used to generated HMAC is specified by {@link setValidation Validation}.
31
 *
32
 * To encrypt and decrypt data, call {@link encrypt()} and {@link decrypt()}
33
 * respectively. The encryption algorithm can be set by {@link setEncryption Encryption}.
34
 *
35
 * Note, to use encryption, the PHP Mcrypt extension must be loaded.
36
 *
37
 * @author Qiang Xue <qiang.xue@gmail.com>
38
 * @version $Id: TSecurityManager.php 2541 2008-10-21 15:05:13Z qiang.xue $
39
 * @package System.Security
40
 * @since 3.0
41
 */
42
class TSecurityManager extends TModule
43
{
44
	const STATE_VALIDATION_KEY='prado:securitymanager:validationkey';
45
	const STATE_ENCRYPTION_KEY='prado:securitymanager:encryptionkey';
46
	private $_validationKey=null;
47
	private $_encryptionKey=null;
48
	private $_validation=TSecurityManagerValidationMode::SHA1;
49
	private $_encryption='3DES';
50
 
51
	/**
52
	 * Initializes the module.
53
	 * The security module is registered with the application.
54
	 * @param TXmlElement initial module configuration
55
	 */
56
	public function init($config)
57
	{
58
		$this->getApplication()->setSecurityManager($this);
59
	}
60
 
61
	/**
62
	 * Generates a random key.
63
	 */
64
	protected function generateRandomKey()
65
	{
66
		return rand().rand().rand().rand();
67
	}
68
 
69
	/**
70
	 * @return string the private key used to generate HMAC.
71
	 * If the key is not explicitly set, a random one is generated and returned.
72
	 */
73
	public function getValidationKey()
74
	{
75
		if($this->_validationKey===null)
76
		{
77
			if(($this->_validationKey=$this->getApplication()->getGlobalState(self::STATE_VALIDATION_KEY))===null)
78
			{
79
				$this->_validationKey=$this->generateRandomKey();
80
				$this->getApplication()->setGlobalState(self::STATE_VALIDATION_KEY,$this->_validationKey,null);
81
			}
82
		}
83
		return $this->_validationKey;
84
	}
85
 
86
	/**
87
	 * @param string the key used to generate HMAC
88
	 * @throws TInvalidDataValueException if the key is empty
89
	 */
90
	public function setValidationKey($value)
91
	{
92
		if($value!=='')
93
			$this->_validationKey=$value;
94
		else
95
			throw new TInvalidDataValueException('securitymanager_validationkey_invalid');
96
	}
97
 
98
	/**
99
	 * @return string the private key used to encrypt/decrypt data.
100
	 * If the key is not explicitly set, a random one is generated and returned.
101
	 */
102
	public function getEncryptionKey()
103
	{
104
		if($this->_encryptionKey===null)
105
		{
106
			if(($this->_encryptionKey=$this->getApplication()->getGlobalState(self::STATE_ENCRYPTION_KEY))===null)
107
			{
108
				$this->_encryptionKey=$this->generateRandomKey();
109
				$this->getApplication()->setGlobalState(self::STATE_ENCRYPTION_KEY,$this->_encryptionKey,null);
110
			}
111
		}
112
		return $this->_encryptionKey;
113
	}
114
 
115
	/**
116
	 * @param string the key used to encrypt/decrypt data.
117
	 * @throws TInvalidDataValueException if the key is empty
118
	 */
119
	public function setEncryptionKey($value)
120
	{
121
		if($value!=='')
122
			$this->_encryptionKey=$value;
123
		else
124
			throw new TInvalidDataValueException('securitymanager_encryptionkey_invalid');
125
	}
126
 
127
	/**
128
	 * @return TSecurityManagerValidationMode hashing algorithm used to generate HMAC. Defaults to TSecurityManagerValidationMode::SHA1.
129
	 */
130
	public function getValidation()
131
	{
132
		return $this->_validation;
133
	}
134
 
135
	/**
136
	 * @param TSecurityManagerValidationMode hashing algorithm used to generate HMAC.
137
	 */
138
	public function setValidation($value)
139
	{
140
		$this->_validation=TPropertyValue::ensureEnum($value,'TSecurityManagerValidationMode');
141
	}
142
 
143
	/**
144
	 * @return string the algorithm used to encrypt/decrypt data. Defaults to '3DES'.
145
	 */
146
	public function getEncryption()
147
	{
148
		return $this->_encryption;
149
	}
150
 
151
	/**
152
	 * @throws TNotSupportedException Do not call this method presently.
153
	 */
154
	public function setEncryption($value)
155
	{
156
		throw new TNotSupportedException('Currently only 3DES encryption is supported');
157
	}
158
 
159
	/**
160
	 * Encrypts data with {@link getEncryptionKey EncryptionKey}.
161
	 * @param string data to be encrypted.
162
	 * @return string the encrypted data
163
	 * @throws TNotSupportedException if PHP Mcrypt extension is not loaded
164
	 */
165
	public function encrypt($data)
166
	{
167
		if(function_exists('mcrypt_encrypt'))
168
		{
169
			$module=mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, '');
170
			$key=substr(md5($this->getEncryptionKey()),0,mcrypt_enc_get_key_size($module));
171
			srand();
172
			$iv=mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
173
			mcrypt_generic_init($module,$key,$iv);
174
			$encrypted=$iv.mcrypt_generic($module,$data);
175
			mcrypt_generic_deinit($module);
176
			mcrypt_module_close($module);
177
			return $encrypted;
178
		}
179
		else
180
			throw new TNotSupportedException('securitymanager_mcryptextension_required');
181
	}
182
 
183
	/**
184
	 * Decrypts data with {@link getEncryptionKey EncryptionKey}.
185
	 * @param string data to be decrypted.
186
	 * @return string the decrypted data
187
	 * @throws TNotSupportedException if PHP Mcrypt extension is not loaded
188
	 */
189
	public function decrypt($data)
190
	{
191
		if(function_exists('mcrypt_decrypt'))
192
		{
193
			$module=mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, '');
194
			$key=substr(md5($this->getEncryptionKey()),0,mcrypt_enc_get_key_size($module));
195
			$ivSize=mcrypt_enc_get_iv_size($module);
196
			$iv=substr($data,0,$ivSize);
197
			mcrypt_generic_init($module,$key,$iv);
198
			$decrypted=mdecrypt_generic($module,substr($data,$ivSize));
199
			mcrypt_generic_deinit($module);
200
			mcrypt_module_close($module);
201
			return rtrim($decrypted,"\0");
202
		}
203
		else
204
			throw new TNotSupportedException('securitymanager_mcryptextension_required');
205
	}
206
 
207
	/**
208
	 * Prefixes data with an HMAC.
209
	 * @param string data to be hashed.
210
	 * @return string data prefixed with HMAC
211
	 */
212
	public function hashData($data)
213
	{
214
		$hmac=$this->computeHMAC($data);
215
		return $hmac.$data;
216
	}
217
 
218
	/**
219
	 * Validates if data is tampered.
220
	 * @param string data to be validated. The data must be previously
221
	 * generated using {@link hashData()}.
222
	 * @return string the real data with HMAC stripped off. False if the data
223
	 * is tampered.
224
	 */
225
	public function validateData($data)
226
	{
227
		$len=$this->_validation==='SHA1'?40:32;
228
		if(strlen($data)>=$len)
229
		{
230
			$hmac=substr($data,0,$len);
231
			$data2=substr($data,$len);
232
			return $hmac===$this->computeHMAC($data2)?$data2:false;
233
		}
234
		else
235
			return false;
236
	}
237
 
238
	/**
239
	 * Computes the HMAC for the data with {@link getValidationKey ValidationKey}.
240
	 * @param string data to be generated HMAC
241
	 * @return string the HMAC for the data
242
	 */
243
	protected function computeHMAC($data)
244
	{
245
		if($this->_validation==='SHA1')
246
		{
247
			$pack='H40';
248
			$func='sha1';
249
		}
250
		else
251
		{
252
			$pack='H32';
253
			$func='md5';
254
		}
255
		$key=$this->getValidationKey();
256
		$key=str_pad($func($key), 64, chr(0));
257
		return $func((str_repeat(chr(0x5C), 64) ^ substr($key, 0, 64)) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ substr($key, 0, 64)) . $data)));
258
	}
259
}
260
 
261
 
262
/**
263
 * TSecurityManagerValidationMode class.
264
 * TSecurityManagerValidationMode defines the enumerable type for the possible validation modes
265
 * that can be used by {@link TSecurityManager}.
266
 *
267
 * The following enumerable values are defined:
268
 * - MD5: an MD5 hash is generated from the data and used for validation.
269
 * - SHA1: an SHA1 hash is generated from the data and used for validation.
270
 *
271
 * @author Qiang Xue <qiang.xue@gmail.com>
272
 * @version $Id: TSecurityManager.php 2541 2008-10-21 15:05:13Z qiang.xue $
273
 * @package System.Security
274
 * @since 3.0.4
275
 */
276
class TSecurityManagerValidationMode extends TEnumerable
277
{
278
	const MD5='MD5';
279
	const SHA1='SHA1';
280
}
281