Skip to content

Instantly share code, notes, and snippets.

@forthxu
Created November 9, 2017 03:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save forthxu/3e89ed2051f986a3cbe381093ca4da0c to your computer and use it in GitHub Desktop.
Save forthxu/3e89ed2051f986a3cbe381093ca4da0c to your computer and use it in GitHub Desktop.
可加密解密的base32
<?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