Follow us on Twitter X-Cart on Facebook Wiki
Shopping cart software Solutions for online shops and malls

More secure password encryption mod (using mcrypt)

 
Reply
   X-Cart forums > X-Cart 4 > Dev Questions
 
Thread Tools Search this Thread
  #1  
Old 04-03-2006, 09:20 AM
 
intel352 intel352 is offline
 

X-Wizard
  
Join Date: Dec 2005
Posts: 1,071
 

Default More secure password encryption mod (using mcrypt)

I wasn't happy with the level of encryption for user passwords within x-cart,
so based upon a freely available class that uses MCrypt password encrypt/decrypt
functionality, I've modified X-Cart to support user-encrypted passwords,
up to 256-bit level encryption :-)

(I read on Wikipedia that the currently "crackable" level is 66-bit, so hackers
would have a ways to go if they were trying to crack the encryption algorithm)

--------------------------------------

This mod REQUIRES that the MCrypt module be compiled into PHP.
If you are on a server that runs CPanel/WHM, it is no problem at all for the server
admin to go into the Apache build settings and enable MCrypt.

DISCLAIMER: This modification works perfectly on our Centos v4 server
running WHM/CPanel, Apache 1.3.x, PHP 4.4.x, MySQL 4.0.25, with X-Cart 4.0.18.
We claim no responsibility for any damage you may cause by applying this mod.
We do not guarantee that this mod will work in your "environment". We do not
guarantee your own ability to install this mod successfully. You install
this mod at your own risk!!
If needed, I can install this mod for $25
(if for some reason I were to install the mod and it didn't work in your environment,
I would uninstall the mod and you would not be charged). You may contact me via
these forums in PM or email to contract my services, support can be handled in this thread.

IMPORTANT -- Create a back-up of all files that you will be modifying,
as well as your database, before applying this mod!!


--------------------------------------

This mod affects the following files:
  • config.php
  • include/change_password.php
  • include/class.mycrypt.php - ADDED
  • include/func.php
  • include/help.php
  • include/login.php
  • include/register.php
  • sql/xcart_tables.sql

In a follow-up post, I'll copy/paste contents from a PATCH file that
can perform the alterations as needed


--------------------------------------

OPEN config.php
FIND
Code:
$START_CHAR_CODE = 100; # 'd' letter

AFTER, ADD
Code:
# # Variables for MCrypt functionality, CRYPT_KEY should be changed per site # $CRYPT_KEY = 'YOUR_UNIQUE_SITE_KEY_HERE_ANY_NUMALPHA_KEY_MAKE_IT_LONG'; $CRYPT_CIPHER = 'rijndael-256'; $CRYPT_MODE = 'cbc';

Replace the value of CRYPT_KEY with any random string, long=good. You may use numbers and letters.
I have not tested the use of non-alphanumeric characters, feel free to test.
DO NOT TEST on a live site, once you set the CRYPT_KEY, you must not change it again.
Read the notes at the end regarding settings for CRYPT_CIPHER and CRYPT_MODE


OPEN include/change_password.php
FIND
Code:
db_query("UPDATE $sql_tbl[customers] SET password='".addslashes(text_crypt($new_password))."', change_password='N' WHERE login='".addslashes($xlogin)."'");

REPLACE WITH
Code:
$new_password = text_crypt($new_password,false,true,true); db_query("UPDATE $sql_tbl[customers] SET password='".addslashes($new_password['s'])."', password_key='".addslashes($new_password['iv'])."', change_password='N' WHERE login='".addslashes($xlogin)."'");

