我正在开发自己的加密和解密算法。我的加密功能工作正常,但解密功能工作不正常。以下是我的功能:
<?php
function encrypt($os,$mode=64,$pattern="tyv9xXa2iUEMhZLD6YlF4BOjg8AdJz0nVHKPRTpb5smfQ1WwroIkqcN3eSG7Cu"){
$ns="";
for($i=0;$i<strlen($os);$i++){
$ns.=$pattern[(strpos($pattern,$os[$i])+$mode)%strlen($pattern)];
}
return $ns;
}
function decrypt($os,$mode=64,$pattern="tyv9xXa2iUEMhZLD6YlF4BOjg8AdJz0nVHKPRTpb5smfQ1WwroIkqcN3eSG7Cu"){
$ns="";
for($i=0;$i<strlen($os);$i++){
$ns.=$pattern[abs(strpos($pattern,$os[$i])-$mode)%strlen($pattern)];
}
return $ns;
}
echo decrypt(encrypt("abcde"));
?>
我的预期输出是:abcde
但返回的输出是:ejUPa
加密是这样工作的:
$new_char_index = ($char_index + $shift) % $alphabet_length;
其中模CCD_ 3处理环绕,使得新索引仍然在字母表范围内。这对正数有效,但对负数无效。以下是一些例子:
echo -3 % 7; // -3
echo -11 % 7; // -4
这就是为什么简单地将+
更改为-
不起作用:
$new_char_index = ($char_index - $shift) % $alphabet_length;
这会导致出现负数。在PHP中不能访问负数数组,但在Python中可以这样做。
简单的解决方法是确保生成的索引始终是正数。你已经在abs()
中尝试过了,但问题是这并不能正确地从字母表的另一侧换行,而只是删除了错误的符号。
一个简单的解决方案是在模运算之前添加字母表长度,以获得正数:
$new_char_index = ($char_index - $shift + $alphabet_length) % $alphabet_length;
这是有效的,因为$alphabet_length % $alphabet_length == 0
。它按字母表的正确位置换行。
现在你只需要确保$shift
已经在字母表范围内:
$shift = $shift % $alphabet_length;
最后一个改进是:您可以使用相同的函数进行加密和解密,因为$enc_shift == -$dec_shift
和最后一个公式应该为这两者提供工作。
这不是加密。这是Caeser密码的变体。简单地说,你应该永远不要实现你自己的加密(除非你确切地知道你在做什么…)。这只会造成混淆。
至于代码本身,我怀疑是操作顺序问题。简单地用-
替换+
不会逆转encrypt()
函数中的运算符优先级。php文档页面的注释中提供了一个方便的通用字符串旋转函数。
如果你想要加密,有很多关于固体加密的好文章;这是我个人认为的一个好的起点。
这里有一个适用于每个$mode和$pattern大小的解决方案。您必须注意,您只能对$pattern中包含的字符进行"加密"。
<?php
function encrypt($os,$mode=64,$pattern=" tyv9xXa2iUEMhZLD6YlF4BOjg8AdJz0nVHKPRTpb5smfQ1WwroIkqcN3eSG7Cu"){
$patternLength = strlen($pattern);
if($mode < 0) {
$mode = ($patternLength - $mode) % $patternLength;
}
if($mode >= $patternLength) {
$mode %= $patternLength;
}
$ns="";
for($i=0;$i<strlen($os);$i++){
$ns.=$pattern[(strpos($pattern,$os[$i])+$mode)%strlen($pattern)];
}
return $ns;
}
function decrypt($os,$mode=64,$pattern=" tyv9xXa2iUEMhZLD6YlF4BOjg8AdJz0nVHKPRTpb5smfQ1WwroIkqcN3eSG7Cu"){
$patternLength = strlen($pattern);
if($mode < 0) {
$mode = ($patternLength - $mode) % $patternLength;
}
if($mode >= $patternLength) {
$mode %= $patternLength;
}
$ns="";
for($i=0;$i<strlen($os);$i++){
$pos = strpos($pattern,$os[$i]);
if($pos >= $mode ) {
$ns .= $pattern[$pos - $mode];
} else {
// $pos - $mode is negative so we need + sign
$ns .= $pattern[$patternLength + ($pos - $mode)];
}
}
return $ns;
}
为了测试这个,你可以做一些类似的事情:
$failed = false;
for($mode = -128; $mode <= 128; $mode++) {
// include all possible chars in the test to see if encryption and
// decryption works for all.
$allChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ";
if(decrypt(encrypt($allChars, $mode), $mode) != $allChars) {
echo "mode ".$mode." failed<br>";
$failed = true;
};
}
if(!$failed) {
echo "success";
}
修复它:
$ns.=$pattern[abs(strpos($pattern,$os[$i]))-$mode%strlen($pattern)];
在您的解密^^中。只是放置括号的问题。
完整固定代码:
function encrypt($os,$mode=64,$pattern="tyv9xXa2iUEMhZLD6YlF4BOjg8AdJz0nVHKPRTpb5smfQ1WwroIkqcN3eSG7Cu"){
$ns="";
for($i=0;$i<strlen($os);$i++){
$ns.=$pattern[(strpos($pattern,$os[$i])+$mode)%strlen($pattern)];
}
return $ns;
}
function decrypt($os,$mode=64,$pattern="tyv9xXa2iUEMhZLD6YlF4BOjg8AdJz0nVHKPRTpb5smfQ1WwroIkqcN3eSG7Cu"){
$ns="";
for($i=0;$i<strlen($os);$i++){
$ns.=$pattern[abs(strpos($pattern,$os[$i]))-$mode%strlen($pattern)];
}
return $ns;
}
echo decrypt(encrypt("abcde"));
希望你能自己理解其中的区别。
现在要解决空间问题:
$pattern=" tyv9xXa2iUEMhZLD6YlF4BOjg8AdJz0nVHKPRTpb5smfQ1WwroIkqcN3eSG7Cu"
注意字符串开头的空格。
由于评论而增加的注释。。。
如果您希望将$mode更改为62,则需要适当地缩短$pattern。例如
function encrypt($os,$mode=62,$pattern=" tyv9xXa2iUEMhZLD6YlF4BOjg8AdJz0nVHKPRTpb5smfQ1WwroIkqcN3eSG7"){
$ns="";
for($i=0;$i<strlen($os);$i++){
$ns.=$pattern[(strpos($pattern,$os[$i])+$mode)%strlen($pattern)];
}
return $ns;
}
function decrypt($os,$mode=62,$pattern=" tyv9xXa2iUEMhZLD6YlF4BOjg8AdJz0nVHKPRTpb5smfQ1WwroIkqcN3eSG7"){
$ns="";
for($i=0;$i<strlen($os);$i++){
$ns.=$pattern[abs(strpos($pattern,$os[$i]))-$mode%strlen($pattern)];
}
return $ns;
}
echo decrypt(encrypt("abcde"));
工作正常,注意$pattern现在缺少最后2个字符。