Implemented re-keying of CustomerPortal. See PHPCRED-38
Implemented re-keying of CustomerPortal. See PHPCRED-38

<?php <?php
/** PHPCredLocker Re-Key Utility /** PHPCredLocker Re-Key Utility
* *
* Re-Generates Crypto keys and re-encrypts all stored data - Likely to be a long process! * Re-Generates Crypto keys and re-encrypts all stored data - Likely to be a long process!
* *
* Copyright (C) 2014 B Tasker * Copyright (C) 2014 B Tasker
* Released under GNU AGPL V3 * Released under GNU AGPL V3
* See LICENSE * See LICENSE
* *
*/ */
   
require_once 'cli_only.php'; require_once 'cli_only.php';
   
define('_CREDLOCK',"1"); define('_CREDLOCK',"1");
error_reporting(0); error_reporting(0);
   
   
   
/** Wrapper class so that keys can be read from different sources /** Wrapper class so that keys can be read from different sources
* *
*/ */
class cryptokeyscli{ class cryptokeyscli{
   
function __construct(){ function __construct(){
require 'conf/crypto.php'; require 'conf/crypto.php';
$this->keys = $crypt; $this->keys = $crypt;
$this->cipher = $cipher; $this->cipher = $cipher;
} }
   
   
function writekeyfile(){ function writekeyfile(){
   
$fh = fopen('conf/crypto.php','w'); $fh = fopen('conf/crypto.php','w');
   
fwrite($fh,"<?php\n /** Crypto Keys\n * KEEP THIS FILE SECRET\n * \n */\n defined('_CREDLOCK') or die; \n"); fwrite($fh,"<?php\n /** Crypto Keys\n * KEEP THIS FILE SECRET\n * \n */\n defined('_CREDLOCK') or die; \n");
   
fwrite($fh,"\n\n/** Cipher settings */\n\n"); fwrite($fh,"\n\n/** Cipher settings */\n\n");
   
foreach ($this->cipher as $k=>$v){ foreach ($this->cipher as $k=>$v){
   
if (!is_object($v)){ if (!is_object($v)){
fwrite($fh,"\$cipher->$k = '$v';\n"); fwrite($fh,"\$cipher->$k = '$v';\n");
}else{ }else{
foreach ($v as $vk => $vv){ foreach ($v as $vk => $vv){
fwrite($fh,"\$cipher->$k->$vk = '$vv';\n"); fwrite($fh,"\$cipher->$k->$vk = '$vv';\n");
} }
} }
   
} }
   
   
fwrite($fh,"\n\n/** KEYS FOLLOW */\n"); fwrite($fh,"\n\n/** KEYS FOLLOW */\n");
foreach ($this->keys as $k=>$v){ foreach ($this->keys as $k=>$v){
fwrite($fh,"\$crypt->$k = '$v';\n\n"); fwrite($fh,"\$crypt->$k = '$v';\n\n");
} }
   
fclose($fh); fclose($fh);
} }
   
} }
   
   
   
class Utils{ class Utils{
static function genKey($len){ static function genKey($len){
$newkey = null; $newkey = null;
while ($len > 0){ while ($len > 0){
   
$key = Crypto::generateNum(32,254); $key = Crypto::generateNum(32,254);
if ($key == 127 ){ if ($key == 127 ){
// Skip the delete char // Skip the delete char
continue; continue;
} }
   
$newkey .= chr($key); $newkey .= chr($key);
$len--; $len--;
   
} }
   
return base64_encode($newkey); return base64_encode($newkey);
   
} }
} }
   
   
   
   
// Set the working directory to the root // Set the working directory to the root
chdir(dirname(__FILE__)."/../"); chdir(dirname(__FILE__)."/../");
   
// Load the framework and config etc // Load the framework and config etc
require_once 'lib/Framework/main.php'; require_once 'lib/Framework/main.php';
require_once 'lib/crypto.php'; require_once 'lib/crypto.php';
   
   
$output = new CLIOutput; $output = new CLIOutput;
$input = new CLIInput; $input = new CLIInput;
   
$output->_("PHPCredlocker Re-Key Script\n==========================\n"); $output->_("PHPCredlocker Re-Key Script\n==========================\n");
$output->_("Note: This script may take some time to complete, and the WebUI may not function correctly until complete"); $output->_("Note: This script may take some time to complete, and the WebUI may not function correctly until complete");
   