OPEN include/func.php
FIND
Code:
function text_crypt($s, $is_blowfish = false) { global $START_CHAR_CODE, $CRYPT_SALT, $merchant_password, $current_area, $active_modules, $blowfish, $config; if ($s == "") return $s; if($is_blowfish && $merchant_password && ($current_area == 'A' || ($current_area == 'P' && $active_modules["Simple_Mode"])) && $blowfish && $config['Security']['blowfish_enabled'] == 'Y') { $s = trim($s); $result = "B".func_crc32($s).func_bf_crypt($s, $merchant_password); } else { $enc = rand(1,255); # generate random salt. $result = "S".text_crypt_symbol($enc); # include salt in the result; $enc ^= $CRYPT_SALT; for ($i = 0; $i < strlen($s); $i++) { $r = ord(substr($s, $i, 1)) ^ $enc++; if ($enc > 255) $enc = 0; $result .= text_crypt_symbol($r); } } return $result; }

REPLACE WITH
Code:
function text_crypt($s, $is_blowfish = false, $ret_iv = false, $mcrypt = false) { global $CRYPT_KEY, $CRYPT_CIPHER, $CRYPT_MODE, $START_CHAR_CODE, $CRYPT_SALT, $merchant_password, $current_area, $active_modules, $blowfish, $config, $xcart_dir; if ($s == "") return $s; if($mcrypt){ require_once($xcart_dir.'/include/class.mcrypt.php'); $crypto = new phpMcrypt($CRYPT_KEY, $CRYPT_CIPHER, $CRYPT_MODE); $encrypted_str = $crypto->encrypt($s); $iv = base64_encode($crypto->initvector()); $crypto->__destruct(); $result = $ret_iv?array('s'=>$encrypted_str,'iv'=>$iv):$encrypted_str; }else{ if($is_blowfish && $merchant_password && ($current_area == 'A' || ($current_area == 'P' && $active_modules["Simple_Mode"])) && $blowfish && $config['Security']['blowfish_enabled'] == 'Y') { $s = trim($s); $result = "B".func_crc32($s).func_bf_crypt($s, $merchant_password); } else { $enc = rand(1,255); # generate random salt. $result = "S".text_crypt_symbol($enc); # include salt in the result; $enc ^= $CRYPT_SALT; for ($i = 0; $i < strlen($s); $i++) { $r = ord(substr($s, $i, 1)) ^ $enc++; if ($enc > 255) $enc = 0; $result .= text_crypt_symbol($r); } } } return $result; }

FIND
Code:
function text_decrypt($s) { global $START_CHAR_CODE, $CRYPT_SALT, $merchant_password, $current_area, $active_modules, $blowfish; if ($s == "") return $s; $crypt_method = substr($s, 0, 1); $s = substr($s, 1); if($crypt_method == 'B') { if($merchant_password && ($current_area == 'A' || ($current_area == 'P' && $active_modules["Simple_Mode"])) && $blowfish) { $crc32 = substr($s, 0, 4); $s = substr($s, 4); $result = func_bf_decrypt($s, $merchant_password); if(func_crc32($result) != $crc32) { $result = func_get_langvar_by_name('err_data_corrupted'); } } else { return false; } } elseif($crypt_method != 'B') { if($crypt_method != 'S') { $s = $crypt_method.$s; } $enc = $CRYPT_SALT ^ text_decrypt_symbol($s, 0); $result = ""; for ($i = 2; $i < strlen($s); $i+=2) { # $i=2 to skip salt $result .= chr(text_decrypt_symbol($s, $i) ^ $enc++); if ($enc > 255) $enc = 0; } } return $result; }

REPLACE WITH
Code:
function text_decrypt($s, $iv = '', $mcrypt = false) { global $CRYPT_KEY, $CRYPT_CIPHER, $CRYPT_MODE, $START_CHAR_CODE, $CRYPT_SALT, $merchant_password, $current_area, $active_modules, $blowfish, $xcart_dir; if ($s == "") return $s; if($mcrypt){ require_once($xcart_dir.'/include/class.mcrypt.php'); if($iv!='') $crypto = new phpMcrypt($CRYPT_KEY, $CRYPT_CIPHER, $CRYPT_MODE, base64_decode($iv)); else $crypto = new phpMcrypt($CRYPT_KEY, $CRYPT_CIPHER, $CRYPT_MODE); $decrypted_str = $crypto->decrypt($s); $crypto->__destruct(); $result = $decrypted_str; }else{ $crypt_method = substr($s, 0, 1); $s = substr($s, 1); if($crypt_method == 'B') { if($merchant_password && ($current_area == 'A' || ($current_area == 'P' && $active_modules["Simple_Mode"])) && $blowfish) { $crc32 = substr($s, 0, 4); $s = substr($s, 4); $result = func_bf_decrypt($s, $merchant_password); if(func_crc32($result) != $crc32) { $result = func_get_langvar_by_name('err_data_corrupted'); } } else { return false; } } elseif($crypt_method != 'B') { if($crypt_method != 'S') { $s = $crypt_method.$s; } $enc = $CRYPT_SALT ^ text_decrypt_symbol($s, 0); $result = ""; for ($i = 2; $i < strlen($s); $i+=2) { # $i=2 to skip salt $result .= chr(text_decrypt_symbol($s, $i) ^ $enc++); if ($enc > 255) $enc = 0; } } } return $result; }

FIND
Code:
$userinfo["passwd1"] = stripslashes(text_decrypt($userinfo["password"])); $userinfo["passwd2"] = stripslashes(text_decrypt($userinfo["password"])); $userinfo["password"] = stripslashes(text_decrypt($userinfo["password"]));

REPLACE WITH
Code:
$userinfo["passwd1"] = stripslashes(text_decrypt($userinfo["password"], $userinfo["password_key"], true)); $userinfo["passwd2"] = stripslashes(text_decrypt($userinfo["password"], $userinfo["password_key"], true)); $userinfo["password"] = stripslashes(text_decrypt($userinfo["password"], $userinfo["password_key"], true));

FIND
Code:
$account = func_query_first("SELECT login, password FROM $sql_tbl[customers] WHERE login='$uname'"); if ($account["login"] == text_decrypt($account["password"])) $return[] = $account["login"];

REPLACE WITH
Code:
$account = func_query_first("SELECT login, password, password_key FROM $sql_tbl[customers] WHERE login='$uname'"); if ($account["login"] == text_decrypt($account["password"], $account["password_key"], true)) $return[] = $account["login"];

FIND
Code:
$account = func_query_first("SELECT login, password FROM $sql_tbl[customers] WHERE login='$login_' AND usertype='$usertype'"); if (!empty($account)) { if ($account["login"] == text_decrypt($account["password"])) $return[] = $account["login"];

REPLACE WITH
Code:
$account = func_query_first("SELECT login, password, password_key FROM $sql_tbl[customers] WHERE login='$login_' AND usertype='$usertype'"); if (!empty($account)) { if ($account["login"] == text_decrypt($account["password"], $account["password_key"], true)) $return[] = $account["login"];

OPEN include/help.php
FIND
Code:
$accounts = func_query("select login, password, usertype from $sql_tbl[customers] where email='$email' and status='Y'");

REPLACE WITH
Code:
$accounts = func_query("select login, password, password_key, usertype from $sql_tbl[customers] where email='$email' and status='Y'");

FIND
Code:
$accounts[$key]["password"]=text_decrypt($accounts[$key]["password"]);

REPLACE WITH
Code:
$accounts[$key]["password"]=text_decrypt($accounts[$key]["password"], $accounts[$key]["password_key"], true);

OPEN include/login.php
FIND
Code:
if (!empty($user_data) && $password == text_decrypt($user_data["password"]) && !empty($password) && $allow_login) {

REPLACE WITH
Code:
if ($user_data['password_key']==''){ $newpass = text_crypt(text_decrypt($user_data['password']),false,true,true); $user_data['password'] = $newpass['s']; $user_data['password_key'] = $newpass['iv']; db_query("UPDATE $sql_tbl[customers] SET password='".addslashes($user_data["password"])."',password_key='".addslashes($user_data["password_key"])."' WHERE loginid='".$user_data["loginid"]."'"); unset($newpass); } if ($allow_login && !empty($user_data) && !empty($password) && $password == text_decrypt($user_data["password"], $user_data["password_key"], true)) {

OPEN include/register.php
FIND
Code:
$crypted = addslashes(text_crypt($passwd1));

REPLACE WITH
Code:
$crypted = addslashes(text_crypt($passwd1,false,true,true));

FIND
Code:
db_query("UPDATE $sql_tbl[customers] SET password='$crypted', password_hint='$password_hint', password_hint_answer='$password_hint_answer', title='$title', firstname='$firstname', lastname='$lastname', company='$company', b_address='".$b_address."\n".$b_address_2."', b_city='$b_city', b_county='".(@$b_county)."', b_state='$b_state', b_country='$b_country', b_zipcode='$b_zipcode', s_address='".$s_address."\n".$s_address_2."', s_city='$s_city', s_county='".(@$s_county)."', s_state='$s_state', s_country='$s_country', s_zipcode='$s_zipcode', phone='$phone', email='$email', fax='$fax', url='$url', card_name='$card_name', card_type='$card_type', card_number='".addslashes(text_crypt($card_number))."', card_expire='$card_expire', card_cvv2='$card_cvv2', pending_membership='$pending_membership', ssn='$ssn', change_password='$change_password', parent = '$parent', pending_plan_id = '$pending_plan_id' WHERE login='$login' AND usertype='$login_type'");

REPLACE WITH
Code:
db_query("UPDATE $sql_tbl[customers] SET password='".addslashes($crypted['s'])."', password_key='".addslashes($crypted['iv'])."', password_hint='$password_hint', password_hint_answer='$password_hint_answer', title='$title', firstname='$firstname', lastname='$lastname', company='$company', b_address='".$b_address."\n".$b_address_2."', b_city='$b_city', b_county='".(@$b_county)."', b_state='$b_state', b_country='$b_country', b_zipcode='$b_zipcode', s_address='".$s_address."\n".$s_address_2."', s_city='$s_city', s_county='".(@$s_county)."', s_state='$s_state', s_country='$s_country', s_zipcode='$s_zipcode', phone='$phone', email='$email', fax='$fax', url='$url', card_name='$card_name', card_type='$card_type', card_number='".addslashes(text_crypt($card_number))."', card_expire='$card_expire', card_cvv2='$card_cvv2', pending_membership='$pending_membership', ssn='$ssn', change_password='$change_password', parent = '$parent', pending_plan_id = '$pending_plan_id' WHERE login='$login' AND usertype='$login_type'");

FIND
Code:
db_query("INSERT INTO $sql_tbl[customers] (login,usertype,password,password_hint,password_hint_answer,title,firstname,lastname,company,b_address,b_city,b_county,b_state,b_country,b_zipcode,s_address,s_city,s_county,s_state,s_country,s_zipcode,phone,email,fax,url,card_name,card_type,card_number,card_expire,card_cvv2,first_login,status,referer,pending_membership,ssn,parent,pending_plan_id,change_password) VALUES ('$uname','$usertype','$crypted','".@$password_hint."','".@$password_hint_answer."','$title','$firstname','$lastname','$company','".$b_address."\n".$b_address_2."','$b_city','".(@$b_county)."','$b_state','$b_country','$b_zipcode','".$s_address."\n".$s_address_2."','$s_city','".(@$s_county)."','$s_state','$s_country','$s_zipcode','$phone','$email','$fax','$url','".@$card_name."','".@$card_type."','".addslashes(text_crypt(@$card_number))."','".@$card_expire."','".@$card_cvv2."','".time()."','Y','".@$RefererCookie."','".@$pending_membership."','".@$ssn."', '$parent', '$pending_plan_id','$change_password')");

REPLACE WITH
Code:
db_query("INSERT INTO $sql_tbl[customers] (login,usertype,password,password_key,password_hint,password_hint_answer,title,firstname,lastname,company,b_address,b_city,b_county,b_state,b_country,b_zipcode,s_address,s_city,s_county,s_state,s_country,s_zipcode,phone,email,fax,url,card_name,card_type,card_number,card_expire,card_cvv2,first_login,status,referer,pending_membership,ssn,parent,pending_plan_id,change_password) VALUES ('$uname','$usertype','".addslashes($crypted['s'])."','".addslashes($crypted['iv'])."','".@$password_hint."','".@$password_hint_answer."','$title','$firstname','$lastname','$company','".$b_address."\n".$b_address_2."','$b_city','".(@$b_county)."','$b_state','$b_country','$b_zipcode','".$s_address."\n".$s_address_2."','$s_city','".(@$s_county)."','$s_state','$s_country','$s_zipcode','$phone','$email','$fax','$url','".@$card_name."','".@$card_type."','".addslashes(text_crypt(@$card_number))."','".@$card_expire."','".@$card_cvv2."','".time()."','Y','".@$RefererCookie."','".@$pending_membership."','".@$ssn."', '$parent', '$pending_plan_id','$change_password')");

OPEN sql/xcart_tables.sql (OPTIONAL)
FIND
Code:
password varchar(128) NOT NULL default '',

REPLACE WITH
Code:
password blob NOT NULL, password_key blob NOT NULL,

CREATE include/class.mcrypt.php
PASTE IN THE FOLLOWING CODE
Code:
<?php /* * class.mcrypt.php -> phpMcrypt Class (PHP4) */ /** * @author Dustin Whittle * @version 0.01 */ if ( !defined('XCART_START') ) { header("Location: ../"); die("Access denied"); } class phpMcrypt { var $td; var $iv = false; // this gets called when class is instantiated function phpMcrypt($key = 'MyRandomStringThatWillAlwaysBeTheSame', $algorithm = 'tripledes', $mode = 'ecb', $iv = false) { if(extension_loaded('mcrypt') === FALSE) { $prefix = (PHP_SHLIB_SUFFIX == 'dll') ? 'php_' : ''; dl($prefix . 'mcrypt.' . PHP_SHLIB_SUFFIX) or die('The Mcrypt module could not be loaded.'); } // set mcrypt mode and cipher $this->td = mcrypt_module_open($algorithm, '', $mode, '') ; // Unix has better pseudo random number generator then mcrypt, so if it is available lets use it! $random_seed = strstr(PHP_OS, "WIN") ? MCRYPT_RAND : MCRYPT_DEV_RANDOM; // if initialization vector set in constructor use it else, generate from random seed $this->iv = ($iv === false) ? mcrypt_create_iv(mcrypt_enc_get_iv_size($this->td), $random_seed) : substr($iv, 0, mcrypt_enc_get_iv_size($this->td)); // get the expected key size based on mode and cipher $expected_key_size = mcrypt_enc_get_key_size($this->td); // we dont need to know the real key, we just need to be able to confirm a hashed version $key = substr(md5($key), 0, $expected_key_size); // initialize mcrypt library with mode/cipher, encryption key, and random initialization vector mcrypt_generic_init($this->td, $key, $this->iv); } function initvector() { /* return the $iv used */ return $this->iv; } function encrypt($plain_string) { /* encrypt string using mcrypt and then encode any special characters and then return the encrypted string */ return base64_encode(mcrypt_generic($this->td, $plain_string)); } function decrypt($encrypted_string) { /* remove any special characters then decrypt string using mcrypt and then trim null padding and then finally return the encrypted string */ return trim(mdecrypt_generic($this->td, base64_decode($encrypted_string))); } // since php 4 does not have deconstructors, we will need to manually call this function function __destruct() { // shutdown mcrypt mcrypt_generic_deinit($this->td); // close mcrypt cipher module mcrypt_module_close($this->td); } } /*** USAGE ***/ /* require_once('include/class.mcrypt.php'); // require the phpMcrypt class $cryptKey = 'va364hqm34ha9v7v3n2aj3nvva6rl3m4nv78s64hv8d6cl2v4235h4'; $cipher = 'rijndael-256'; $mode = 'cbc'; $crypto = new phpMcrypt($cryptKey, $cipher, $mode); $the_string_to_be_encrypted = 'blah.blah.blah'; $the_string_that_is_encrypted = $crypto->encrypt($the_string_to_be_encrypted); $the_iv = $crypto->initvector(); $crypto->__destruct(); $crypto = new phpMcrypt($cryptKey, $cipher, $mode, $the_iv); $the_encrypted_string_decrypted = $crypto->decrypt($the_string_that_is_encrypted); $crypto->__destruct(); echo 'Original: ' . $the_string_to_be_encrypted . ' '; echo 'Initialization Vector: ' . $the_iv . ' '; echo 'Encrypted: ' . $the_string_that_is_encrypted . ' '; echo 'Decrypted: ' . $the_encrypted_string_decrypted . ' '; */ /* Possible ciphers: cast-128 gost rijndael-128 twofish arcfour cast-256 loki97 rijndael-192 saferplus wake blowfish-compat des rijndael-256 serpent xtea blowfish enigma rc2 tripledes */ /* Possible modes: cfb cbc // more secure than ECB, good security + speed compromise ctr ecb ofb */ ?>


EXECUTE THE FOLLOWING CODE VIA phpMyAdmin (changing SQL)
-- replace "xcart_" with your own prefix if needed
Code:
ALTER TABLE `xcart_customers` CHANGE `password` `password` blob NOT NULL AFTER membership, ADD `password_key` blob NOT NULL AFTER password;

SAVE AND CLOSE ALL FILES



I created a script to convert all passwords in the database, but that
proved to be a lengthy process (5000+ members would have taken several hours to process).
Due to the slow speed of that process, I altered this mod will automatically
convert a user's password when the login script is prompted in x-cart.
When an attempt is made to login, the script checks the user's password,
if it's not the new "standard", then the password is decrypted, and re-encrypted.


In config.php, you have the ability to change the encryption algorithm (CRYPT_CIPHER)
and the "mode" used for encryption (CRYPT_MODE).
The defaults provided are a strong combination (256-bit encryption), but feel
free to change. Once you set these values, you cannot alter them again.

On my own server, running latest Apache/PHP/MCrypt as provided by CPanel/WHM,
my options for CIPHER and MODE are listed below, they'll likely work for you:

Quote:
/* Possible ciphers:
cast-128
gost
rijndael-128
twofish
arcfour
cast-256
loki97
rijndael-192
saferplus
wake
blowfish-compat
des
rijndael-256
serpent
xtea
blowfish
enigma
rc2
tripledes
*/

/* Possible modes:
cfb
cbc // more secure than ECB, good security + speed compromise
ctr
ecb
ofb
*/


Cheers!

-intel352
__________________
-Jon Langevin
WARNING: Unethical developer - NOT RECOMMENDED
See details here
Reply With Quote
  #2  
Old 04-03-2006, 09:31 AM
 
intel352 intel352 is offline
 

X-Wizard
  
Join Date: Dec 2005
Posts: 1,071
 

Default

Here is the patch file contents. This is only useful to users that know how to automatically apply a patch to source code.

You must read the previous post regarding config.php, configuration of the new variables. Also you still need to execute the SQL query, found at the end of the previous post.

Code:
Index: config.php =================================================================== --- config.php (revision 12) +++ config.php (working copy) @@ -390,6 +390,14 @@ $START_CHAR_CODE = 100; # 'd' letter # +# Variables for MCrypt functionality, CRYPT_KEY should be changed per site +# +$CRYPT_KEY = 'YOUR_UNIQUE_SITE_KEY_HERE_ANY_NUMALPHA_KEY_MAKE_IT_LONG'; +$CRYPT_CIPHER = 'rijndael-256'; +$CRYPT_MODE = 'cbc'; + + +# # Include functions # @include_once($xcart_dir."/include/func.php"); Index: include/change_password.php =================================================================== --- include/change_password.php (revision 12) +++ include/change_password.php (working copy) @@ -95,7 +95,8 @@ $count = func_query_first_cell("SELECT COUNT(*) FROM $sql_tbl[old_passwords] WHERE login='".addslashes($xlogin)."' AND password='".addslashes(md5($old_password))."'"); if ($count<1) db_query("INSERT INTO $sql_tbl[old_passwords] (login,password) VALUES ('".addslashes($xlogin)."','".addslashes(md5($old_password))."')"); - db_query("UPDATE $sql_tbl[customers] SET password='".addslashes(text_crypt($new_password))."', change_password='N' WHERE login='".addslashes($xlogin)."'"); + $new_password = text_crypt($new_password,false,true,true); + db_query("UPDATE $sql_tbl[customers] SET password='".addslashes($new_password['s'])."', password_key='".addslashes($new_password['iv'])."', change_password='N' WHERE login='".addslashes($xlogin)."'"); if (isset($login_change["login"])) { $login = $login_change["login"]; $login_type = $login_change["login_type"]; @@ -110,4 +111,4 @@ $location[] = array(func_get_langvar_by_name("lbl_chpass"), ""); -?> +?> \ No newline at end of file Index: include/class.mcrypt.php =================================================================== --- include/class.mcrypt.php (revision 0) +++ include/class.mcrypt.php (revision 0) @@ -0,0 +1,141 @@ +<?php + +/* + * class.mcrypt.php -> phpMcrypt Class (PHP4) + */ + +/** + * @author Dustin Whittle + * @version 0.01 + */ + +if ( !defined('XCART_START') ) { header("Location: ../"); die("Access denied"); } + +class phpMcrypt +{ + + var $td; + var $iv = false; + + // this gets called when class is instantiated + function phpMcrypt($key = 'MyRandomStringThatWillAlwaysBeTheSame', $algorithm = 'tripledes', $mode = 'ecb', $iv = false) + { + + if(extension_loaded('mcrypt') === FALSE) + { + $prefix = (PHP_SHLIB_SUFFIX == 'dll') ? 'php_' : ''; + dl($prefix . 'mcrypt.' . PHP_SHLIB_SUFFIX) or die('The Mcrypt module could not be loaded.'); + } + + // set mcrypt mode and cipher + $this->td = mcrypt_module_open($algorithm, '', $mode, '') ; + + // Unix has better pseudo random number generator then mcrypt, so if it is available lets use it! + $random_seed = strstr(PHP_OS, "WIN") ? MCRYPT_RAND : MCRYPT_DEV_RANDOM; + + // if initialization vector set in constructor use it else, generate from random seed + $this->iv = ($iv === false) ? mcrypt_create_iv(mcrypt_enc_get_iv_size($this->td), $random_seed) : substr($iv, 0, mcrypt_enc_get_iv_size($this->td)); + + // get the expected key size based on mode and cipher + $expected_key_size = mcrypt_enc_get_key_size($this->td); + + // we dont need to know the real key, we just need to be able to confirm a hashed version + $key = substr(md5($key), 0, $expected_key_size); + + // initialize mcrypt library with mode/cipher, encryption key, and random initialization vector + mcrypt_generic_init($this->td, $key, $this->iv); + } + + function initvector() + { + /* + return the $iv used + */ + return $this->iv; + } + + function encrypt($plain_string) + { + /* + encrypt string using mcrypt and then encode any special characters + and then return the encrypted string + */ + return base64_encode(mcrypt_generic($this->td, $plain_string)); + } + + function decrypt($encrypted_string) + { + /* + remove any special characters then decrypt string using mcrypt and then trim null padding + and then finally return the encrypted string + */ + return trim(mdecrypt_generic($this->td, base64_decode($encrypted_string))); + } + + // since php 4 does not have deconstructors, we will need to manually call this function + function __destruct() + { + // shutdown mcrypt + mcrypt_generic_deinit($this->td); + + // close mcrypt cipher module + mcrypt_module_close($this->td); + } + +} + +/*** USAGE ***/ +/* +require_once('include/class.mcrypt.php'); // require the phpMcrypt class + +$cryptKey = 'va364hqm34ha9v7v3n2aj3nvva6rl3m4nv78s64hv8d6cl2v4235h4'; +$cipher = 'rijndael-256'; +$mode = 'cbc'; + +$crypto = new phpMcrypt($cryptKey, $cipher, $mode); +$the_string_to_be_encrypted = 'blah.blah.blah'; +$the_string_that_is_encrypted = $crypto->encrypt($the_string_to_be_encrypted); +$the_iv = $crypto->initvector(); +$crypto->__destruct(); + +$crypto = new phpMcrypt($cryptKey, $cipher, $mode, $the_iv); +$the_encrypted_string_decrypted = $crypto->decrypt($the_string_that_is_encrypted); +$crypto->__destruct(); + +echo 'Original: ' . $the_string_to_be_encrypted . ' '; +echo 'Initialization Vector: ' . $the_iv . ' '; +echo 'Encrypted: ' . $the_string_that_is_encrypted . ' '; +echo 'Decrypted: ' . $the_encrypted_string_decrypted . ' '; +*/ + +/* Possible ciphers: +cast-128 +gost +rijndael-128 +twofish +arcfour +cast-256 +loki97 +rijndael-192 +saferplus +wake +blowfish-compat +des +rijndael-256 +serpent +xtea +blowfish +enigma +rc2 +tripledes +*/ + +/* Possible modes: +CFB +CBC // more secure than ECB, good security + speed compromise +CTR +ECB +OFB +*/ + +?> \ No newline at end of file Index: include/func.php =================================================================== --- include/func.php (revision 12) +++ include/func.php (working copy) @@ -447,24 +447,35 @@ return chr($START_CHAR_CODE + ($c & 240) / 16).chr($START_CHAR_CODE + ($c & 15)); } -function text_crypt($s, $is_blowfish = false) { - global $START_CHAR_CODE, $CRYPT_SALT, $merchant_password, $current_area, $active_modules, $blowfish, $config; +function text_crypt($s, $is_blowfish = false, $ret_iv = false, $mcrypt = false) { + global $CRYPT_KEY, $CRYPT_CIPHER, $CRYPT_MODE, $START_CHAR_CODE, $CRYPT_SALT, $merchant_password, $current_area, $active_modules, $blowfish, $config, $xcart_dir; if ($s == "") return $s; - if($is_blowfish && $merchant_password && ($current_area == 'A' || ($current_area == 'P' && $active_modules["Simple_Mode"])) && $blowfish && $config['Security']['blowfish_enabled'] == 'Y') { - $s = trim($s); - $result = "B".func_crc32($s).func_bf_crypt($s, $merchant_password); - } else { - $enc = rand(1,255); # generate random salt. - $result = "S".text_crypt_symbol($enc); # include salt in the result; - $enc ^= $CRYPT_SALT; - for ($i = 0; $i < strlen($s); $i++) { - $r = ord(substr($s, $i, 1)) ^ $enc++; - if ($enc > 255) - $enc = 0; - $result .= text_crypt_symbol($r); - } + if($mcrypt){ + require_once($xcart_dir.'/include/class.mcrypt.php'); + + $crypto = new phpMcrypt($CRYPT_KEY, $CRYPT_CIPHER, $CRYPT_MODE); + $encrypted_str = $crypto->encrypt($s); + $iv = base64_encode($crypto->initvector()); + $crypto->__destruct(); + + $result = $ret_iv?array('s'=>$encrypted_str,'iv'=>$iv):$encrypted_str; + }else{ + if($is_blowfish && $merchant_password && ($current_area == 'A' || ($current_area == 'P' && $active_modules["Simple_Mode"])) && $blowfish && $config['Security']['blowfish_enabled'] == 'Y') { + $s = trim($s); + $result = "B".func_crc32($s).func_bf_crypt($s, $merchant_password); + } else { + $enc = rand(1,255); # generate random salt. + $result = "S".text_crypt_symbol($enc); # include salt in the result; + $enc ^= $CRYPT_SALT; + for ($i = 0; $i < strlen($s); $i++) { + $r = ord(substr($s, $i, 1)) ^ $enc++; + if ($enc > 255) + $enc = 0; + $result .= text_crypt_symbol($r); + } + } } return $result; } @@ -477,35 +488,48 @@ return (ord(substr($s, $i, 1)) - $START_CHAR_CODE)*16 + ord(substr($s, $i+1, 1)) - $START_CHAR_CODE; } -function text_decrypt($s) { - global $START_CHAR_CODE, $CRYPT_SALT, $merchant_password, $current_area, $active_modules, $blowfish; +function text_decrypt($s, $iv = '', $mcrypt = false) { + global $CRYPT_KEY, $CRYPT_CIPHER, $CRYPT_MODE, $START_CHAR_CODE, $CRYPT_SALT, $merchant_password, $current_area, $active_modules, $blowfish, $xcart_dir; if ($s == "") return $s; - $crypt_method = substr($s, 0, 1); - $s = substr($s, 1); - if($crypt_method == 'B') { - if($merchant_password && ($current_area == 'A' || ($current_area == 'P' && $active_modules["Simple_Mode"])) && $blowfish) { - $crc32 = substr($s, 0, 4); - $s = substr($s, 4); - $result = func_bf_decrypt($s, $merchant_password); - if(func_crc32($result) != $crc32) { - $result = func_get_langvar_by_name('err_data_corrupted'); + if($mcrypt){ + require_once($xcart_dir.'/include/class.mcrypt.php'); + + if($iv!='') + $crypto = new phpMcrypt($CRYPT_KEY, $CRYPT_CIPHER, $CRYPT_MODE, base64_decode($iv)); + else + $crypto = new phpMcrypt($CRYPT_KEY, $CRYPT_CIPHER, $CRYPT_MODE); + $decrypted_str = $crypto->decrypt($s); + $crypto->__destruct(); + + $result = $decrypted_str; + }else{ + $crypt_method = substr($s, 0, 1); + $s = substr($s, 1); + if($crypt_method == 'B') { + if($merchant_password && ($current_area == 'A' || ($current_area == 'P' && $active_modules["Simple_Mode"])) && $blowfish) { + $crc32 = substr($s, 0, 4); + $s = substr($s, 4); + $result = func_bf_decrypt($s, $merchant_password); + if(func_crc32($result) != $crc32) { + $result = func_get_langvar_by_name('err_data_corrupted'); + } + } else { + return false; } - } else { - return false; + } elseif($crypt_method != 'B') { + if($crypt_method != 'S') { + $s = $crypt_method.$s; + } + $enc = $CRYPT_SALT ^ text_decrypt_symbol($s, 0); + $result = ""; + for ($i = 2; $i < strlen($s); $i+=2) { # $i=2 to skip salt + $result .= chr(text_decrypt_symbol($s, $i) ^ $enc++); + if ($enc > 255) + $enc = 0; + } } - } elseif($crypt_method != 'B') { - if($crypt_method != 'S') { - $s = $crypt_method.$s; - } - $enc = $CRYPT_SALT ^ text_decrypt_symbol($s, 0); - $result = ""; - for ($i = 2; $i < strlen($s); $i+=2) { # $i=2 to skip salt - $result .= chr(text_decrypt_symbol($s, $i) ^ $enc++); - if ($enc > 255) - $enc = 0; - } } return $result; } @@ -736,9 +760,9 @@ unset($extended_info); } - $userinfo["passwd1"] = stripslashes(text_decrypt($userinfo["password"])); - $userinfo["passwd2"] = stripslashes(text_decrypt($userinfo["password"])); - $userinfo["password"] = stripslashes(text_decrypt($userinfo["password"])); + $userinfo["passwd1"] = stripslashes(text_decrypt($userinfo["password"], $userinfo["password_key"], true)); + $userinfo["passwd2"] = stripslashes(text_decrypt($userinfo["password"], $userinfo["password_key"], true)); + $userinfo["password"] = stripslashes(text_decrypt($userinfo["password"], $userinfo["password_key"], true)); $userinfo["card_number"] = text_decrypt($userinfo["card_number"]); list($userinfo["b_address"], $userinfo["b_address_2"]) = split("[\n\r]+", $userinfo["b_address"]); $userinfo["b_statename"] = func_get_state($userinfo["b_state"], $userinfo["b_country"]); @@ -5253,8 +5277,8 @@ # # Check password security for specified user name # - $account = func_query_first("SELECT login, password FROM $sql_tbl[customers] WHERE login='$uname'"); - if ($account["login"] == text_decrypt($account["password"])) + $account = func_query_first("SELECT login, password, password_key FROM $sql_tbl[customers] WHERE login='$uname'"); + if ($account["login"] == text_decrypt($account["password"], $account["password_key"], true)) $return[] = $account["login"]; } else { @@ -5265,9 +5289,9 @@ foreach ($accounts as $login_) { if (!empty($uname) and $uname != $login_) continue; - $account = func_query_first("SELECT login, password FROM $sql_tbl[customers] WHERE login='$login_' AND usertype='$usertype'"); + $account = func_query_first("SELECT login, password, password_key FROM $sql_tbl[customers] WHERE login='$login_' AND usertype='$usertype'"); if (!empty($account)) { - if ($account["login"] == text_decrypt($account["password"])) + if ($account["login"] == text_decrypt($account["password"], $account["password_key"], true)) $return[] = $account["login"]; } } Index: include/help.php =================================================================== --- include/help.php (revision 12) +++ include/help.php (working copy) @@ -135,14 +135,14 @@ # if ($REQUEST_METHOD=="POST" and $action=="recover_password") { -$accounts = func_query("select login, password, usertype from $sql_tbl[customers] where email='$email' and status='Y'"); +$accounts = func_query("select login, password, password_key, usertype from $sql_tbl[customers] where email='$email' and status='Y'"); # # Decrypt passwords # if($accounts) { foreach($accounts as $key=>$account) - $accounts[$key]["password"]=text_decrypt($accounts[$key]["password"]); + $accounts[$key]["password"]=text_decrypt($accounts[$key]["password"], $accounts[$key]["password_key"], true); $mail_smarty->assign("accounts",$accounts); Index: include/login.php =================================================================== --- include/login.php (revision 12) +++ include/login.php (working copy) @@ -95,7 +95,15 @@ $allow_login = in_array($REMOTE_ADDR, $iplist); } + + if ($user_data['password_key']==''){ + $newpass = text_crypt(text_decrypt($user_data['password']),false,true,true); + $user_data['password'] = $newpass['s']; + $user_data['password_key'] = $newpass['iv']; + db_query("UPDATE $sql_tbl[customers] SET password='".addslashes($user_data["password"])."',password_key='".addslashes($user_data["password_key"])."' WHERE loginid='".$user_data["loginid"]."'"); + unset($newpass); + } - if (!empty($user_data) && $password == text_decrypt($user_data["password"]) && !empty($password) && $allow_login) { + if ($allow_login && !empty($user_data) && !empty($password) && $password == text_decrypt($user_data["password"], $user_data["password_key"], true)) { # # Success login # Index: include/register.php =================================================================== --- include/register.php (revision 12) +++ include/register.php (working copy) @@ -341,7 +341,7 @@ # # Fields filled without errors. User registered successfully # - $crypted = addslashes(text_crypt($passwd1)); + $crypted = addslashes(text_crypt($passwd1,false,true,true)); if($default_fields['s_state']['avail'] == 'Y' && $default_fields['s_country']['avail'] == 'Y') { if (is_array($states) and !func_check_state($states, stripslashes($s_state), $s_country) && $s_display_states) { @@ -414,7 +414,7 @@ if ($mode=="update") { $intershipper_recalc = "Y"; - db_query("UPDATE $sql_tbl[customers] SET password='$crypted', password_hint='$password_hint', password_hint_answer='$password_hint_answer', title='$title', firstname='$firstname', lastname='$lastname', company='$company', b_address='".$b_address."\n".$b_address_2."', b_city='$b_city', b_county='".(@$b_county)."', b_state='$b_state', b_country='$b_country', b_zipcode='$b_zipcode', s_address='".$s_address."\n".$s_address_2."', s_city='$s_city', s_county='".(@$s_county)."', s_state='$s_state', s_country='$s_country', s_zipcode='$s_zipcode', phone='$phone', email='$email', fax='$fax', url='$url', card_name='$card_name', card_type='$card_type', card_number='".addslashes(text_crypt($card_number))."', card_expire='$card_expire', card_cvv2='$card_cvv2', pending_membership='$pending_membership', ssn='$ssn', change_password='$change_password', parent = '$parent', pending_plan_id = '$pending_plan_id' WHERE login='$login' AND usertype='$login_type'"); + db_query("UPDATE $sql_tbl[customers] SET password='".addslashes($crypted['s'])."', password_key='".addslashes($crypted['iv'])."', password_hint='$password_hint', password_hint_answer='$password_hint_answer', title='$title', firstname='$firstname', lastname='$lastname', company='$company', b_address='".$b_address."\n".$b_address_2."', b_city='$b_city', b_county='".(@$b_county)."', b_state='$b_state', b_country='$b_country', b_zipcode='$b_zipcode', s_address='".$s_address."\n".$s_address_2."', s_city='$s_city', s_county='".(@$s_county)."', s_state='$s_state', s_country='$s_country', s_zipcode='$s_zipcode', phone='$phone', email='$email', fax='$fax', url='$url', card_name='$card_name', card_type='$card_type', card_number='".addslashes(text_crypt($card_number))."', card_expire='$card_expire', card_cvv2='$card_cvv2', pending_membership='$pending_membership', ssn='$ssn', change_password='$change_password', parent = '$parent', pending_plan_id = '$pending_plan_id' WHERE login='$login' AND usertype='$login_type'"); db_query("DELETE FROM $sql_tbl[register_field_values] WHERE login = '$login'"); if($additional_values) { @@ -467,7 +467,7 @@ # $intershipper_recalc = "Y"; - db_query("INSERT INTO $sql_tbl[customers] (login,usertype,password,password_hint,password_hint_answer,title,firstname,lastname,company,b_address,b_city,b_county,b_state,b_country,b_zipcode,s_address,s_city,s_county,s_state,s_country,s_zipcode,phone,email,fax,url,card_name,card_type,card_number,card_expire,card_cvv2,first_login,status,referer,pending_membership,ssn,parent,pending_plan_id,change_password) VALUES ('$uname','$usertype','$crypted','".@$password_hint."','".@$password_hint_answer."','$title','$firstname','$lastname','$company','".$b_address."\n".$b_address_2."','$b_city','".(@$b_county)."','$b_state','$b_country','$b_zipcode','".$s_address."\n".$s_address_2."','$s_city','".(@$s_county)."','$s_state','$s_country','$s_zipcode','$phone','$email','$fax','$url','".@$card_name."','".@$card_type."','".addslashes(text_crypt(@$card_number))."','".@$card_expire."','".@$card_cvv2."','".time()."','Y','".@$RefererCookie."','".@$pending_membership."','".@$ssn."', '$parent', '$pending_plan_id','$change_password')"); + db_query("INSERT INTO $sql_tbl[customers] (login,usertype,password,password_key,password_hint,password_hint_answer,title,firstname,lastname,company,b_address,b_city,b_county,b_state,b_country,b_zipcode,s_address,s_city,s_county,s_state,s_country,s_zipcode,phone,email,fax,url,card_name,card_type,card_number,card_expire,card_cvv2,first_login,status,referer,pending_membership,ssn,parent,pending_plan_id,change_password) VALUES ('$uname','$usertype','".addslashes($crypted['s'])."','".addslashes($crypted['iv'])."','".@$password_hint."','".@$password_hint_answer."','$title','$firstname','$lastname','$company','".$b_address."\n".$b_address_2."','$b_city','".(@$b_county)."','$b_state','$b_country','$b_zipcode','".$s_address."\n".$s_address_2."','$s_city','".(@$s_county)."','$s_state','$s_country','$s_zipcode','$phone','$email','$fax','$url','".@$card_name."','".@$card_type."','".addslashes(text_crypt(@$card_number))."','".@$card_expire."','".@$card_cvv2."','".time()."','Y','".@$RefererCookie."','".@$pending_membership."','".@$ssn."', '$parent', '$pending_plan_id','$change_password')"); db_query("REPLACE INTO $sql_tbl[login_history] (login, date_time, usertype, action, status, ip) VALUES ('$uname','".time()."','$usertype','login','success','$REMOTE_ADDR')"); Index: sql/xcart_tables.sql =================================================================== --- sql/xcart_tables.sql (revision 12) +++ sql/xcart_tables.sql (working copy) @@ -281,7 +281,8 @@ login varchar(32) NOT NULL default '', usertype char(1) NOT NULL default '', membership varchar(32) NOT NULL default '', - password varchar(128) NOT NULL default '', + password blob NOT NULL, + password_key blob NOT NULL, password_hint varchar(128) NOT NULL default '', password_hint_answer varchar(128) NOT NULL default '', b_address varchar(64) NOT NULL default '',
__________________
-Jon Langevin
WARNING: Unethical developer - NOT RECOMMENDED
See details here
Reply With Quote
Reply
   X-Cart forums > X-Cart 4 > Dev Questions


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump


All times are GMT -8. The time now is 10:16 AM.

   

 
X-Cart forums © 2001-2020