PHP: функция расшифровки шифра XOR не работает

В последнее время я занимаюсь исследованиями в области криптографии. Чтобы лучше понять все это, я пытался написать более продвинутую версию шифра XOR на PHP. Я заставил функцию шифрования работать нормально, но вывод функции расшифровки довольно странный и полностью отличается от введенного сообщения.

Идея алгоритма состоит в том, чтобы выполнить операцию XOR сначала для первого и последнего символа, затем для второго и предпоследнего символа и так далее. После этого он выполняет операцию XOR над первыми двумя символами и двумя последними символами, затем над третьим и четвертым символом, со вторым и третьим до последнего и так далее еще раз. Это продолжается с блоками из 3, 4, 5 и более символов.

Код, который у меня есть прямо сейчас:

<?php
function encrypt($message, $key) {
    $output_text = '';

    // Add zeros at the end until the length of the message corresponds with the length of
the key
    $message = str_pad($message,strlen($key),0);

    if((strlen($message) % 2)) {
        // The lenght of the message is odd, add a zero
        $message = $message . 0;
    }

    // Define the final length of the message
    $length = strlen($message);

    // Firstly, take 1 character, then 2, then 3, etc. until you reach half the length of the message
    for($characters=1; $characters<=($length/2); $characters++) {
        // Loop from i til half the length of the message
        for($i=0; $i<=(($length/2)-1); $i += $characters) {
            // Take the first and last character, the the first two and the last two, etc.

            // Stop when it crosses half the length
            if( ($i + $characters ) >= ( $length / 2 ) ) break;

            // firstly, the characters at the beginning
            $beginning = substr($message, $i, $characters);
            for($j=0; $j<$characters; $j++) {
                $position = ( $i + 1 ) + $j;
                $output_text .= chr(ord($beginning{$j}) ^ ord($key{$position}));
            }

            // Then those at the end
            $ending = substr($message, $length-(($i+1) * $characters), $characters);
            for($j=0; $j<$characters; $j++) {
                $position = ( $length - ( ( $i + 1 )* $characters) ) + $j;
                $output_text .= chr(ord($ending{$j}) ^ ord($key{$position}));
            }
        }
    }

    return $output_text;
}
function decrypt($message, $key) {
    $output_text = null;

    // Define the final length of the message
    $length = strlen($message);

    // Firstly, take 1 character, then 2, then 3, etc. until you reach half the length of the message
    for($characters=1; $characters<=($length/2); $characters++) {

        // Loop from i til half the length of the message
        for($i=0; $i<=(($length/2)-1); $i += $characters) {
            // Take the first and last character, the the first two and the last two, etc.

            // Stop when it crosses half the length
            if( ($i + $characters ) >= ( $length / 2 ) ) break;

            // firstly, the characters at the beginning
            $beginning = substr($message, $i, $characters);
            for($j=0; $j<$characters; $j++) {
                $position = ( $i + 1 ) + $j;
                $output_text .= chr(ord($key{$position}) ^ ord($beginning{$j}));
            }

            // The those at the end
            $ending = substr($message, $length-(($i+1) * $characters), $characters);
            for($j=0; $j<$characters; $j++) {
                $position = ( $length - ( ( $i + 1 )* $characters) ) + $j;
                $output_text .= chr(ord($key{$position}) ^ ord($ending{$j}));
            }
        }
    }

    return $output_text;
}

$message = 'sampletextjusttotrythisoutcreatedin2012';
$key = '123';
$output_text = encrypt($message, $key);
echo $output_text . '<br /><hr />';
echo decrypt($output_text, $key);

Заранее спасибо за попытку помочь мне!


person Jeroen    schedule 06.01.2012    source источник
comment
Я не уверен, как должен работать ваш алгоритм шифрования, но это не так. Он расширяет открытый текст размером 15 байт до зашифрованного текста размером 594 байта, включая большие фрагменты открытого текста.   -  person    schedule 06.01.2012
comment
Он должен работать так, как я объяснил в посте, и еще раз, это не для практического использования, просто для лучшего понимания;)   -  person Jeroen    schedule 06.01.2012
comment
Скажем так, я знаю, что шифрование вообще не работает, но если предположить, что это функция шифрования, то какой должна быть правильная функция дешифрования?   -  person Jeroen    schedule 06.01.2012
comment
XOR — это математический примитив, а не шифр — когда вы говорите «шифр XOR», я предполагаю, что вы имеете в виду шифр Виженера с XOR в качестве операции объединения. Вы, вероятно, не многому научитесь с помощью этой выдуманной конструкции, так как она не похожа ни на какой стандартный шифр или режим работы — вам лучше изучить самые основы того, как работают потоковые или блочные шифры, и написать ваш собственный демонстрационный шифр, основанный на этом.   -  person Nick Johnson    schedule 09.01.2012


Ответы (2)


Прямо сейчас самая сложная часть «расшифровки» строки — это выяснить, насколько длинным был ввод. Если мы возьмем это как дополнительный параметр, мы можем расшифровать его примерно так:

function decrypt($cipher, $messagelen, $key) {
    if($messagelen % 2) { $messagelen++; }
    $x = substr($cipher, -$messagelen + 2);
    $y = substr($x, 0, strlen($key) - 1) ^ substr($key, 1);
    $z = substr($x, strlen($key) - 1);
    return $y . $z; 
}

Это делается намного проще, потому что большая часть сообщения появляется в открытом виде в конце зашифрованного текста. Упс. Единственные символы в этом повторении, которые «зашифрованы», — это первые несколько символов, которые просто подвергаются XOR с ключом.

Два средних символа безвозвратно потеряны из-за ошибки шифрования. Примечания о том, как это исправить, находятся в моих комментариях ниже.

person Community    schedule 06.01.2012
comment
Большой! Интересно, однако, как вы к этому пришли, не могли бы вы объяснить это? Если вы также можете помочь мне исправить два недостающих символа в шифровании, я добавлю награду в 100 баллов :) - person Jeroen; 07.01.2012
comment
Чтобы исправить шифрование: измените >= в условном выражении Stop, когда оно пересекает половину длины, на >. Чтобы расшифровать результат, измените -$messagelen + 2 (в строке 3 моей функции) на просто $messagelen. - person ; 07.01.2012
comment
Спасибо, работает отлично! Что касается объяснения, я полностью понимаю, как работает ваш код, я просто хотел бы знать, как вы к нему пришли? - person Jeroen; 07.01.2012
comment
Методом проб и ошибок. Тот факт, что большая часть сообщения была доступна в открытом виде (в конце вывода encrypt), очень помог. - person ; 07.01.2012

Давайте начнем с чего-нибудь попроще: если у вас есть сообщение и ключ, выполните операцию XOR над сообщением с ключом, чтобы зашифровать его. XOR зашифрованного сообщения с ключом для его расшифровки.

$msg = "The rooster crows at midnight!";
$key = "secret key";

$cipher_text = simple_xor($msg, $key);
$plain_text  = simple_xor($cipher_text, $key);

echo "Original msg: $msg\n";
echo "Supplied key: $key\n";
echo "\n";
echo "Cipher Text: " . base64_encode($cipher_text) . "\n";
echo "  Decrypted: " . $plain_text . "\n";

function simple_xor($input, $key) {

    # Input must be of even length.
    if (strlen($input) % 2)
        $input .= '0';

    # Keys longer than the input will be truncated.
    if (strlen($key) > strlen($input))
        $key = substr($key, 0, strlen($input));

    # Keys shorter than the input will be padded.
    if (strlen($key) < strlen($input))
        $key = str_pad($key, strlen($input), '0', STR_PAD_RIGHT);

    # Now the key and input are the same length.
    # Zero is used for any trailing padding required.

    # Simple XOR'ing, each input byte with each key byte.
    $result = '';
    for ($i = 0; $i < strlen($input); $i++) {
        $result .= $input{$i} ^ $key{$i};
    }
    return $result;
}

Здесь вы можете увидеть внутреннюю ценность XOR. Учитывая Msg XOR Key = C, затем C XOR Key = Msg и C XOR Msg = Key.

Теперь давайте вернемся к вашему подходу — кажется, вы хотите смешать больше символов, чтобы получить более «сильный» зашифрованный результат. Прежде чем сделать это, найдите минутку, чтобы подумать о том, что создает надежность шифрования при использовании XOR таким образом. Во время этого процесса предположим, что у злоумышленника есть вышеуказанный код, но нет $msg или $key.

Злоумышленник будет знать длину вашего сообщения и ключа, потому что этот алгоритм всегда генерирует результат, равный количеству байтов сообщения и ключа.

Самым надежным ключом будет тот, в котором каждый байт отличается — таким образом, результат не будет содержать шаблонов. Например, если вы зашифруете текст на английском языке с помощью ключа, содержащего только один повторяющийся байт, я могу заметить, что зашифрованный текст содержит один повторяющийся байт несколько раз. Вероятно, это буква «е» в вашем обычном тексте, самая популярная гласная. Если бы ключ содержал совершенно случайные байты, то любая закономерность, обнаруженная в зашифрованном тексте, не помогла бы мне идентифицировать открытый текст.

Итак, является ли сильным сообщение «Ноги» и ключ «abcd»? Что ж, это определенно сильнее, чем использование ключа «0000», но могло бы быть и сильнее. Злоумышленник может предположить, что вы использовали простой ключ, содержащий только строчные буквы. Это означает, что для перебора этого ключа злоумышленнику нужно перепробовать 26^8 возможных вариантов. На современных компьютерах это можно сделать менее чем за секунду. Лучший ключ будет включать заглавные буквы, цифры, знаки препинания и другие символы. Еще лучший ключ будет включать непечатаемые символы, например: $key = chr(27) . chr(6) . 'q.';

Еще один интересный элемент, который следует учитывать при использовании этого алгоритма, заключается в том, что он требует, чтобы ключ был такой же длины, как и сообщение. Это означает, что для сильного шифрования большого количества текста (например, романа) требуется полностью случайный ключ, длина которого также равна длине романа. Большинство основных алгоритмов избегают этого требования, шифруя сообщение блоками. Существует множество различных способов реализации блочного кодирования, позвольте мне проиллюстрировать один из них, известный как цепочка блоков шифрования (CBC).

Простой CBC работает, беря первые несколько байтов открытого текста, выполняя операцию XOR с ключом, который генерирует первые несколько байтов зашифрованного текста. Следующие несколько байтов открытого текста шифруются с помощью операции XOR с первыми несколькими байтами зашифрованного текста И ключом. Этот процесс повторяется до тех пор, пока весь открытый текст не будет зашифрован. Это создает цепочку, в которой каждый блок зашифрованного текста был создан с использованием предыдущего блока и ключа. Чтобы расшифровать последний результат, вы должны XOR зашифрованного текста с предыдущим блоком зашифрованного текста, а затем снова с ключом.

Сильные алгоритмы включают в себя другие функции, обеспечивающие максимально возможную случайность зашифрованного текста, в том числе функции, позволяющие определить, было ли изменено зашифрованное сообщение. Хорошим местом, чтобы узнать больше о режимах блочного шифрования, является Википедия: http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation

На странице «Криптография» также содержится большой набор вводной информации о различных формах шифрования и процессе криптоанализа. http://en.wikipedia.org/wiki/Cryptography

person Tails    schedule 07.01.2012
comment
Большое спасибо за этот обширный ответ, вы действительно все мне очень хорошо объяснили! (хотя мне пришлось прочитать это несколько раз, прежде чем полностью понять это) - person Jeroen; 09.01.2012