扩散算法的一种PHP实现,可用于数字加密/整数加密/id加密。
扩散的最终效果是数字空间到数字空间的一种一对一映射,以两位数的数字空间为例,00~99这100个数各自扩散后的结果集仍旧为00~99的100个数。
扩散前的数字55,扩散后对应到哪一个数,由数本身、扩散过程及密码共同决定。
多少位数字扩散后仍旧为多少位,但不能少于两位。对于位数少的可以在前面补0后再扩散。
还原时,输入参数中的前缀0不能省略。
class Crypto
{
protected $numberMap = [7, 3, 5, 8, 4, 0, 2, 1, 9, 6];
/**
* 计算扩散/还原轮数
* @return int 明文或密文长度。
*/
protected function calculateRound($len)
{
$round = 0;
$x = $len - 1;
while ($x > 0) {
$round++;
$x = ($x >> 1);
}
return $round;
}
/**
* 生成数字加密/解密的S盒子。
* @return string S盒子。
*/
public function generateNumberMap()
{
$s = range(0, 9);
shuffle($s);
return "[" . implode(',', $s) . "]";
}
/**
* 设置数字加密/解密使用的S盒子。
* @param array $map S盒子。
* @return void
*/
public function setNumberMap($map)
{
$temp = $map;
if (!is_array($temp)) {
throw new \Exception('Parameter $map should be an array.');
}
sort($temp);
if ($temp != range(0, 9)) {
throw new \Exception('Parameter $map should be a permutation of 0 to 9.');
}
$this->numberMap = $map;
}
/**
* 扩展数字加密/解密的KEY
* @return string 要扩展的密钥。
* @return int 扩展后的长度。
*/
protected function extendNumKey($key, $len)
{
//通过多次哈希计算,然后利用进制转换,从而得到密码相关的且足够长的数字密码。
$extKey = '';
$i = 0;
do {
$aHex = str_split(md5($key . $i++), 8);
$aNum = array_map(function ($item) {
return substr(base_convert($item, 16, 10), 1);
}, $aHex);
$extKey .= join('', $aNum);
} while (strlen($extKey) < $len);
return str_split(substr($extKey, 0, $len));
}
/**
* 数字加密。
* @param string|int $numStr 要加密的数字。
* @param string $key 密码,支持任意字符串。
* @param int $fill 填充长度,填充0到要加密的数字前,使数字长度不小于填充长度。
* @return string 加密后的数字字符串。
*/
public function numberEncrypt($numStr, $key, $fill = 0)
{
$numStr = (string) $numStr;
$fill = (int) $fill;
if ($fill > 0 && strlen($numStr) < $fill) {
$numStr = sprintf("%0{$fill}s", $numStr);
}
if (!preg_match("/^\d{2,}$/", $numStr)) {
throw new \Exception('Parameter $numStr must be a two or more Numbers.');
}
$num = str_split($numStr);
$numLen = count($num);
//扩散轮数
$round = $this->calculateRound($numLen);
//每次扩散使用不同密码,所以需要扩展密码。
$extLen = $numLen * $round;
$extKey = $this->extendNumKey($key, $extLen);
//扩散
$z = 0;
for ($i = 0; $i < $round; $i++) {
for ($j = 0; $j < $numLen; $j++) {
$dist = ($j + (1 << $i)) % $numLen;
$num[$dist] = $this->numberMap[($num[$j] + $num[$dist] + $extKey[$z++]) % 10];
}
}
return join('', $num);
}
/**
* 数字解密。
* @param string|int $numStr 要解密的数字。
* @param string $key 密码,支持任意字符串。
* @param int $fill 填充长度,填充0到要解密的数字前,使数字长度不小于填充长度。
* @return string 解密后的数字字符串。
*/
public function numberDecrypt($numStr, $key, $fill = 0)
{
$numStr = (string) $numStr;
$fill = (int) $fill;
if ($fill > 0 && strlen($numStr) < $fill) {
$numStr = sprintf("%0{$fill}s", $numStr);
}
if (!preg_match("/^\d{2,}$/", $numStr)) {
throw new \Exception('Parameter $numStr must be a two or more Numbers.');
}
$num = str_split($numStr);
$numLen = count($num);
//还原轮数
$round = $this->calculateRound($numLen);
//扩展密码
$extLen = $numLen * $round;
$extKey = $this->extendNumKey($key, $extLen);
//还原
$flippedMap = array_flip($this->numberMap);
$z = $extLen;
for ($i = $round - 1; $i >= 0; $i--) {
for ($j = $numLen - 1; $j >= 0; $j--) {
$dist = ($j + (1 << $i)) % $numLen;
$num[$dist] = (20 + $flippedMap[$num[$dist]] - $num[$j] - $extKey[--$z]) % 10;
}
}
return join("", $num);
}
}
此方法已发布为Composer包:
composer require wpfly/crypto
扩散算法原理参看:
[原创] 强大的世界级加密算法:扩散加密算法-密码应用-看雪论坛-安全社区|安全招聘|bbs.pediy.com
您的【点赞】与【收藏】是博主最大的创作动力!