$confirm = $input->read("Type YES to continue"); $confirm = $input->read("Type YES to continue");
   
if ($confirm != "YES"){ if ($confirm != "YES"){
$output->_("Aborting"); $output->_("Aborting");
die; die;
} }
   
   
$output->_("Backing up crypto.php"); $output->_("Backing up crypto.php");
if (!copy("conf/crypto.php","conf/crypto.backup.php")){ if (!copy("conf/crypto.php","conf/crypto.backup.php")){
$output->_("Could not back up keyfile. Aborting"); $output->_("Could not back up keyfile. Aborting");
die; die;
} }
   
   
   
$db = new BTDB; $db = new BTDB;
$crypt = new Crypto; $crypt = new Crypto;
$currentkeys = new cryptokeyscli(); // We use this object to make sure we've got a copy of the original $currentkeys = new cryptokeyscli(); // We use this object to make sure we've got a copy of the original
$newkeys = new cryptokeyscli(); // We'll be making the changes in here $newkeys = new cryptokeyscli(); // We'll be making the changes in here
   
   
$keylength = $newkeys->cipher->keyLength; $keylength = $newkeys->cipher->keyLength;
   
$output->_("Preparing to Re-Key Users"); $output->_("Preparing to Re-Key Users");
   
$db->setQuery("SELECT * FROM #__Users"); $db->setQuery("SELECT * FROM #__Users");
$users = $db->loadResults(); $users = $db->loadResults();
   
// For users, it's as simple as re-encrypting the Password hash // For users, it's as simple as re-encrypting the Password hash
$passes = array(); $passes = array();
   
foreach ($users as $user){ foreach ($users as $user){
$passes[$user->username] = $crypt->decrypt($user->pass,'auth'); $passes[$user->username] = $crypt->decrypt($user->pass,'auth');
} }
   
  // We also need to grab any data in the Customer Portal table and re-encrypt that
  $sql = "SELECT * FROM #__CustPortal";
  $db->setQuery($sql);
  $cportal = $db->loadResults();
  $ccportal = array();
   
  foreach ($cportal as $cust){
   
  $cust->email = $crypt->decrypt($cust->email,'auth');
  $cust->pass = $crypt->decrypt($cust->pass,'auth');
  $ccportal[] = $cust;
   
  }
   
   
   
   
$output->_("Generating new encryption key"); $output->_("Generating new encryption key");
   
$newkeys->keys->auth = Utils::genKey($keylength); $newkeys->keys->auth = Utils::genKey($keylength);
   
// Write the key // Write the key
$newkeys->writekeyfile(); $newkeys->writekeyfile();
   
// Encrypt using the new key and update the database // Encrypt using the new key and update the database
foreach ($passes as $user=>$pass){ foreach ($passes as $user=>$pass){
$cpass = $crypt->encrypt($pass,'auth'); $cpass = $crypt->encrypt($pass,'auth');
   
$sql = "UPDATE #__Users SET pass='".$db->stringEscape($cpass)."' WHERE username='".$db->stringEscape($user)."'"; $sql = "UPDATE #__Users SET pass='".$db->stringEscape($cpass)."' WHERE username='".$db->stringEscape($user)."'";
$db->setQuery($sql); $db->setQuery($sql);
$db->runQuery(); $db->runQuery();
} }
   
   
  foreach ($ccportal as $cust){
  $cust->email = $crypt->encrypt($cust->email,'auth');
  $cust->pass = $crypt->encrypt($cust->pass,'auth');
   
  $sql = "UPDATE #__CustPortal SET `email`='".$db->stringEscape($cust->email)."', `pass`='".$db->stringEscape($cust->pass)."' WHERE id=".(int) $cust->id;
  $db->setQuery($sql);
  $db->runQuery();
  }
   
   
