康盛的 authcode 函數很牛叉,是一個具備有效期的加解密函數,同一個字符每次加密所產生的結果都是不一致的,而且能夠自定義設置過時時間。php
設計原理:authcode 是使用異或運算進行加密和解密。html
加密算法
明文:1010 1001函數
密匙:1110 0011編碼
密文:0100 1010加密
得出密文0100 1010,解密之需和密匙異或下就能夠了spa
解密設計
密文:0100 1010code
密匙:1110 0011htm
明文:1010 1001
並無什麼高深的算法,密匙重要性很高,因此,關鍵在於怎麼生成密匙。
1 <?php 2 3 /** 4 * @param string $string 原文或者密文 5 * @param string $operation 操做(ENCODE | DECODE), 默認爲 DECODE 6 * @param string $key 密鑰 7 * @param int $expiry 密文有效期, 加密時候有效, 單位 秒,0 爲永久有效 8 * @return string 處理後的 原文或者 通過 base64_encode 處理後的密文 9 ************************* 10 * @example 11 * 12 * $a = authcode('abc', 'ENCODE', 'key'); 13 * $b = authcode($a, 'DECODE', 'key'); // $b(abc) 14 * 15 * $a = authcode('abc', 'ENCODE', 'key', 3600); 16 * $b = authcode('abc', 'DECODE', 'key'); // 在一個小時內,$b(abc),不然 $b 爲空 17 */ 18 function authcode($string, $operation = 'DECODE', $key = '', $expiry = 3600) { 19 20 // 隨機密鑰長度 取值 0-32; 21 // 加入隨機密鑰,能夠令密文無任何規律,即使是原文和密鑰徹底相同,加密結果也會每次不一樣,增大破解難度。 22 // 取值越大,密文變更規律越大,密文變化 = 16 的 $ckey_length 次方 23 // 當此值爲 0 時,則不產生隨機密鑰 24 $ckey_length = 4; 25 26 $key = md5($key ? $key : 'default_key'); // 這裏能夠填寫默認key值 27 $keya = md5(substr($key, 0, 16)); // 密匙a會參與加解密 [keya = md5 新key前16位] 28 $keyb = md5(substr($key, 16, 16)); // 密匙b會用來作數據完整性驗證 [keyb = md5 新key後16位] 29 // 密匙c用於變化生成的密文 30 // 加密:keyc = 當前時間毫秒作md5加密,截取末尾隨機祕鑰長度字符 31 // 解密:keyc = 截取傳入的字符串string末尾隨機祕鑰長度字符 32 $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : ''; 33 // 參與運算的密匙 34 $cryptkey = $keya.md5($keya.$keyc); 35 $key_length = strlen($cryptkey); 36 37 // 明文,前10位用來保存時間戳,解密時驗證數據有效性,10到26位用來保存$keyb(密匙b),解密時會經過這個密匙驗證數據完整性 38 // 若是是解碼的話,會從第$ckey_length位開始,由於密文前$ckey_length位保存 動態密匙,以保證解密正確 39 $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string; 40 $string_length = strlen($string); 41 $result = ''; 42 $box = range(0, 255); 43 44 $rndkey = array(); 45 // 產生密匙簿 46 for($i = 0; $i <= 255; $i++) { 47 $rndkey[$i] = ord($cryptkey[$i % $key_length]); 48 } 49 50 // 用固定的算法,打亂密匙簿,增長隨機性,好像很複雜,實際上對並不會增長密文的強度 51 for($j = $i = 0; $i < 256; $i++) { 52 $j = ($j + $box[$i] + $rndkey[$i]) % 256; 53 $tmp = $box[$i]; 54 $box[$i] = $box[$j]; 55 $box[$j] = $tmp; 56 } 57 58 // 核心加解密部分 59 for($a = $j = $i = 0; $i < $string_length; $i++) { 60 $a = ($a + 1) % 256; 61 $j = ($j + $box[$a]) % 256; 62 $tmp = $box[$a]; 63 $box[$a] = $box[$j]; 64 $box[$j] = $tmp; 65 // 從密匙簿得出密匙進行異或,再轉成字符 66 $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256])); 67 } 68 69 if($operation == 'DECODE') { 70 // substr($result, 0, 10) == 0 驗證數據有效性 71 // substr($result, 0, 10) - time() > 0 驗證數據有效性 72 // substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16) 驗證數據完整性 73 // 驗證數據有效性,請看未加密明文的格式 74 if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) { 75 return substr($result, 26); 76 } else { 77 return ''; 78 } 79 } else { 80 // 把動態密匙保存在密文裏,這也是爲何一樣的明文,生產不一樣密文後能解密的緣由 81 // 由於加密後的密文多是一些特殊字符,複製過程可能會丟失,因此用base64編碼 82 return $keyc.str_replace('=', '', base64_encode($result)); 83 } 84 85 }