PHP: Функцията за декриптиране на шифроване XOR не работи

Напоследък правя някои изследвания в областта на криптографията. За да разбера по-добре всичко това, се опитвах да напиша по-усъвършенствана версия на XOR шифъра в PHP. Накарах функцията за криптиране да работи добре, но изходът на функцията за дешифриране е доста странен и напълно различен от въведеното съобщение.

Идеята на алгоритъма е да се изпълни операция XOR първо върху първия и последния знак, след това върху втория и предпоследния знак и т.н. След това изпълнява операция XOR върху първите два знака и последните два знака, след това третия и четвъртия знак и 2-рия и 3-тия до последния и така нататък отново. Това се случва с блокове от 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 шифър, предполагам, че имате предвид шифъра на Vigenere с 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.

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

Най-силният ключ ще бъде този, при който всеки байт е различен - по този начин резултатът няма да съдържа модели. Например, ако шифровате английски текст с ключ, съдържащ само един повторен байт, може да забележа, че шифърът съдържа един байт, повторен многократно. Това вероятно е буквата "e" във вашия обикновен текст, най-популярната гласна. Ако ключът съдържа напълно произволни байтове, тогава всеки модел, забелязан в шифрования текст, няма да ми помогне да идентифицирам обикновения текст.

И така, силно ли е съобщението „Feet“ и ключът „abcd“? Е, със сигурност е по-силен от използването на ключ "0000", но може да бъде и по-силен. Нападателят може да предположи, че сте използвали прост ключ, съдържащ само малки букви. Това означава, че за да форсирате този ключ, нападателят трябва да опита 26 ^ 8 възможни опции. Това може да стане за по-малко от секунда на съвременните компютри. По-добрият ключ би включвал главни букви, цифри, препинателни знаци и други знаци. Още по-добър ключ би включвал и непечатаеми знаци, например: $key = chr(27) . chr(6) . 'q.';

Друг интересен елемент, който трябва да се вземе предвид при този алгоритъм е, че той изисква ключът да бъде с еднаква дължина като съобщението. Това означава, че силното криптиране на голямо количество текст (като роман) изисква ключ, който е напълно случаен и също толкова дълъг, колкото романа. Повечето основни алгоритми избягват това изискване, като криптират съобщението на блокове. Има много различни начини за прилагане на блоково кодиране, позволете ми да илюстрирам един, известен като cipher-block-chaining (CBC).

Simple CBC работи, като взема първите няколко байта от обикновения текст, използвайки го XOR с ключа, който генерира първите няколко байта от шифрования текст. Следващите няколко байта от обикновения текст се криптират чрез XOR'ing с първите няколко байта от шифрования текст И ключа. Този процес се повтаря, докато целият обикновен текст бъде шифрован. Това създава верига, където всеки блок в шифрования текст е създаден с помощта на предишния блок и ключ. За да дешифрирате последния резултат, трябва да извършите 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