unset($passes); unset($passes);
$output->_(""); $output->_("");
$confirm = $input->read("User database has been re-keyed. Please LOG IN to the web interface to check it's worked. If it has type YES to continue"); $confirm = $input->read("User database has been re-keyed. Please LOG IN to the web interface to check it's worked. If it has type YES to continue");
   
   
// Probably need to do a little more to hold the users hand here really // Probably need to do a little more to hold the users hand here really
if ($confirm != "YES"){ if ($confirm != "YES"){
$output->_("Aborting"); $output->_("Aborting");
die; die;
} }
   
   
   
   
// Credtypes are similarly simple, just the name to switch // Credtypes are similarly simple, just the name to switch
   
$output->_("Preparing to Re-Key Credential Types"); $output->_("Preparing to Re-Key Credential Types");
   
$db->setQuery("SELECT * FROM #__CredTypes"); $db->setQuery("SELECT * FROM #__CredTypes");
$credtypes = $db->loadResults(); $credtypes = $db->loadResults();
   
$ctypes = array(); $ctypes = array();
   
foreach ($credtypes as $credtype){ foreach ($credtypes as $credtype){
$credtype->Name = $crypt->decrypt($credtype->Name,'CredType'); $credtype->Name = $crypt->decrypt($credtype->Name,'CredType');
$ctypes[] = $credtype; $ctypes[] = $credtype;
} }
   
   
$output->_("Generating new encryption key"); $output->_("Generating new encryption key");
$newkeys->keys->CredType = Utils::genKey($keylength); $newkeys->keys->CredType = Utils::genKey($keylength);
$newkeys->writekeyfile(); $newkeys->writekeyfile();
   
// Encrypt and update // Encrypt and update
   
foreach ($ctypes as $credtype){ foreach ($ctypes as $credtype){
$name = $crypt->encrypt($credtype->Name,'CredType'); $name = $crypt->encrypt($credtype->Name,'CredType');
$db->setQuery("UPDATE #__CredTypes SET `Name`='".$db->stringEscape($name)."' WHERE `id`=".(int)$credtype->id); $db->setQuery("UPDATE #__CredTypes SET `Name`='".$db->stringEscape($name)."' WHERE `id`=".(int)$credtype->id);
$db->runQuery(); $db->runQuery();
} }
unset($ctypes); unset($ctypes);
unset($credtypes); unset($credtypes);
   
$output->_(""); $output->_("");
$confirm = $input->read("CredTypes have been re-keyed, Please log into the front end and ensure that you can view Credential Type names correctly"); $confirm = $input->read("CredTypes have been re-keyed, Please log into the front end and ensure that you can view Credential Type names correctly");
   
   
// Probably need to do a little more to hold the users hand here really // Probably need to do a little more to hold the users hand here really
if ($confirm != "YES"){ if ($confirm != "YES"){
$output->_("Aborting"); $output->_("Aborting");
die; die;
} }
   
   
// Customers require a little more work! // Customers require a little more work!
   
$output->_("Preparing to Re-Key Customers"); $output->_("Preparing to Re-Key Customers");
   
$db->setQuery("SELECT * FROM #__Cust"); $db->setQuery("SELECT * FROM #__Cust");
$customers = $db->loadResults(); $customers = $db->loadResults();
$ccustomers = array(); $ccustomers = array();
   
foreach ($customers as $customer){ foreach ($customers as $customer){
   
$customer->Name = $crypt->decrypt($customer->Name,'Customer'); $customer->Name = $crypt->decrypt($customer->Name,'Customer');
$customer->ContactName = $crypt->decrypt($customer->ContactName,'Customer'); $customer->ContactName = $crypt->decrypt($customer->ContactName,'Customer');
$customer->ContactSurname = $crypt->decrypt($customer->ContactSurname,'Customer'); $customer->ContactSurname = $crypt->decrypt($customer->ContactSurname,'Customer');
$customer->Email = $crypt->decrypt($customer->Email,'Customer'); $customer->Email = $crypt->decrypt($customer->Email,'Customer');
$ccustomers[] = $customer; $ccustomers[] = $customer;
   
} }
   
   
$output->_("Generating new encryption key"); $output->_("Generating new encryption key");
$newkeys->keys->Customer = Utils::genKey($keylength); $newkeys->keys->Customer = Utils::genKey($keylength);
$newkeys->writekeyfile(); $newkeys->writekeyfile();
   
   
// Encrypt and update // Encrypt and update
   
