无法在替换密码中解密我的加密字符串


Unable to decrypt my encrypted string in a substitution cipher

我正在开发自己的加密和解密算法。我的加密功能工作正常,但解密功能工作不正常。以下是我的功能:

<?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个字符。