/[drupal]/contributions/modules/aes/aes.module
ViewVC logotype

Contents of /contributions/modules/aes/aes.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (show annotations) (download) (as text)
Tue Apr 10 17:41:40 2007 UTC (2 years, 7 months ago) by amc
Branch: MAIN
CVS Tags: DRUPAL-5--1-1, HEAD
Changes since 1.1: +221 -110 lines
File MIME type: text/x-php
Commit of 1.1-version.
1 <?php
2 // $Id $
3
4 define("AES_PASSWORD_MAX_LENGTH", 128);
5
6 function aes_menu($may_cache) {
7 $items = array();
8
9 if (!$may_cache) {
10 $items[] = array(
11 'path' => 'admin/settings/aes',
12 'title' => t('AES settings'),
13 'callback' => 'drupal_get_form',
14 'callback arguments' => 'aes_config',
15 'access' => user_access('administer aes'),
16 'description' => t('Configure the AES encryption module.'),
17 'type' => MENU_NORMAL_ITEM,
18 );
19
20 if (arg(0) == 'user') {
21 if (aes_password_exists(arg(1)) && (variable_get("aes_viewing_method", "collapsible") == "page" || variable_get("aes_viewing_method", "collapsible") == "both")) {
22 $items[] = array(
23 'path' => 'user/'.arg(1).'/password',
24 'title' => t('View password'),
25 'callback' => 'aes_get_password',
26 'callback arguments' => array(arg(1), true),
27 'access' => user_access('view passwords'),
28 'type' => MENU_LOCAL_TASK,
29 );
30 }
31 }
32
33 $items[] = array(
34 'path' => 'aes/test',
35 'callback' => 'aes_test',
36 'type' => MENU_CALLBACK,
37 'access' => true,
38 );
39
40 }
41
42 return $items;
43 }
44
45
46 function aes_perm() {
47 return array('administer aes', 'view passwords');
48 }
49
50 function aes_config() {
51
52 if (file_exists(variable_get("aes_key_path", "")) && is_writable(variable_get("aes_key_path", "")) == false && variable_get("aes_key_storage_method", "") == "File") {
53 drupal_set_message(t("The keyfile %keyfile_path is not writable. This module needs to be able to write to this file to update the encryption key.", array('%keyfile_path' => variable_get("aes_key_path", ""))), "error");
54 }
55
56 $form = array();
57
58 $form['aes'] = array(
59 '#type' => 'fieldset',
60 '#title' => t('AES settings'),
61 '#collapsible' => false,
62 );
63
64
65 $form['aes']['aes_convert'] = array(
66 '#type' => 'checkbox',
67 '#title' => t('Create AES passwords'),
68 '#default_value' => (variable_get("aes_convert", "false") == "true") ? true : false,
69 '#description' => t('Check this box if you would like to start creating AES passwords. Note that this is a process since we can only get an existing users password in plain text at the moment this user logs in. In other words, you won\'t be able to view an existing users password until that user has logged in at least once after you checked this box.'),
70 );
71
72 $form['aes']['view_method'] = array(
73 '#type' => 'select',
74 '#title' => t('Method for viewing passwords'),
75 '#options' => array('collapsible' => t('Sliding frame'), 'page' => t('Own page'), 'both' => t('Both')),
76 '#default_value' => variable_get("aes_viewing_method", "collapsible"),
77 '#description' => t('Wether to show the password as a sliding frame on the user info page (hidden by default) or on a separate page with a tab on the user page, or both.'),
78 );
79
80 $form['aes']['aes_cipher'] = array(
81 '#type' => 'select',
82 '#title' => t('Cipher'),
83 '#options' => array('rijndael-128' => 'Rijndael 128', 'rijndael-192' => 'Rijndael 192', 'rijndael-256' => 'Rijndael 256'),
84 '#default_value' => variable_get("aes_cipher", "rijndael-128"),
85 );
86
87 $form['aes']['aes_key_storage_method'] = array(
88 '#type' => 'select',
89 '#title' => t('Key storage method'),
90 '#options' => array('Database' => 'Database', 'File' => 'File'),
91 '#default_value' => variable_get("aes_key_storage_method", ""),
92 '#description' => t('If possible, you should use the file storage method and assign a path below.'),
93 );
94
95 $form['aes']['aes_key_path'] = array(
96 '#type' => 'textfield',
97 '#title' => t('Path to keyfile'),
98 '#default_value' => variable_get("aes_key_path", ""),
99 '#description' => t('The path, including the filename, of the file in which to store your key. The access restrictions on this file should be set as high as possible while still allowing PHP read/write access.'),
100 );
101
102 $form['aes']['aes_key'] = array(
103 '#type' => 'password',
104 '#title' => t('Key'),
105 '#description' => t("The key for your encryption system. You normally don't need to worry about this since this module will generate a key for you if none is specified. However you have the option of using your own custom key here."),
106 );
107
108 $form['aes']['aes_key_c'] = array(
109 '#type' => 'password',
110 '#title' => t('Confirm key'),
111 );
112
113 $form['aes']['submit'] = array(
114 '#type' => 'submit',
115 '#value' => t('Save'),
116 );
117
118
119 return $form;
120 }
121
122 function aes_config_validate($form_id, $form) {
123 if (!empty($form['aes_key'])) {
124 if ($form['aes_key'] !== $form['aes_key_c']) {
125 form_set_error("aes_key", t("The encryption keys didn't match."));
126 }
127 }
128
129 //if the storage method is set to File, check that the file can be openend for writing
130 if ($form['aes_key_storage_method'] == "File") {
131 $fp = @fopen($form['aes_key_path'], "a");
132
133 if ($fp === false) {
134 form_set_error("aes_key_path", t("Can't write to the specified location."));
135 }
136 else {
137 fclose($fp);
138 }
139 }
140
141 }
142
143 function aes_config_submit($form_id, $form) {
144 if ($form['aes_convert']) {
145 variable_set("aes_convert", "true");
146 }
147 else {
148 variable_set("aes_convert", "false");
149 }
150
151 variable_set("aes_key_path", $form['aes_key_path']);
152
153 //check if the storage method has changed
154 if ($form['aes_key_storage_method'] != variable_get("aes_key_storage_method", "")) {
155 //if it has changed, we need to move the key to the new storage
156 drupal_set_message(t("Switching key storage method to !method.", array('!method' => $form['aes_key_storage_method'])));
157 //get the key
158 $key = aes_get_key();
159 //delete the key from the old storage
160 aes_delete_key(variable_get("aes_key_storage_method", ""));
161 //set the new storage
162 variable_set("aes_key_storage_method", $form['aes_key_storage_method']);
163 //store the key in its new location
164 aes_store_key($key);
165 }
166
167 //if the cipher has changed...
168 if ($form['aes_cipher'] != variable_get("aes_cipher", "rijndael-128")) {
169 $result = db_query("SELECT uid, pass FROM {aes_passwords}");
170
171 $old_cipher = variable_get("aes_cipher", "rijndael-128");
172 variable_set("aes_cipher", $form['aes_cipher']);
173 $new_cipher = $form['aes_cipher'];
174
175 //get the old iv
176 $old_iv = variable_get("aes_encryption_iv", "");
177 //update the cipher the system uses
178 variable_set("aes_cipher", $form['aes_cipher']);
179 //create a new iv to match the new cipher
180 aes_make_iv();
181 //get the new iv
182 $new_iv = variable_get("aes_encryption_iv", "");
183
184 $updates_num = 0;
185 while ($user = db_fetch_array($result)) {
186
187 $plain_pass = trim(aes_decrypt($user['pass'], true, null, $old_cipher, $old_iv));
188 $new_pass = aes_encrypt($plain_pass, true, null, $new_cipher, $new_iv);
189
190 $updates_num++;
191 db_query("UPDATE {aes_passwords} SET pass='%s' WHERE uid=%d", $new_pass, $user['uid']);
192 }
193 drupal_set_message(t("Updated the passwords of !updates_num users because of a change in cipher.", array('!updates_num' => $updates_num)));
194 }
195
196 //if the key has changed...
197 if (!empty($form['aes_key'])) {
198 $old_key = aes_get_key();
199 $result = aes_store_key($form['aes_key']);
200
201 if ($result === false) {
202 drupal_set_message(t("Failed to write new encryption key! Aborting."));
203 return;
204 }
205
206 drupal_set_message(t("Key changed."));
207
208 //since the key has changed we need to re-encrypt all the passwords with the new key (except the anonymous account)
209 $a = db_query("SELECT uid, pass FROM {aes_passwords} WHERE uid != 0");
210
211 $updates_num = 0;
212 while ($user = db_fetch_array($a)) {
213 $plain_pass = trim(aes_decrypt($user['pass'], true, $old_key));
214 $new_pass = aes_encrypt($plain_pass, true, $form['aes_key']);
215 $updates_num++;
216
217 db_query("UPDATE {aes_passwords} SET pass='%s' WHERE uid=%d", $new_pass, $user['uid']);
218 }
219
220 drupal_set_message(t("Updated the passwords of !updates_num users because of a change in key.", array('!updates_num' => $updates_num)));
221
222 }
223
224 variable_set("aes_viewing_method", $form['view_method']);
225
226 }
227
228 function aes_user($op, &$edit, &$account, $category = null) {
229 if ($op == "view") {
230
231 $info = array();
232 $info['AES'] = array();
233
234 if (user_access('view passwords') && (variable_get("aes_viewing_method", "page") == "collapsible" || variable_get("aes_viewing_method", "page") == "both") && aes_password_exists($account->uid)) {
235 $info['AES']['title'] = t('Password');
236 $info['AES']['class'] = 'member';
237 $info['AES']['value'] = drupal_get_form('view_pw_form', aes_get_password($account->uid, true));
238 return array('Info' => $info);
239 }
240
241 }
242
243 if ($op == "login") {
244 if (variable_get("aes_convert", "true") == "true" && aes_password_exists($account->uid) == false) {
245 db_query("INSERT INTO {aes_passwords} (uid, pass) VALUES (%d, '%s')", $account->uid, aes_encrypt($edit['pass']));
246 }
247 }
248
249 if ($op == "update" || $op == "insert") {
250 if (!empty($edit['pass'])) {
251
252 $password = aes_encrypt($edit['pass']);
253
254 if (strlen($password) > AES_PASSWORD_MAX_LENGTH) {
255 $edit['pass'] = null;
256 drupal_set_message(t("Couldn't update AES password since it's too long.", "error"));
257 }
258 else {
259 db_query("DELETE FROM {aes_passwords} WHERE uid=%d", $account->uid);
260 db_query("INSERT INTO {aes_passwords} (uid, pass) VALUES (%d, '%s')", $account->uid, $password);
261 }
262 }
263 }
264 }
265
266
267 function view_pw_form($password) {
268
269 $form['password'] = array(
270 '#type' => 'fieldset',
271 '#title' => t('Show password'),
272 '#description' => $password,
273 '#collapsible' => true,
274 '#collapsed' => true,
275 );
276
277 return $form;
278 }
279
280 function aes_password_exists($uid) {
281 return db_num_rows(db_query("SELECT uid FROM {aes_passwords} WHERE uid=%d", $uid));
282 }
283
284 function aes_get_password($uid, $decrypt = false) {
285 $result = db_query("SELECT pass FROM {aes_passwords} WHERE uid=%d", $uid);
286 if (db_num_rows($result) == 1) {
287 $user = db_fetch_array($result);
288 }
289 if ($decrypt) {
290 return trim(aes_decrypt($user['pass']));
291 }
292 else {
293 return $user['pass'];
294 }
295 }
296
297 function aes_get_key() {
298 $storage_method = variable_get("aes_key_storage_method", "database");
299
300 if ($storage_method == "Database") {
301 $key = variable_get("aes_key", false);
302 if ($key === false) {
303 $key = aes_make_key();
304 aes_store_key($key);
305 drupal_set_message(t("AES module made a new key since one couldn't be found by using the database storage method."));
306 }
307 }
308 if ($storage_method == "File") {
309 $key = file_get_contents(variable_get("aes_key_path", ""));
310 if ($key === false) {
311 $key = aes_make_key();
312 aes_store_key($key);
313 drupal_set_message(t("AES module made a new key since one couldn't be found by using the file storage method."));
314 }
315 }
316
317 return $key;
318 }
319
320 function aes_store_key($key) {
321 $storage_method = variable_get("aes_key_storage_method", "Database");
322
323 if ($storage_method == "Database") {
324 variable_set("aes_key", $key);
325 }
326 else if ($storage_method == "File") {
327 $result = file_put_contents(variable_get("aes_key_path", ""), $key);
328
329 $fp = fopen(variable_get("aes_key_path", ""), "w");
330 if ($fp === false) {
331 drupal_set_message(t("Couldn't write key to file ".variable_get("aes_key_path", "")), "error");
332 return false;
333 }
334 $key = fwrite($fp, $key);
335 fclose($fp);
336 }
337 else {
338 drupal_set_message(t("Unknown storage method in AES module."), "error");
339 return false;
340 }
341
342 return true;
343 }
344
345 function aes_delete_key($storage_method) {
346
347 if ($storage_method == "Database") {
348 variable_del("aes_key");
349 }
350 if ($storage_method == "File") {
351 $result = unlink(variable_get("aes_key_path", ""));
352 if ($result === false) {
353 drupal_set_message(t("Couldn't delete keyfile!"), "error");
354 }
355 }
356 }
357
358 function aes_make_key() {
359
360 $acceptable = false;
361
362 $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
363
364 while ($acceptable === false) {
365
366 $key = "";
367
368 while (strlen($key) < 32) {
369 $key .= substr($chars, rand(0, strlen($chars)), 1);
370 }
371
372 $acceptable = true;
373
374 $matches = array();
375
376 //is there at least one lowercase letter?
377 $result = preg_match("/.*[a-z].*/", $key, &$matches);
378
379 if($result == 0) {
380 $acceptable = false;
381 }
382
383 //is there at least one uppercase letter?
384 $result = preg_match("/.*[A-Z].*/", $key, &$matches);
385
386 if($result == 0) {
387 $acceptable = false;
388 }
389
390 //is there at least one numeric?
391 $result = preg_match("/.*[0-9].*/", $key, &$matches);
392
393 if($result == 0) {
394 $acceptable = false;
395 }
396 }
397
398 return $key;
399 }
400
401 function aes_make_iv() {
402
403 if (strtoupper(substr(PHP_OS, 0, 3)) === "WIN") {
404 $randgen = MCRYPT_RAND;
405 }
406 else {
407 $randgen = MCRYPT_DEV_URANDOM;
408 }
409
410 $td = mcrypt_module_open(variable_get("aes_cipher", "rijndael-128"), "", MCRYPT_MODE_CBC, "");
411 $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), $randgen);
412 mcrypt_module_close($td);
413 variable_set("aes_encryption_iv", base64_encode($iv));
414 }
415
416 /**
417 Encrypts a string.
418 @param $string The string to encrypt.
419 @param $base64encode Whether to return the string base64 encoded (recommended for database insertion).
420 @param $custom_key Use this as the key rather than the stored one for this operation.
421 @param $custom_cipher Use this cipher rather than the default one.
422 @param $custom_iv Use this initialization vector instead of the default one.
423 @return The encrypted string.
424 */
425 function aes_encrypt($string, $base64encode = true, $custom_key = null, $custom_cipher = null, $custom_iv = null) {
426
427 if ($custom_cipher != null) {
428 $cipher = $custom_cipher;
429 }
430 else {
431 $cipher = variable_get("aes_cipher", "rijndael-128");
432 }
433
434 $td = mcrypt_module_open($cipher, "", MCRYPT_MODE_CBC, "");
435
436 if ($custom_iv == null) {
437 $iv = base64_decode(variable_get("aes_encryption_iv", ""));
438 }
439 else {
440 $iv = base64_decode($custom_iv);
441 }
442
443 if (empty($iv)) {
444 aes_make_iv();
445 $iv = base64_decode(variable_get("aes_encryption_iv", ""));
446 watchdog("aes", t("No initialization vector found while trying to encrypt! This could be a bit of a pain since you might have to reset all the passwords for all users. I've created a new one now and will try to carry on as normal."), WATCHDOG_WARNING);
447 }
448
449 $ks = mcrypt_enc_get_key_size($td);
450
451 if (!empty($custom_key)) {
452 $key = $custom_key;
453 }
454 else {
455 $key = aes_get_key();
456 }
457
458 $key = substr(sha1($key), 0, $ks);
459
460 mcrypt_generic_init($td, $key, $iv);
461 $encrypted = mcrypt_generic($td, $string);
462 mcrypt_generic_deinit($td);
463
464 mcrypt_module_close($td);
465
466 if ($base64encode) {
467 return base64_encode($encrypted);
468 }
469 else {
470 return $encrypted;
471 }
472 }
473
474 /**
475 Decrypts a string of encrypted data.
476 @param $string The string to decrypt.
477 @param $base64encoded Whether this encrypted string is base64 encoded or not.
478 @param $custom_key Use this as the key rather than the stored one for this operation.
479 @param $custom_cipher Use this cipher rather than the default one.
480 @param $custom_iv Use this initialization vector instead of the default one.
481 @return The decrypted string.
482 */
483 function aes_decrypt($string, $base64encoded = true, $custom_key = null, $custom_cipher = null, $custom_iv = null) {
484 if ($base64encoded) {
485 $string = base64_decode($string);
486 }
487
488 if ($custom_cipher != null) {
489 $cipher = $custom_cipher;
490 }
491 else {
492 $cipher = variable_get("aes_cipher", "rijndael-128");
493 }
494
495 $td = mcrypt_module_open($cipher, "", MCRYPT_MODE_CBC, "");
496 $ks = mcrypt_enc_get_key_size($td);
497
498 if ($custom_iv == null) {
499 $iv = base64_decode(variable_get("aes_encryption_iv", ""));
500 }
501 else {
502 $iv = base64_decode($custom_iv);
503 }
504
505 if (empty($iv)) {
506 watchdog("aes", t("No initialization vector found while trying to decrypt. Aborting!"), WATCHDOG_ERROR);
507 }
508
509 if (!empty($custom_key)) {
510 $key = $custom_key;
511 }
512 else {
513 $key = aes_get_key();
514 }
515
516 $key = substr(sha1($key), 0, $ks);
517
518 mcrypt_generic_init($td, $key, $iv);
519 $decrypted = mdecrypt_generic($td, $string);
520 mcrypt_generic_deinit($td);
521
522 mcrypt_module_close($td);
523
524 return $decrypted;
525 }
526
527 function aes_enable() {
528 if (extension_loaded("mcrypt") === false) {
529 drupal_set_message("The mcrypt PHP-extension is not loaded! The AES module can't work without this extension.", "error");
530 }
531
532 $iv = base64_decode(variable_get("aes_encryption_iv", ""));
533
534 if (empty($iv)) {
535 aes_make_iv();
536 }
537
538 }

  ViewVC Help
Powered by ViewVC 1.1.2