foreach ($ccustomers as $customer){ foreach ($ccustomers as $customer){
   
$customer->Name = $crypt->encrypt($customer->Name,'Customer'); $customer->Name = $crypt->encrypt($customer->Name,'Customer');
$customer->ContactName = $crypt->encrypt($customer->ContactName,'Customer'); $customer->ContactName = $crypt->encrypt($customer->ContactName,'Customer');
$customer->ContactSurname = $crypt->encrypt($customer->ContactSurname,'Customer'); $customer->ContactSurname = $crypt->encrypt($customer->ContactSurname,'Customer');
$customer->Email = $crypt->encrypt($customer->Email,'Customer'); $customer->Email = $crypt->encrypt($customer->Email,'Customer');
   
   
$sql = "UPDATE #__Cust SET `Name`='".$db->stringEscape($customer->Name)."', `ContactName`='".$db->stringEscape($customer->ContactName)."',". $sql = "UPDATE #__Cust SET `Name`='".$db->stringEscape($customer->Name)."', `ContactName`='".$db->stringEscape($customer->ContactName)."',".
"`ContactSurname`='".$db->stringEscape($customer->ContactSurname)."',`Email`='".$db->stringEscape($customer->Email)."' WHERE `id`=".(int)$customer->id; "`ContactSurname`='".$db->stringEscape($customer->ContactSurname)."',`Email`='".$db->stringEscape($customer->Email)."' WHERE `id`=".(int)$customer->id;
$db->setQuery($sql); $db->setQuery($sql);
$db->runQuery(); $db->runQuery();
} }
unset($ccustomers); unset($ccustomers);
unset($customers); unset($customers);
$output->_(""); $output->_("");
$confirm = $input->read("Customers have been re-keyed, Please log into the front end and ensure that you can view Customer names and details correctly"); $confirm = $input->read("Customers have been re-keyed, Please log into the front end and ensure that you can view Customer names and details correctly");
   
// Probably need to do a little more to hold the users hand here really // Probably need to do a little more to hold the users hand here really
if ($confirm != "YES"){ if ($confirm != "YES"){
$output->_("Aborting"); $output->_("Aborting");
die; die;
} }
   
   
   
   
// Groups next, relatively straight forward // Groups next, relatively straight forward
   
$output->_("Preparing to Re-Key Groups"); $output->_("Preparing to Re-Key Groups");
$db->setQuery("SELECT * FROM #__Groups"); $db->setQuery("SELECT * FROM #__Groups");
$groups = $db->loadResults(); $groups = $db->loadResults();
$cgroups = array(); $cgroups = array();
   
foreach ($groups as $group){ foreach ($groups as $group){
   
$group->Name = $crypt->decrypt($group->Name,'Groups'); $group->Name = $crypt->decrypt($group->Name,'Groups');
$cgroups[] = $group; $cgroups[] = $group;
} }
   
$output->_("Generating new encryption key"); $output->_("Generating new encryption key");
$newkeys->keys->Groups = Utils::genKey($keylength); $newkeys->keys->Groups = Utils::genKey($keylength);
$newkeys->writekeyfile(); $newkeys->writekeyfile();
   
   
foreach ($cgroups as $group){ foreach ($cgroups as $group){
   
$group->Name = $crypt->encrypt($group->Name,'Groups'); $group->Name = $crypt->encrypt($group->Name,'Groups');
$sql = "UPDATE #__Groups SET `Name`='".$group->Name."' WHERE `id`=".(int)$group->id; $sql = "UPDATE #__Groups SET `Name`='".$group->Name."' WHERE `id`=".(int)$group->id;
$db->setQuery($sql); $db->setQuery($sql);
$db->runQuery(); $db->runQuery();
   
} }
   
unset($cgroups); unset($cgroups);
unset($groups); unset($groups);
$output->_(""); $output->_("");
$confirm = $input->read("Groups have been re-keyed, Please log into the front end and ensure that you can view Group names correctly"); $confirm = $input->read("Groups have been re-keyed, Please log into the front end and ensure that you can view Group names correctly");
   
// Probably need to do a little more to hold the users hand here really // Probably need to do a little more to hold the users hand here really
if ($confirm != "YES"){ if ($confirm != "YES"){
$output->_("Aborting"); $output->_("Aborting");
die; die;
} }