View source
<?php
define("AES_PASSWORD_MAX_LENGTH", 128);
define("CRYPT_AES_MODE", 1);
function aes_menu() {
$items = array();
$items['admin/config/system/aes'] = array(
'title' => 'AES settings',
'description' => 'Configure the AES encryption module.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'aes_config',
),
'access arguments' => array(
'administer aes',
),
'file' => 'aes.admin.inc',
'type' => MENU_NORMAL_ITEM,
);
$items['user/%/password'] = array(
'title' => 'View password',
'page callback' => 'aes_get_password',
'page arguments' => array(
1,
TRUE,
),
'access callback' => 'aes_show_password_page',
'access arguments' => array(
'view passwords',
1,
),
'type' => MENU_LOCAL_TASK,
);
$items['aes_get_password_callback/%'] = array(
'title' => 'User\'s password',
'page callback' => 'aes_ajax_callback',
'page arguments' => array(
1,
),
'access arguments' => array(
'view passwords',
),
'type' => MENU_CALLBACK,
);
return $items;
}
function aes_permission() {
return array(
'administer aes' => array(
'title' => t('Administer AES'),
'description' => t('Administer AES module.'),
),
'view passwords' => array(
'title' => t('View passwords'),
'description' => t('View user password in plain text.'),
'restrict access' => TRUE,
),
);
}
function aes_load_phpsec() {
if (module_exists('libraries') && libraries_get_path('phpseclib')) {
$phpsec_include_path = libraries_get_path('phpseclib');
}
else {
$phpsec_include_path = dirname(__FILE__) . '/phpseclib';
}
if (file_exists($phpsec_include_path . '/Crypt/AES.php') === FALSE) {
return -2;
}
if (is_readable($phpsec_include_path . '/Crypt/AES.php') === FALSE) {
drupal_set_message(t("It appears that phpseclib is installed in the right location but can't be read. Check that the permissions on the directory and its files allows for reading by the webserver."));
return -3;
}
if (function_exists("set_include_path") == FALSE) {
return -1;
}
set_include_path(get_include_path() . PATH_SEPARATOR . $phpsec_include_path);
include_once 'Crypt/AES.php';
return TRUE;
}
function aes_show_password_page($access, $uid) {
$viewing_method = variable_get("aes_viewing_method", "page");
return user_access($access) && aes_password_exists($uid) && ($viewing_method == "page" || $viewing_method == "both");
}
function aes_user_view($account, $view_mode, $langcode) {
$viewing_method = variable_get("aes_viewing_method", "page");
if (user_access('view passwords') && ($viewing_method == "inplace" || $viewing_method == "both") && variable_get("aes_convert", FALSE)) {
if (aes_password_exists($account->uid)) {
drupal_add_library('system', 'drupal.ajax');
$link = l(t('Show password'), 'aes_get_password_callback/' . $account->uid . '/nojs/', array(
'attributes' => array(
'class' => array(
'use-ajax',
),
),
));
$account->content['info']['aes_password'] = array(
'#type' => 'user_profile_item',
'#title' => t('AES Encryption'),
'#markup' => '<div id="aes_password">' . $link . '</div>',
);
}
else {
$account->content['info']['aes_password'] = array(
'#type' => 'user_profile_item',
'#title' => t('AES Encryption'),
'#markup' => t("This user's password does not yet exist in AES encrypted form."),
);
}
}
}
function aes_ajax_callback($uid, $type = 'ajax') {
$output = aes_get_password($uid, TRUE);
if ($type != 'ajax') {
$user = user_load($uid, FALSE);
drupal_set_title($user->name . '\'s password');
return $output;
}
$commands = array();
$commands[] = ajax_command_replace('#aes_password', $output);
$page = array(
'#type' => 'ajax',
'#commands' => $commands,
);
ajax_deliver($page);
}
function aes_user_login(&$edit, $account) {
if (variable_get("aes_convert", FALSE) && aes_password_exists($account->uid) == FALSE && isset($edit['input']) && isset($edit['input']['pass'])) {
db_insert('aes_passwords')
->fields(array(
'uid' => $account->uid,
'pass' => aes_encrypt($edit['input']['pass']),
))
->execute();
}
}
function aes_user_insert(&$edit, $account, $category) {
aes_user_alter($edit, $account);
}
function aes_user_update(&$edit, $account, $category) {
aes_user_alter($edit, $account);
}
function aes_user_delete($account) {
db_delete('aes_passwords')
->where("uid = :uid", array(
':uid' => $account->uid,
))
->execute();
}
function aes_user_alter(&$edit, $account) {
if (!isset($_POST['pass']) || !isset($_POST['pass']['pass1'])) {
return;
}
$plain_text_password = $_POST['pass']['pass1'];
if (!empty($plain_text_password) && $account->uid) {
$password = aes_encrypt($plain_text_password);
if (strlen($password) > AES_PASSWORD_MAX_LENGTH) {
drupal_set_message(t("Couldn't update AES password since it's too long."), "error");
}
else {
if (aes_password_exists($account->uid) == FALSE) {
if (variable_get("aes_convert", FALSE)) {
db_insert('aes_passwords')
->fields(array(
'uid' => $account->uid,
'pass' => $password,
))
->execute();
}
}
else {
db_update('aes_passwords')
->fields(array(
'pass' => $password,
))
->where("uid = :uid", array(
':uid' => $account->uid,
))
->execute();
}
}
}
}
function aes_password_exists($uid) {
return aes_get_password($uid) ? TRUE : FALSE;
}
function aes_get_password($uid, $decrypt = FALSE) {
$password = db_select('aes_passwords', 'p')
->fields('p', array(
'pass',
))
->condition('uid', $uid)
->execute()
->fetchField();
if (empty($password)) {
return FALSE;
}
if ($decrypt) {
return aes_decrypt($password);
}
return $password;
}
function aes_get_key() {
$storage_method = variable_get("aes_key_storage_method", "Database");
if ($storage_method == "Database") {
$key = variable_get("aes_key", FALSE);
if ($key === FALSE) {
$key = aes_make_key();
aes_store_key($key);
watchdog("aes", "AES module made a new key since one couldn't be found by using the database storage method.");
}
}
if ($storage_method == "File") {
$key = file_get_contents(variable_get("aes_key_path", ""));
if ($key === FALSE) {
$key = aes_make_key();
aes_store_key($key);
watchdog("aes", "AES module made a new key since one couldn't be found by using the file storage method.");
}
}
return $key;
}
function aes_store_key($key) {
$storage_method = variable_get("aes_key_storage_method", "Database");
if ($storage_method == "Database") {
variable_set("aes_key", $key);
return TRUE;
}
if ($storage_method != "File") {
throw new Exception('Unknown storage method in AES module: ' . $storage_method);
}
$fp = fopen(variable_get("aes_key_path", ""), "w");
if ($fp === FALSE) {
drupal_set_message(t("Couldn't write key to file " . variable_get("aes_key_path", "")), "error");
return FALSE;
}
fwrite($fp, $key);
fclose($fp);
return TRUE;
}
function aes_delete_key($storage_method) {
if ($storage_method == "Database") {
variable_del("aes_key");
}
if ($storage_method == "File") {
$result = unlink(variable_get("aes_key_path", ""));
if ($result === FALSE) {
drupal_set_message(t("Couldn't delete keyfile!"), "error");
}
}
}
function aes_make_key() {
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
srand();
while (TRUE) {
$key = '';
while (strlen($key) < 32) {
$key .= substr($chars, rand(0, strlen($chars)), 1);
}
if (!preg_match('/.*[a-z].*/', $key)) {
continue;
}
if (!preg_match('/.*[A-Z].*/', $key)) {
continue;
}
if (!preg_match('/.*[0-9].*/', $key)) {
continue;
}
break;
}
return $key;
}
function aes_make_iv($ignore_implementation = FALSE) {
if (variable_get("aes_implementation", "mcrypt") == "phpseclib" && $ignore_implementation == FALSE) {
watchdog("aes", "Called aes_make_iv when using phpseclib. This is harmless, but shouldn't happen.", array(), WATCHDOG_WARNING);
return;
}
if (strtoupper(substr(PHP_OS, 0, 3)) === "WIN") {
$randgen = MCRYPT_RAND;
srand();
}
else {
$randgen = MCRYPT_DEV_URANDOM;
}
$td = mcrypt_module_open_safe(variable_get("aes_cipher", "rijndael-128"), "", MCRYPT_MODE_CBC, "");
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), $randgen);
mcrypt_module_close($td);
variable_set("aes_encryption_iv", base64_encode($iv));
}
function aes_encrypt($string, $base64encode = TRUE, $custom_key = NULL, $custom_cipher = NULL, $custom_iv = NULL, $custom_implementation = NULL) {
if (empty($string)) {
watchdog("aes", "Tried to encrypt an empty string.", array(), WATCHDOG_WARNING);
return FALSE;
}
if ($custom_cipher != NULL) {
$cipher = $custom_cipher;
}
else {
$cipher = variable_get("aes_cipher", "rijndael-128");
}
if (!empty($custom_key)) {
$key = $custom_key;
}
else {
$key = aes_get_key();
}
if ($custom_implementation == "mcrypt" || $custom_implementation == "phpseclib") {
$implementation = $custom_implementation;
}
else {
$implementation = variable_get("aes_implementation", "mcrypt");
}
if ($implementation == "phpseclib") {
if (is_null($custom_cipher) == FALSE) {
watchdog("aes", "A custom cipher was defined when encrypting a string in the AES module using the phpseclib implementation. This implementation doesn't support custom ciphers therefore the argument was ignored and the encryption was done with the standard cipher.", array(), WATCHDOG_WARNING);
}
aes_load_phpsec();
$phpsec = new Crypt_AES();
$phpsec
->setKey($key);
if (!is_null($custom_iv)) {
$phpsec
->setIV(base64_decode($custom_iv));
}
$encrypted = $phpsec
->encrypt($string);
}
else {
if ($implementation == "mcrypt") {
$td = mcrypt_module_open_safe($cipher, "", MCRYPT_MODE_CBC, "");
if ($custom_iv == NULL) {
$iv = base64_decode(variable_get("aes_encryption_iv", ""));
}
else {
$iv = base64_decode($custom_iv);
}
if (empty($iv)) {
aes_make_iv();
$iv = base64_decode(variable_get("aes_encryption_iv", ""));
watchdog("aes", "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.", array(), WATCHDOG_WARNING);
}
$ks = mcrypt_enc_get_key_size($td);
$key = substr(sha1($key), 0, $ks);
mcrypt_generic_init($td, $key, $iv);
$encrypted = mcrypt_generic($td, $string);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
}
else {
$error_msg = t("Request was sent to encrypt a string with the AES module, but the AES module has no active encryption implementation to work with! Did you forget to run update.php after upgrading this module?");
if (user_access('administer aes')) {
drupal_set_message($error_msg, "error");
}
watchdog("aes", $error_msg, array(), WATCHDOG_ERROR);
return FALSE;
}
}
if ($base64encode) {
return base64_encode($encrypted);
}
else {
return $encrypted;
}
}
function aes_decrypt($string, $base64encoded = TRUE, $custom_key = NULL, $custom_cipher = NULL, $custom_iv = NULL, $custom_implementation = NULL) {
if ($base64encoded) {
$string = base64_decode($string);
}
if (empty($string)) {
watchdog("aes", "Tried to decrypt an empty string.", array(), WATCHDOG_WARNING);
return FALSE;
}
if ($custom_cipher != NULL) {
$cipher = $custom_cipher;
}
else {
$cipher = variable_get("aes_cipher", "rijndael-128");
}
if (!empty($custom_key)) {
$key = $custom_key;
}
else {
$key = aes_get_key();
}
if ($custom_implementation == "mcrypt" || $custom_implementation == "phpseclib") {
$implementation = $custom_implementation;
}
else {
$implementation = variable_get("aes_implementation", "mcrypt");
}
if ($implementation == "phpseclib") {
if (is_null($custom_cipher) == FALSE) {
watchdog("aes", "A custom cipher was defined when decrypting a string in the AES module using the phpseclib implementation. This implementation doesn't support custom ciphers therefore the argument was ignored and the decryption was done with the standard cipher.", array(), WATCHDOG_WARNING);
}
aes_load_phpsec();
$phpsec = new Crypt_AES();
$phpsec
->setKey($key);
if (!is_null($custom_iv)) {
$phpsec
->setIV(base64_decode($custom_iv));
}
$decrypted = $phpsec
->decrypt($string);
}
else {
if ($implementation == "mcrypt") {
$td = mcrypt_module_open_safe($cipher, "", MCRYPT_MODE_CBC, "");
$ks = mcrypt_enc_get_key_size($td);
if ($custom_iv == NULL) {
$iv = base64_decode(variable_get("aes_encryption_iv", ""));
}
else {
$iv = base64_decode($custom_iv);
}
if (empty($iv)) {
watchdog("aes", "No initialization vector found while trying to decrypt. Aborting!", array(), WATCHDOG_ERROR);
}
$key = substr(sha1($key), 0, $ks);
mcrypt_generic_init($td, $key, $iv);
$decrypted = mdecrypt_generic($td, $string);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
}
else {
$error_msg = t("Request was sent to decrypt a string with the AES module, but the AES module has no active encryption implementation to work with! Did you forget to run update.php after upgrading this module?");
if (user_access('administer aes')) {
drupal_set_message($error_msg, "error");
}
watchdog("aes", $error_msg, array(), WATCHDOG_ERROR);
return FALSE;
}
}
return trim($decrypted);
}
function mcrypt_module_open_safe($algorithm, $algorithm_directory, $mode, $mode_directory) {
if (!function_exists('mcrypt_module_open')) {
throw new Exception('AES: Mcrypt is selected as encryption implementation but is unavailable.');
}
return mcrypt_module_open($algorithm, $algorithm_directory, $mode, $mode_directory);
}