PHP Classes

File: handlers/encrypting.inc.php

Recommend this page to a friend!
  Classes of Colin McKinnon   Stackable PHP Session Handler   handlers/encrypting.inc.php   Download  
File: handlers/encrypting.inc.php
Role: Class source
Content type: text/plain
Description: Encrypting Session Handler
Class: Stackable PHP Session Handler
Store session data with multiple session handlers
Author: By
Last change:
Date: 8 years ago
Size: 5,644 bytes
 

Contents

Class file image Download
<?php

/**
 * Encrypting PHP session handler
 * The session data is encypted using a random key stored in a cookie
 *
 * Note that since there is no session handler hook for regenerateId in PHP < 5.5.10, we can't tell
 * when we should create a new key - and in the absence of further checks, the key
 * is vulnerable to fixation!
 *
 * The actual encryption is provided by a slaved object - the example below uses AES256
 * The session object provides key management and stackable session handling capability
 * while the encryptor deals with encoding, encryption algorithms/modes/initialization
 * vectors.
 *
 * Here I've used the session id as the initialization vector. This is marginally better
 * than just encrypting the data, but is predictable. OTOH using a random IV means that
 * we have an additional complication of managing that data.
 */

class encryptingSessionHandler extends stackSess {
    private
$ekey;
    private
$keyname;
    private
$engine;
    private
$sessionidread;
    private
$keyregenerated;

    function
__construct($shNext=false, $keyname=false)
    {
        if (
false!=$shNext) {
           
$this->addNext($shNext);
        }
        if (
$keyname) {
           
$this->keyname=$keyname;
        } else {
           
$this->keyname='x' .session_name();
        }
    }
    function
open($save_path, $name)
        {
       
$this->logit("encryptingSessionHandler::open($save_path, $name)");
       
$this->engine=new encryptorEngine();

       
$p=session_get_cookie_params();

        if (isset(
$_COOKIE[$this->keyname]) && 5<strlen($_COOKIE[$this->keyname])) {
           
$this->ekey=urldecode($_COOKIE[$this->keyname]);
        } else {
           
$this->createKey();
           
$this->logit("changed key to " . $this->ekey);
        }
        if (
$this->shStackNext) {
           
$result=$this->shStackNext->open($save_path, $name);
        }
        return (
$this->ekey && $result);
    }

    function
read($session_id)
    {
       
$this->logit("encryptingSessionHandler::read($session_id)");
       
$this->sessionidread=$session_id;
        if (
$this->shStackNext) {
           
$data=$this->shStackNext->read($session_id);
            if (!
$data) return '';
            return
$this->engine->decrypt($data,$this->ekey, $session_id);
        } else {
           
trigger_error("Encrpyting ssession handler must be chained to a storage handler", E_USER_ERROR);
            return
false;
        }
    }
   
    function
write($session_id, $session_data)
    {
       
$this->logit("encryptingSessionHandler::write($session_id, session_data)");
        if (
$this->sessionidread!=$session_id && !$this->keyregenerated) {
           
$msg=$this->sessionidread . " to " . $session_id;
           
trigger_error("Session ID regenerated ($msg) but encryption key not changed!", E_USER_WARNING);
        }
       
$data=$this->engine->encrypt($session_data,$this->ekey,$session_id);
        return
$this->shStackNext->write($session_id, $data);
    }

   
/**
     * in addition to telling the other handlers to destroy the session
     * we also remove the key
     */
   
function destroy($session_id)
    {
       
$this->createKey();
        return
$this->shStackNext->destroy($session_id);
    }

    function
create_sid($newltCreatedSid=false)
    {
       
$this->logit("encryptingSessionHandler::create_sid()");
       
$this->createKey();
       
$newlyCreatedSid=$this->shStackNext->create_sid($newlyCreatedSid);
        return
$newlyCreatedSid;
    }

    function
createKey()
    {
       
$this->logit("encryptingSessionHandler::createKey()");
       
$p=session_get_cookie_params();
       
$key=$this->engine->generateRandomKey();
        if (
setcookie($this->keyname, $key,
           
$p['lifetime'], $p['path'], $p['domain'], $p['secure'], $p['httponly'])) {
           
$this->keyregenerated=true;
           
$this->ekey=$key;
            return
$key;
                }
       
$this->logit("Failed in encryptingSessionHandler::createKey()");
        return
false;
        }
}

class
dummyEncryptorEngine {
    function
encrypt($data,$key,$sessionid)
    {
        return
$data;
    }
    function
decrypt($data,$key,$sessionid)
    {
        return
$data;
    }
    function
generateRandomKey()
    {
        return
uniqid();
    }
}
class
encryptorEngine {
    private
$descriptor;
    private
$iv;
    private
$iv_basedon;
   
    function
__construct($algo='rijndael-256')
    {
       
$this->d=mcrypt_module_open($algo, '', 'cbc', '');
    }
    function
checkIv($sessionid)
    {
        if (
$sessionid==$this->iv_basedon) {
            return
$this->iv;
        }
       
$this->iv_basedon=$sessionid;

       
$proto=$sessionid;
       
$ivlength=mcrypt_enc_get_iv_size($this->d);
        while (
strlen($sessionid) && strlen($proto)<$ivlength) {
           
$proto.=$sessionid;
        }
       
$proto=sha1($sessionid);
       
$proto.=$proto;
       
$this->iv=substr($proto, 0, $ivlength);
        return
$this->iv;
    }
    function
encrypt($data,$key,$sessionid)
    {
       
$iv=$this->checkIv($sessionid);
       
mcrypt_generic_init($this->d, $this->unmakesafe($key), $iv);
       
$encrypted=base64_encode(mcrypt_generic($this->d, $data));
       
mcrypt_generic_deinit($this->d);
        return
$encrypted;
    }
    function
decrypt($data,$key,$sessionid)
    {
       
$iv=$this->checkIv($sessionid);
       
mcrypt_generic_init($this->d, $this->unmakesafe($key), $iv);
       
$decrypted=mdecrypt_generic($this->d, base64_decode($data));
       
mcrypt_generic_deinit($this->d);
        return
$decrypted;
    }
    function
generateRandomKey()
    {
       
$length=mcrypt_enc_get_key_size($this->d);
        if (
function_exists('openssl_random_pseudo_bytes')) {
            return
$this->makesafe(openssl_random_pseudo_bytes($length));
        }
        if (
function_exists('random_bytes')) {
            return
$this->makesafe(random_bytes($length));
        }
               
$key=$this->makesafe(uniqid('',true));
               
trigger_error("Session encryption using low entropy key generator", E_USER_WARNING);
        return
$key;
    }
    function
makesafe($str)
    {
       
$str=base64_encode($str);
       
$str=str_replace('+','-',$str);
       
$str=str_replace('=','.',$str);
        return
$str;
    }
    function
unmakesafe($str)
    {
       
$str=str_replace('.','=',$str);
       
$str=str_replace('-','+',$str);
        return
base64_decode($str);
    }
}