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

Diff of /contributions/modules/aes/aes.module

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

revision 1.1, Tue Mar 20 20:29:42 2007 UTC revision 1.1.2.1, Thu Dec 6 20:20:14 2007 UTC
# Line 1  Line 1 
1  <?php  <?php
2  // $Id$  // $Id $
3    
4    define("AES_PASSWORD_MAX_LENGTH", 128);
5    
6  function aes_menu($may_cache) {  function aes_menu($may_cache) {
7    $items = array();    $items = array();
# Line 7  function aes_menu($may_cache) { Line 9  function aes_menu($may_cache) {
9    if (!$may_cache) {    if (!$may_cache) {
10      $items[] = array(      $items[] = array(
11      'path' => 'admin/settings/aes',      'path' => 'admin/settings/aes',
12      'title' => 'AES settings',      'title' => t('AES settings'),
13      'callback' => 'drupal_get_form',      'callback' => 'drupal_get_form',
14      'callback arguments' => 'aes_config',      'callback arguments' => 'aes_config',
15      'access' => user_access('administer aes'),      'access' => user_access('administer aes'),
16      'description' => 'Configure the AES encryption module.',      'description' => t('Configure the AES encryption module.'),
17      'type' => MENU_NORMAL_ITEM,      '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    
34    return $items;    return $items;
# Line 27  function aes_perm() { Line 42  function aes_perm() {
42  function aes_config() {  function aes_config() {
43    
44    if (file_exists(variable_get("aes_key_path", "")) && is_writable(variable_get("aes_key_path", "")) == false && variable_get("aes_key_storage_method", "") == "File") {    if (file_exists(variable_get("aes_key_path", "")) && is_writable(variable_get("aes_key_path", "")) == false && variable_get("aes_key_storage_method", "") == "File") {
45      drupal_set_message("The keyfile (".variable_get("aes_key_path", "").") is not writable. This module needs to be able to write to this file to update the encryption key.", "error");      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");
46    }    }
47    
48    $form = array();    $form = array();
# Line 41  function aes_config() { Line 56  function aes_config() {
56    
57    $form['aes']['aes_convert'] = array(    $form['aes']['aes_convert'] = array(
58    '#type' => 'checkbox',    '#type' => 'checkbox',
59    '#title' => t('Convert passwords'),    '#title' => t('Create AES passwords'),
60    '#default_value' => (variable_get("aes_convert", "false") == "true") ? true : false,    '#default_value' => (variable_get("aes_convert", "false") == "true") ? true : false,
61    '#description' => t(''),    '#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.'),
62      );
63    
64      $form['aes']['view_method'] = array(
65      '#type' => 'select',
66      '#title' => t('Method for viewing passwords'),
67      '#options' => array('collapsible' => t('Sliding frame'), 'page' => t('Own page'), 'both' => t('Both')),
68      '#default_value' => variable_get("aes_viewing_method", "collapsible"),
69      '#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.'),
70      );
71    
72      $form['aes']['aes_cipher'] = array(
73      '#type' => 'select',
74      '#title' => t('Cipher'),
75      '#options' => array('rijndael-128' => 'Rijndael 128', 'rijndael-192' => 'Rijndael 192', 'rijndael-256' => 'Rijndael 256'),
76      '#default_value' => variable_get("aes_cipher", "rijndael-128"),
77    );    );
78    
79    $form['aes']['aes_key_storage_method'] = array(    $form['aes']['aes_key_storage_method'] = array(
# Line 51  function aes_config() { Line 81  function aes_config() {
81    '#title' => t('Key storage method'),    '#title' => t('Key storage method'),
82    '#options' => array('Database' => 'Database', 'File' => 'File'),    '#options' => array('Database' => 'Database', 'File' => 'File'),
83    '#default_value' => variable_get("aes_key_storage_method", ""),    '#default_value' => variable_get("aes_key_storage_method", ""),
84      '#description' => t('If possible, you should use the file storage method and assign a path below.'),
85    );    );
86    
87    $form['aes']['aes_key_path'] = array(    $form['aes']['aes_key_path'] = array(
88    '#type' => 'textfield',    '#type' => 'textfield',
89    '#title' => t('Path to keyfile'),    '#title' => t('Path to keyfile'),
90    '#default_value' => variable_get("aes_key_path", ""),    '#default_value' => variable_get("aes_key_path", ""),
91    '#description' => t(''),    '#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.'),
92    );    );
93    
94    $form['aes']['aes_key'] = array(    $form['aes']['aes_key'] = array(
95    '#type' => 'password',    '#type' => 'password',
96    '#title' => t('Key'),    '#title' => t('Key'),
97    '#description' => t(''),    '#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."),
98    );    );
99    
100    $form['aes']['aes_key_c'] = array(    $form['aes']['aes_key_c'] = array(
# Line 114  function aes_config_submit($form_id, $fo Line 145  function aes_config_submit($form_id, $fo
145    //check if the storage method has changed    //check if the storage method has changed
146    if ($form['aes_key_storage_method'] != variable_get("aes_key_storage_method", "")) {    if ($form['aes_key_storage_method'] != variable_get("aes_key_storage_method", "")) {
147      //if it has changed, we need to move the key to the new storage      //if it has changed, we need to move the key to the new storage
148      drupal_set_message(t("Switching key storage method to ".$form['aes_key_storage_method']."."));      drupal_set_message(t("Switching key storage method to !method.", array('!method' => $form['aes_key_storage_method'])));
149      //get the key      //get the key
150      $key = aes_get_key();      $key = aes_get_key();
151      //delete the key from the old storage      //delete the key from the old storage
# Line 125  function aes_config_submit($form_id, $fo Line 156  function aes_config_submit($form_id, $fo
156      aes_store_key($key);      aes_store_key($key);
157    }    }
158    
159      //if the cipher has changed...
160      if ($form['aes_cipher'] != variable_get("aes_cipher", "rijndael-128")) {
161        $result = db_query("SELECT uid, pass FROM {aes_passwords} WHERE uid != 0");
162    
163        $old_cipher = variable_get("aes_cipher", "rijndael-128");
164        variable_set("aes_cipher", $form['aes_cipher']);
165        $new_cipher = $form['aes_cipher'];
166    
167        //get the old iv
168        $old_iv = variable_get("aes_encryption_iv", "");
169        //update the cipher the system uses
170        variable_set("aes_cipher", $form['aes_cipher']);
171        //create a new iv to match the new cipher
172        aes_make_iv();
173        //get the new iv
174        $new_iv = variable_get("aes_encryption_iv", "");
175    
176        $updates_num = 0;
177        while ($user = db_fetch_array($result)) {
178    
179          $plain_pass = trim(aes_decrypt($user['pass'], true, null, $old_cipher, $old_iv));
180          $new_pass = aes_encrypt($plain_pass, true, null, $new_cipher, $new_iv);
181    
182          $updates_num++;
183          db_query("UPDATE {aes_passwords} SET pass='%s' WHERE uid=%d", $new_pass, $user['uid']);
184        }
185        drupal_set_message(t("Updated the passwords of !updates_num users because of a change in cipher.", array('!updates_num' => $updates_num)));
186      }
187    
188    //if the key has changed...    //if the key has changed...
189    if (!empty($form['aes_key'])) {    if (!empty($form['aes_key'])) {
190      $old_key = aes_get_key();      $old_key = aes_get_key();
# Line 138  function aes_config_submit($form_id, $fo Line 198  function aes_config_submit($form_id, $fo
198      drupal_set_message(t("Key changed."));      drupal_set_message(t("Key changed."));
199    
200      //since the key has changed we need to re-encrypt all the passwords with the new key (except the anonymous account)      //since the key has changed we need to re-encrypt all the passwords with the new key (except the anonymous account)
201      $a = db_query("SELECT uid, pass FROM {users} WHERE uid != 0");      $a = db_query("SELECT uid, pass FROM {aes_passwords} WHERE uid != 0");
202    
203      $updates_num = 0;      $updates_num = 0;
204      while ($user = db_fetch_array($a)) {      while ($user = db_fetch_array($a)) {
205        //since we might be dealing with a database consisting of mixed MD5 and AES passwords, assume an MD5 pass if the string is 32 characters long        $plain_pass = trim(aes_decrypt($user['pass'], true, $old_key));
206        if (aes_password_type($user['pass']) != "md5") {        $new_pass = aes_encrypt($plain_pass, true, $form['aes_key']);
207          $plain_pass = trim(aes_decrypt($user['pass'], true, $old_key));        $updates_num++;
         $new_pass = aes_encrypt($plain_pass, true, $form['aes_key']);  
         $updates_num++;  
       }  
       else {  
         $new_pass = $user['pass'];  
       }  
208    
209        db_query("UPDATE {users} SET pass='".$new_pass."' WHERE uid=".$user['uid']);        db_query("UPDATE {aes_passwords} SET pass='%s' WHERE uid=%d", $new_pass, $user['uid']);
210      }      }
211    
212      drupal_set_message(t("Updated the passwords of ".$updates_num." users."));      drupal_set_message(t("Updated the passwords of !updates_num users because of a change in key.", array('!updates_num' => $updates_num)));
213    
214    }    }
215    
216  }    variable_set("aes_viewing_method", $form['view_method']);
   
 function aes_auth($username, $password, $server) {  
   
   $result = db_query("SELECT uid FROM {users} WHERE name='".db_escape_string($username)."' AND pass='".aes_encrypt($password)."'");  
   
   if (db_num_rows($result) > 0) {  
     return true;  
   }  
   else {  
     return false;  
   }  
 }  
   
 function aes_info($field = 0) {  
   $info['name'] = "AES";  
   $info['protocol'] = "HTTP";  
217    
   if ($field) {  
     return $info[$field];  
   }  
   else {  
     return $info;  
   }  
218  }  }
219    
220  function aes_user($op, &$edit, &$account, $category = null) {  function aes_user($op, &$edit, &$account, $category = null) {
# Line 191  function aes_user($op, &$edit, &$account Line 223  function aes_user($op, &$edit, &$account
223      $info = array();      $info = array();
224      $info['AES'] = array();      $info['AES'] = array();
225    
226      if (user_access('view passwords') && aes_password_type($account->pass) == "aes") {      if (user_access('view passwords') && (variable_get("aes_viewing_method", "page") == "collapsible" || variable_get("aes_viewing_method", "page") == "both") && aes_password_exists($account->uid)) {
227          $info['AES']['title'] = t('Password');
228        $info['AES']['value'] = drupal_get_form('view_pw_form');        $info['AES']['class'] = 'member';
229        $info['AES']['value'] = str_replace("[password]", trim(aes_decrypt($account->pass)), $info['AES']['value']);        $info['AES']['value'] = drupal_get_form('view_pw_form', aes_get_password($account->uid, true));
230      }        return array('Info' => $info);
     else if (aes_password_type($account->pass) == "md5") {  
       $info['AES']['value'] = t("Unavailable");  
     }  
     else {  
       $info['AES']['value'] = t("Hidden");  
231      }      }
232    
   
     $info['AES']['title'] = t('Password');  
     $info['AES']['class'] = 'member';  
   
     return array('Info' => $info);  
   
233    }    }
234    
235    if ($op == "login") {    if ($op == "login") {
236        if (variable_get("aes_convert", "true") == "true" && aes_password_exists($account->uid) == false) {
237      $convert = variable_get("aes_convert", "true");        db_query("INSERT INTO {aes_passwords} (uid, pass) VALUES (%d, '%s')", $account->uid, aes_encrypt($edit['pass']));
   
     if ($convert == "true") {  
       $md5_pass = md5($edit['pass']);  
       $result = db_query("SELECT uid FROM {users} WHERE name='".db_escape_string($edit['name'])."' AND pass='".$md5_pass."'");  
   
       if (db_num_rows($result) > 0) {  
         db_query("UPDATE {users} SET pass='".aes_encrypt($edit['pass'])."' WHERE name='".db_escape_string($edit['name'])."'");  
   
         return true;  
       }  
238      }      }
239    }    }
240    
241    if ($op == "update" || $op == "insert") {    if ($op == "update" || $op == "insert") {
242      if (!empty($edit['pass'])) {      if (!empty($edit['pass']) && $account->uid) {
243    
244        $password = aes_encrypt($edit['pass']);        $password = aes_encrypt($edit['pass']);
245        db_query("UPDATE {users} SET pass='".$password."' WHERE uid=".$account->uid);  
246        $edit['pass'] = null;        if (strlen($password) > AES_PASSWORD_MAX_LENGTH) {
247            $edit['pass'] = null;
248            drupal_set_message(t("Couldn't update AES password since it's too long.", "error"));
249          }
250          else {
251            db_query("DELETE FROM {aes_passwords} WHERE uid=%d", $account->uid);
252            db_query("INSERT INTO {aes_passwords} (uid, pass) VALUES (%d, '%s')", $account->uid, $password);
253          }
254      }      }
255    }    }
256    
257      if ($op == "delete") {
258        db_query("DELETE FROM {aes_passwords} WHERE uid=%d", $account->uid);
259      }
260  }  }
261    
262  function view_pw_form() {  
263    function view_pw_form($password) {
264    
265    $form['password'] = array(    $form['password'] = array(
266    '#type' => 'fieldset',    '#type' => 'fieldset',
267    '#title' => t('Show password'),    '#title' => t('Show password'),
268    '#description' => '[password]',    '#description' => $password,
269    '#collapsible' => true,    '#collapsible' => true,
270    '#collapsed' => true,    '#collapsed' => true,
271    );    );
# Line 249  function view_pw_form() { Line 273  function view_pw_form() {
273    return $form;    return $form;
274  }  }
275    
276  function aes_password_type($password) {  function aes_password_exists($uid) {
277    if (strlen($password) == 32) {    return db_num_rows(db_query("SELECT uid FROM {aes_passwords} WHERE uid=%d", $uid));
278      return "md5";  }
279    
280    function aes_get_password($uid, $decrypt = false) {
281      $result = db_query("SELECT pass FROM {aes_passwords} WHERE uid=%d", $uid);
282      if (db_num_rows($result) == 1) {
283        $user = db_fetch_array($result);
284      }
285      if ($decrypt) {
286        return trim(aes_decrypt($user['pass']));
287    }    }
288    else {    else {
289      return "aes";      return $user['pass'];
290    }    }
291  }  }
292    
# Line 281  function aes_get_key() { Line 313  function aes_get_key() {
313    return $key;    return $key;
314  }  }
315    
 function aes_make_key() {  
   $chars = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ1234567890";  
   $key = "";  
   while (strlen($key) < 32) {  
     $key .= substr($chars, rand(0, strlen($chars)), 1);  
   }  
   
   return $key;  
 }  
   
316  function aes_store_key($key) {  function aes_store_key($key) {
317    $storage_method = variable_get("aes_key_storage_method", "Database");    $storage_method = variable_get("aes_key_storage_method", "Database");
318    
# Line 298  function aes_store_key($key) { Line 320  function aes_store_key($key) {
320      variable_set("aes_key", $key);      variable_set("aes_key", $key);
321    }    }
322    else if ($storage_method == "File") {    else if ($storage_method == "File") {
     $result = file_put_contents(variable_get("aes_key_path", ""), $key);  
   
323      $fp = fopen(variable_get("aes_key_path", ""), "w");      $fp = fopen(variable_get("aes_key_path", ""), "w");
324      if ($fp === false) {      if ($fp === false) {
325        drupal_set_message(t("Couldn't write key to file ".variable_get("aes_key_path", "")), "error");        drupal_set_message(t("Couldn't write key to file ".variable_get("aes_key_path", "")), "error");
# Line 324  function aes_delete_key($storage_method) Line 344  function aes_delete_key($storage_method)
344    if ($storage_method == "File") {    if ($storage_method == "File") {
345      $result = unlink(variable_get("aes_key_path", ""));      $result = unlink(variable_get("aes_key_path", ""));
346      if ($result === false) {      if ($result === false) {
347        drupal_set_message("Couldn't delete keyfile!", "error");        drupal_set_message(t("Couldn't delete keyfile!"), "error");
348      }      }
349    }    }
350  }  }
351    
352    function aes_make_key() {
353    
354      $acceptable = false;
355    
356      $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
357    
358      while ($acceptable === false) {
359    
360        $key = "";
361    
362        while (strlen($key) < 32) {
363          $key .= substr($chars, rand(0, strlen($chars)), 1);
364        }
365    
366        $acceptable = true;
367    
368        //is there at least one lowercase letter?
369        $result = preg_match("/.*[a-z].*/", $key);
370    
371        if($result == 0) {
372          $acceptable = false;
373        }
374    
375        //is there at least one uppercase letter?
376        $result = preg_match("/.*[A-Z].*/", $key);
377    
378        if($result == 0) {
379          $acceptable = false;
380        }
381    
382        //is there at least one numeric?
383        $result = preg_match("/.*[0-9].*/", $key);
384    
385        if($result == 0) {
386          $acceptable = false;
387        }
388      }
389    
390      return $key;
391    }
392    
393    function aes_make_iv() {
394    
395      if (strtoupper(substr(PHP_OS, 0, 3)) === "WIN") {
396        $randgen = MCRYPT_RAND;
397      }
398      else {
399        $randgen = MCRYPT_DEV_URANDOM;
400      }
401    
402      $td = mcrypt_module_open(variable_get("aes_cipher", "rijndael-128"), "", MCRYPT_MODE_CBC, "");
403      $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), $randgen);
404      mcrypt_module_close($td);
405      variable_set("aes_encryption_iv", base64_encode($iv));
406    }
407    
408  /**  /**
409  Encrypts a string.  Encrypts a string.
410  @param $string The string to encrypt.  @param $string The string to encrypt.
411  @param $base64encode Whether to return the string base64 encoded (recommended for database insertion).  @param $base64encode Whether to return the string base64 encoded (recommended for database insertion).
412  @param $custom_key Use this as the key rather than the stored one for this operation.  @param $custom_key Use this as the key rather than the stored one for this operation.
413    @param $custom_cipher Use this cipher rather than the default one.
414    @param $custom_iv Use this initialization vector instead of the default one.
415  @return The encrypted string.  @return The encrypted string.
416  */  */
417  function aes_encrypt($string, $base64encode = true, $custom_key = null) {  function aes_encrypt($string, $base64encode = true, $custom_key = null, $custom_cipher = null, $custom_iv = null) {
   $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, "", MCRYPT_MODE_CBC, "");  
418    
419    $iv = base64_decode(variable_get("aes_encryption_iv", ""));    if ($custom_cipher != null) {
420        $cipher = $custom_cipher;
421      }
422      else {
423        $cipher = variable_get("aes_cipher", "rijndael-128");
424      }
425    
426      $td = mcrypt_module_open($cipher, "", MCRYPT_MODE_CBC, "");
427    
428      if ($custom_iv == null) {
429        $iv = base64_decode(variable_get("aes_encryption_iv", ""));
430      }
431      else {
432        $iv = base64_decode($custom_iv);
433      }
434    
435    if (empty($iv)) {    if (empty($iv)) {
436      $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_DEV_URANDOM);      aes_make_iv();
437      variable_set("aes_encryption_iv", base64_encode($iv));      $iv = base64_decode(variable_get("aes_encryption_iv", ""));
   
438      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);      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);
439    }    }
440    
# Line 378  Decrypts a string of encrypted data. Line 468  Decrypts a string of encrypted data.
468  @param $string The string to decrypt.  @param $string The string to decrypt.
469  @param $base64encoded Whether this encrypted string is base64 encoded or not.  @param $base64encoded Whether this encrypted string is base64 encoded or not.
470  @param $custom_key Use this as the key rather than the stored one for this operation.  @param $custom_key Use this as the key rather than the stored one for this operation.
471    @param $custom_cipher Use this cipher rather than the default one.
472    @param $custom_iv Use this initialization vector instead of the default one.
473  @return The decrypted string.  @return The decrypted string.
474  */  */
475  function aes_decrypt($string, $base64encoded = true, $custom_key = null) {  function aes_decrypt($string, $base64encoded = true, $custom_key = null, $custom_cipher = null, $custom_iv = null) {
476    if ($base64encoded) {    if ($base64encoded) {
477      $string = base64_decode($string);      $string = base64_decode($string);
478    }    }
479    
480    $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, "", MCRYPT_MODE_CBC, "");    if ($custom_cipher != null) {
481        $cipher = $custom_cipher;
482      }
483      else {
484        $cipher = variable_get("aes_cipher", "rijndael-128");
485      }
486    
487      $td = mcrypt_module_open($cipher, "", MCRYPT_MODE_CBC, "");
488    $ks = mcrypt_enc_get_key_size($td);    $ks = mcrypt_enc_get_key_size($td);
489    
490    $iv = base64_decode(variable_get("aes_encryption_iv", ""));    if ($custom_iv == null) {
491        $iv = base64_decode(variable_get("aes_encryption_iv", ""));
492      }
493      else {
494        $iv = base64_decode($custom_iv);
495      }
496    
497    if (empty($iv)) {    if (empty($iv)) {
498      watchdog("aes", t("No initialization vector found while trying to decrypt. Aborting!"), WATCHDOG_ERROR);      watchdog("aes", t("No initialization vector found while trying to decrypt. Aborting!"), WATCHDOG_ERROR);
# Line 412  function aes_decrypt($string, $base64enc Line 516  function aes_decrypt($string, $base64enc
516    return $decrypted;    return $decrypted;
517  }  }
518    
519    function aes_enable() {
520  function aes_disable() {    if (extension_loaded("mcrypt") === false) {
521    $a = db_query("SELECT uid, pass FROM {users} WHERE uid != 0");      drupal_set_message("The mcrypt PHP-extension is not loaded! The AES module can't work without this extension.", "error");
522      }
523    
524    while ($user = db_fetch_array($a)) {    $iv = base64_decode(variable_get("aes_encryption_iv", ""));
525      if (aes_password_type($user['pass']) != "md5") {  
526        $md5_pass = md5(trim(aes_decrypt($user['pass'])));    if (empty($iv)) {
527        db_query("UPDATE {users} SET pass='".$md5_pass."' WHERE uid=".$user['uid']);      aes_make_iv();
     }  
528    }    }
529    
   drupal_set_message(t("Passwords reset to MD5."));  
530  }  }

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.1.2.1

  ViewVC Help
Powered by ViewVC 1.1.2