<?php

/**
 *--------------------------------------
 * encryption and decryption
 *--------------------------------------
 * @project		: pfa
 * @author		: cblee
 * @created		: 2012-9-23
 * @copyright	: (c)2012 AsThis
 *--------------------------------------
 */
defined('PFA_PATH') or exit('Access Denied');

class ACrypt {
	/* array need serialize to string before encrypt */
	public static function encrypt($string, $key = '', $expireTime = 0, $ckeyLength = 4) {
		return self::_crypt($string, $key, 'ENCODE', $expireTime, $ckeyLength);
	}

	public static function decrypt($string, $key = '', $ckeyLength = 4) {
		return self::_crypt($string, $key, 'DECODE', 0, $ckeyLength);
	}

	//$ckeyLength:dynamic key length, use for generate different ciphertext from same string
	private static function _crypt($string, $key = '', $operation = 'ENCODE', $expireTime = 0, $ckeyLength = 4) {
		$key = md5($key); // key
		$keyA = md5(substr($key, 0, 16)); // key A is used to encryption and decryption
		$keyB = md5(substr($key, 16, 16)); // key B is used for data integrity verification
		// key C is for dynamically generated ciphertext
		if('ENCODE' == $operation) {
			$keyC = $ckeyLength ? substr(md5(microtime()), -$ckeyLength) : '';
		}
		else {
			$keyC = $ckeyLength ? substr($string, 0, $ckeyLength) : '';
		}
		$cryptKey = $keyA.md5($keyA.$keyC); // key for crypt

		$keyLength = strlen($cryptKey);

		if('ENCODE' == $operation) {
			// plaintext, 1-10: timestamp; 11-26: key B;
			$string = sprintf('%010d', $expireTime ? $expireTime + time() : 0).substr(md5($string.$keyB), 0, 16).$string;
		}
		else {
			// start from $ckeyLength
			$string = base64_decode(substr($string, $ckeyLength));
		}

		$string_length = strlen($string);
		$result = '';
		$box = range(0, 255);
		$rndKey = array();
		// create secret key book
		for($i = 0; $i <= 255; $i++) {
			$rndKey[$i] = ord($cryptKey[$i % $keyLength]);
		}
		// disrupt secret key book
		for($j = $i = 0; $i < 256; $i++) {
			$j = ($j + $box[$i] + $rndKey[$i]) % 256;
			$tmp = $box[$i];
			$box[$i] = $box[$j];
			$box[$j] = $tmp;
		}
		// core crypt
		for($a = $j = $i = 0; $i < $string_length; $i++) {
			$a = ($a + 1) % 256;
			$j = ($j + $box[$a]) % 256;
			$tmp = $box[$a];
			$box[$a] = $box[$j];
			$box[$j] = $tmp;
			// key from secret key book by XOR, then turn into characters
			$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
		}

		if('ENCODE' == $operation) {
			// the dynamic key is stored in the ciphertext
			return $keyC.str_replace('=', '', base64_encode($result));
		}
		else {
			// substr($result, 0, 10) == 0 verify the validity of data
			// substr($result, 0, 10) - time() > 0 verify the validity of data
			// substr($result, 10, 16) == substr(md5(substr($result, 26).$keyB), 0, 16) verify data integrity
			if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyB), 0, 16)) {
				return substr($result, 26);
			}
			else {
				return '';
			}
		}
	}

	public function __construct() {
	}
}

?>