Created
November 9, 2017 03:36
-
-
Save forthxu/3e89ed2051f986a3cbe381093ca4da0c to your computer and use it in GitHub Desktop.
可加密解密的base32
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Common; | |
/** | |
* 可加密解密的base32 | |
* | |
* @author ForthXu | |
*/ | |
class base32 { | |
/** | |
* 32个字符字典 | |
* @var array | |
*/ | |
public $base64_config = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '2', '3', '4', '5', '6', '7', '8', '9']; //, 'l', 'o', '1', '0'//去掉容易混淆的字符 | |
/** | |
* 打乱字符字典 和 加密密钥 | |
* @var string | |
*/ | |
protected $key = ""; | |
public function __construct($key = "") { | |
if (!empty($key)) { | |
$rand = 0; | |
foreach (str_split($key) as $s) { | |
$rand *= ord($s); | |
} | |
srand($rand); | |
shuffle($this->base64_config); | |
$this->key = $key; | |
} | |
} | |
/** | |
* base32解密 | |
* @param string $str | |
* @return string | |
*/ | |
public function decode($str) { | |
$binaryString = ""; | |
foreach (str_split($str) as $s) { | |
$char = array_search($s, $this->base64_config); | |
$binaryString .= sprintf("%05b", $char); | |
} | |
$binaryArr = explode(" ", rtrim(chunk_split($binaryString, 8, " "))); | |
//冗余去除 | |
$binaryArrLen = count($binaryArr); | |
if (strlen($binaryArr[$binaryArrLen - 1]) != 8) { | |
unset($binaryArr[$binaryArrLen - 1]); | |
} | |
$result = ""; | |
foreach ($binaryArr as $bin) { | |
$result .= chr(base_convert($bin, 2, 10)); | |
} | |
return $result; | |
} | |
/** | |
* base32加密 | |
* @param string $str | |
* @return string | |
*/ | |
public function encode($str) { | |
$binaryString = ""; | |
foreach (str_split($str) as $s) { | |
$binaryString .= sprintf('%08b', ord($s)); | |
} | |
$binaryArr = explode(" ", rtrim(chunk_split($binaryString, 5, " "))); | |
//冗余补全 | |
$binaryArrLen = count($binaryArr); | |
if (strlen($binaryArr[$binaryArrLen - 1]) != 5) { | |
$binaryArr[$binaryArrLen - 1] = str_pad($binaryArr[$binaryArrLen - 1], 5, '0', STR_PAD_RIGHT); | |
} | |
$result = ""; | |
foreach ($binaryArr as $bin) { | |
$result .= $this->base64_config[base_convert($bin, 2, 10)]; | |
} | |
return $result; | |
} | |
/** | |
* 纯粹base32序列号带加密解密的方法是不做数据验证,这里增加混淆、有效时间、验证结果的处理 | |
* 可逆加密,结果使用base32保证无特殊字符 | |
* @param string $string 加密的内容 | |
* @param string $operation DECODE/ENCODE | |
* @param int $expiry 参数在加密解密过程作用不同,加密结果的有效时间,解密对象是否需要验证时间 | |
* @param int $salt_len 加密盐长度,如果非0则每次加密后的结果都不一样,但解密结果是一样的 | |
* @param int $confirmation 用来校验的长度,最多32位,0不做校验,越长校验越完整 | |
* @return string 过期或者解密出错返回空字符串 | |
*/ | |
public function authCode($string, $operation = 'DECODE', $expiry = 0, $salt_len = 0, $confirmation = 0) { | |
$ckey_length = $salt_len; | |
//输入的key | |
//一半用来生成密钥用于混淆 | |
$keya = md5(substr($this->key, 0, 16)); | |
//一半用来生成hash用于验证 | |
$keyb = md5(substr($this->key, 16, 16)); | |
//获取或者生成salt用于混淆 | |
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : ''; | |
//生产加了salt的混淆密钥 | |
$cryptkey = $keya . md5($keya . $keyc); | |
$key_length = strlen($cryptkey); | |
//加密的内容:salt+使用salt和keya产生的密钥做移位替换(十位的时间戳 + $confirmation位验证keyb验证hash + 字符串) | |
$string = $operation == 'DECODE' ? $this->decode(substr($string, $ckey_length)) : ($expiry > 0 ? sprintf('%010d', $expiry + time()) : "") . ($confirmation > 0 ? substr(md5($string . $keyb), 0, $confirmation) : "") . $string; | |
$string_length = strlen($string); | |
//移位替换 | |
$result = ''; | |
//产生一个异或掩码库 | |
$box = range(0, 255); | |
//根据密钥产生用一个混淆库 | |
$rndkey = array(); | |
for ($i = 0; $i <= 255; $i++) { | |
$rndkey[$i] = ord($cryptkey[$i % $key_length]); | |
} | |
//混淆掩码库,i跟往前j个做交换处理 | |
for ($j = $i = 0; $i < 256; $i++) { | |
$j = ($j + $box[$i] + $rndkey[$i]) % 256; | |
$tmp = $box[$i]; | |
$box[$i] = $box[$j]; | |
$box[$j] = $tmp; | |
} | |
//使用掩码做异或操作 | |
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; | |
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256])); | |
} | |
if ($operation == 'DECODE') { | |
if ( | |
($expiry == 0 || ($expiry > 0 && substr($result, 0, 10) - time() >= 0)) && | |
($confirmation < 1 || ($expiry == 0 ? substr($result, 0, $confirmation) == substr(md5(substr($result, $confirmation) . $keyb), 0, $confirmation) : substr($result, 10, $confirmation) == substr(md5(substr($result, 10 + $confirmation) . $keyb), 0, $confirmation))) | |
) { | |
return $expiry == 0 ? ($confirmation > 0 ? substr($result, $confirmation) : substr($result, 0)) : ($confirmation > 0 ? substr($result, 10 + $confirmation) : substr($result, 10)); | |
} else { | |
return ''; | |
} | |
} else { | |
return $keyc . str_replace('=', '', $this->encode($result)); | |
} | |
} | |
} | |
/* | |
$baseBs = new \Common\base32("1234"); | |
for($i=4294967290;$i<4294967300;$i++){ | |
$encode = $baseBs->encode($i); | |
var_dump($encode); | |
$decode = $baseBs->decode($encode); | |
var_dump($decode); | |
$encode = $baseBs->authCode($i, "ENCODE",0,0,10); | |
var_dump($encode); | |
$decode = $baseBs->authCode($encode, "DECODE",0,0,10); | |
var_dump($decode); | |
echo "\n"; | |
} | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment