寻求将自增Integer ID映射为固定长度非序混淆整数的PHP方案
解决自增ID可逆混淆为7位无顺序整数的PHP实现
首先得说,你之前用的「乘37+XOR」方案有顺序性是正常的——乘法是线性操作,哪怕加了XOR,相邻ID的结果变化还是有规律(比如ID+1后结果的低位波动很容易被察觉)。要实现真正看起来无规律的可逆转换,咱们可以用简化版Feistel密码结构,这玩意儿天生可逆,而且不需要数据库映射,纯算法就能搞定,刚好适合你的场景(1-70000的范围,转7位整数完全够)。
核心思路
Feistel网络通过多轮的「拆分-混淆-交换」操作打乱原数据,因为每一轮的操作都是可逆的,所以解密只需要反向执行步骤就行。咱们针对70000的范围做简化,不用太复杂的轮数,2-3轮就足够打乱顺序了,同时保证结果是7位整数。
PHP实现代码
<?php // 自定义的轮函数,用来增加非线性混淆 function feistelRound($num, $key) { // 用乘法、加法、XOR组合,避免线性规律 return (($num * 123) + 456) ^ $key; } // 加密:自增ID转7位无顺序整数 function encryptId($id) { if ($id < 1 || $id > 70000) { throw new InvalidArgumentException("ID必须在1-70000之间"); } // 把ID拆分成高低两部分(70000的二进制是17位,拆成8位和9位) $left = $id >> 8; $right = $id & 0xFF; // 两轮混淆,用不同的密钥增强随机性 $key1 = 98765; $key2 = 13579; // 第一轮 $temp = $right; $right = $left ^ feistelRound($right, $key1); $left = $temp; // 第二轮 $temp = $right; $right = $left ^ feistelRound($right, $key2); $left = $temp; // 合并高低位,再加上基准数1000000,确保结果是7位整数 $encrypted = ($left << 8) | $right; return $encrypted + 1000000; } // 解密:7位整数转回原ID function decryptId($encryptedNum) { if ($encryptedNum < 1000000 || $encryptedNum > 9999999) { throw new InvalidArgumentException("输入必须是7位整数"); } // 先减去基准数,还原原始混淆值 $num = $encryptedNum - 1000000; // 拆分高低位,和加密时的拆分方式一致 $left = $num >> 8; $right = $num & 0xFF; $key1 = 98765; $key2 = 13579; // 反向执行第二轮(解密是加密的逆过程,轮数倒过来) $temp = $left; $left = $right ^ feistelRound($left, $key2); $right = $temp; // 反向执行第一轮 $temp = $left; $left = $right ^ feistelRound($left, $key1); $right = $temp; // 合并得到原ID return ($left << 8) | $right; } // 测试示例 $testId = 1; $encrypted = encryptId($testId); echo "ID $testId 加密后: $encrypted\n"; echo "加密值 $encrypted 解密后: " . decryptId($encrypted) . "\n"; $testId2 = 2; $encrypted2 = encryptId($testId2); echo "ID $testId2 加密后: $encrypted2\n"; echo "加密值 $encrypted2 解密后: " . decryptId($encrypted2) . "\n"; ?>
关键细节说明
- 轮函数设计:
feistelRound里用了乘法、加法、XOR的组合,避免线性操作带来的顺序性,你也可以自己调整里面的常数(比如123、456),只要保证可逆就行(这里的操作都是可逆的:加法逆是减法,乘法逆是除法(因为123和256互质,在8位范围内可逆),XOR逆是自身)。 - 基准数:加1000000是为了确保结果一定是7位整数,避免出现小于6位的情况,解密时再减去就行。
- 密钥:你可以自定义
key1和key2,密钥不同,混淆后的结果也不同,增强自定义性。
为什么比之前的方案好?
这个方案通过多轮的非线性混淆,相邻ID的加密结果会完全无规律,比如ID=1和ID=2的加密值不会有明显的数值关联,完美解决你之前遇到的顺序性问题。而且全程纯算法,不需要数据库存储映射关系,适合分散的输入节点使用。
内容的提问来源于stack exchange,提问作者BSDG
相关产品推荐
相关产品推荐

