Шифрование алгоритмом XXTEA на PHP

Сначала всех читателей и посетителей нашего блога хотелось бы поздравить с наступившими новогодними праздниками и еще раз пожелать здоровья, удачи и успехов во всех делах!

Сегодня я начну рассматривать тему шифрования, которая ни разу еще не была рассмотрена в нашем блоге. Но начну я не с расширений PECL и встроенных возможностей в PHP, а с простого алгоритма шифрования под названием TEA, а точнее предоставлю совсем небольшую библиотеку для симметричного шифрования для модификации этого алгоритма под названием XXTEA.

Кстати, о симметричности. Для тех, кто не знает: шифрование бывает симметричным и асимметричным. Не будем пока забивать голову различиями. О них мы поговорим в одной из следующих статей. Скажу лишь пока только, что асимметричное шифрование предназначено для обмена информацией между источником и приемником и требует для своей работы два ключа – открытый и закрытый. Асимметричные шифры обычно работают медленнее. Симметричное же шифрование требует для шифрования один единственный ключ и в основном используется для шифрования файлов и информации, хранимой на различных источниках.

Алгоритм TEA

По определению википедии, Tiny Encryption Algorithm (TEA) — блочный алгоритм шифрования типа «Сеть Фейстеля», представленный в году Дэвидом Уилером (David Wheeler) и Роджером Нидхэмом (Roger Needham).

У этого алгоритма в чистом виде были найдены уязвимости, поэтому у него существуют две усовершенствованные модификации: XTEA и XXTEA (закрывает недостатки XTEA). XXTEA является на момент написания статьи последней модификацией, поэтому мы будем рассматривать именно ее.

Вообще, про шифрование можно сказать очень многое – например, о длинах ключей (кстати, длина ключа в XXTEA = 128 бит) или режимах шифрования. Но все это в будущих статьях :)

Реализация XXTEA

Реализацию алгоритма XXTEA можно найти для множества языков программирования на просторах Интернета, но для PHP чистую реализацию (без использования PECL) я нашел только у китайцев :) – на страничке [ссылка]

Спасибо китайским ребятам! :)

Вот небольшой PHP-код, позволяющий шифровать данные алгоритмом XXTEA:

<?php
/* XXTEA encryption arithmetic library.
*
* Copyright (C) Ma Bingyao 
* Version:      1.5
* LastModified: Dec 5
* This library is free.  You can redistribute it and/or modify it.
*/
function long2str($v, $w) {
    $len = count($v);
    $n = ($len - 1) << 2;
    if ($w) {
        $m = $v[$len - 1];
        if (($m < $n - 3) || ($m > $n)) return false;
        $n = $m;
    }
    $s = array();
    for ($i = 0; $i < $len; $i++) {
        $s[$i] = pack("V", $v[$i]);
    }
    if ($w) {
        return substr(join('', $s), 0, $n);
    } else {
        return join('', $s);
    }
}
function str2long($s, $w) {
    $v = unpack("V*", $s. str_repeat("\0", (4 - strlen($s) % 4) & 3));
    $v = array_values($v);
    if ($w) {
        $v[count($v)] = strlen($s);
    }
    return $v;
}
function int32($n) {
    while ($n >= 2147483648) $n -= 4294967296;
    while ($n <= -2147483649) $n += 4294967296;
    return (int)$n;
}
function xxtea_encrypt($str, $key) {
    if ($str == "") {
        return "";
    }
    $v = str2long($str, true);
    $k = str2long($key, false);
    if (count($k) < 4) {
        for ($i = count($k); $i < 4; $i++) {
            $k[$i] = 0;
        }
    }
    $n = count($v) - 1;
    $z = $v[$n];
    $y = $v[0];
    $delta = 0x9E3779B9;
    $q = floor(6 + 52 / ($n + 1));
    $sum = 0;
    while (0 < $q--) {
        $sum = int32($sum + $delta);
        $e = $sum >> 2 & 3;
        for ($p = 0; $p < $n; $p++) {
            $y = $v[$p + 1];
            $mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
            $z = $v[$p] = int32($v[$p] + $mx);
        }
        $y = $v[0];
        $mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
        $z = $v[$n] = int32($v[$n] + $mx);
    }
    return long2str($v, false);
}
function xxtea_decrypt($str, $key) {
    if ($str == "") {
        return "";
    }
    $v = str2long($str, false);
    $k = str2long($key, false);
    if (count($k) < 4) {
        for ($i = count($k); $i < 4; $i++) {
            $k[$i] = 0;
        }
    }
    $n = count($v) - 1;
    $z = $v[$n];
    $y = $v[0];
    $delta = 0x9E3779B9;
    $q = floor(6 + 52 / ($n + 1));
    $sum = int32($q * $delta);
    while ($sum != 0) {
        $e = $sum >> 2 & 3;
        for ($p = $n; $p > 0; $p--) {
            $z = $v[$p - 1];
            $mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
            $y = $v[$p] = int32($v[$p] - $mx);
        }
        $z = $v[$n];
        $mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
        $y = $v[0] = int32($v[0] - $mx);
        $sum = int32($sum - $delta);
    }
    return long2str($v, true);
}
?>

Пример шифрования/дешифрования

В представленном коде мы видим, что у нас есть в распоряжении две функции: xxtea_encrypt и xxtea_decrypt. Остальные функции носят вспомогательный характер. Конечно, можно было бы эту реализацию вынести в отдельный класс, но оставим все как есть.

Пробуем зашифровать и сразу расшифровать текстовую строку:

require_once 'xxtea.inc.php';
$cipher = xxtea_encrypt('My test string', 'My test password');
echo xxtea_decrypt($cipher, 'My test password');

При выводе получаем: My test string

Стоит нам изменить ключ при расшифровке, при выводе мы не получим ничего, т.к. ключ задан неверно. Длина ключа может быть не более 128 бит, т.е. 16 байт. Поэтому если мы зададим в качестве второго аргумента функции xxtea_encrypt/xxtea_decrypt значение длиной больше 16 байт, она примет во внимание только первые 16 байт. Поэтому здесь нужно быть внимательным.

Таким же образом с легкостью можно шифровать содержимое файла.

Секретный ключ всегда следует хранить отдельно от шифра, иначе весь смысл шифрования конечно теряется. На то он и секретный, что его должен знать только тот, кто зашифровал, чтобы впоследствии обратить шифр.

В следующих статьях мы также затронем тему шифрования - не менее интересные возможности языка PHP и его расширений.

Скачать пример к статье: xxtea.zip (1,21 Кб)





Читайте также:



24 Ответов на “Шифрование алгоритмом XXTEA на PHP”

  1. adw0rd

    Спасибо, интересно почитать было, только чем вас TEA именно впечатлил?

    > Стоит нам изменить ключ при расшифровке, при
    > выводе мы не получим ничего, т.к. ключ задан неверно

    хм… ничего вообще или мусор?

  2. novice

    Про такие алгоритмы, как RC2, RC4 и т.д. все давно наслышаны. А TEA - малоизвестен, поэтому про него написал. Да и легкий в реализации. Насчет расшифровки: у меня при задании неправильного ключа не выводилось ничего. Видимо одна из вспомогательных функций работает так, что возвращает false, если что-то не срастается при расшифровке.

  3. Да, к сожалению на php эффективную реализацию сделать достаточно трудно. На C/Delphi есть указатели и поэтому не надо постоянно возиться с алгоритмами преобразования типов. А тут всё по другому…
    Кстати,
    > Асимметричные шифры обычно работают медленнее.
    Тут бы я добавил про гибридные алгоритмы пару слов. :)
    Но всё очень круто и исходничек пригодиться обязательно. :)
    Спасибо!

  4. У PEAR тоже есть свой вариант подобного шифрования (в виде класса)…

    Интересно мне, возможно ли зашифрованную таким методом строку отправлять, к примеру в cookie пользователя? Как браузер отнесётся к этому? Получаются, ведь бинарные данные. И, другой вопрос, если из куков потом забрать такую строку, будет ли она такой же, ведь кодировки сайта и пользователя могут быть разными?

  5. novice

    Попробуйте :) Если не получится расшифровать из-за искажения шифра - посоветую перед сохранением в cookie кодировать шифр в base64, а при чтении из cookie - раскодировать.

  6. Игорь

    Спасибо, надо поэкспериментировать!

  7. rob72

    Хочу предложить еще один простой способ шифрования.
    В основу заложен давно известный алгоритм: Если выполнить XOR данных
    и ключа, то при повторном выполнении XOR шифрованной строки с тем же
    (и только!) ключом будет восстановлена исходная строка.
    К преимуществам можно отнести простоту реализации
    (за счет того, что основная доля вычислений осуществляется встроенной
    функцией md5), а также то, что для шифрования и дешифрования
    используется одна и та же функция.
    Шифрованная строка получается бинарной, так что при необходимости
    нужно использовать base64

    $klen){$key=str_pad($key,$slen,$key,STR_PAD_RIGHT);}
    if($slen

  8. Boris

    Я тоже использую XOR, и всегда хотел спросить: насколько вообще это надежный способ шифрования?

  9. novice

    Boris, если бы XOR был надежен, люди не придумывали бы столько алгоритмов шифрования, существующих на сегодняшний день. Хотя может быть все зависит от длины ключа и я могу ошибаться.

  10. Гость

    А как таким алгаритмом закодировать файл скажем в 100 мегобайт (дамб базы в текстовом файле), если нельзя увиличить размер оперативки выделяемой пхп (по дефалту 32м)?

  11. novice

    В таком случае можно шифровать файл поблочно. Например, блоками размером в 1 Мб. Существуют разные режимы шифрования. Поблочный, если не ошибаюсь, называется CBC.

  12. Гость

    novice, а по подробнее где можно найти? желательно с примерами

  13. novice
  14. Rob72

    Сомневаюсь, что файл 100м вообще можно зашифровать на php,
    30-секундный лимит не позволит, а менять его на хостинге вряд ли разрешат. Тем более, что приведенный метод довольно медленный, ладно бы через библиотеки типа mcrypt

  15. venom280

    Не знаю прочитает ли мой коммент кто-нибудь, но все равно напишу.
    Вся проблема XOR в том, что если сделать XOR к двум зашифрованным строчкам, что мы получим?
    Правильно! Мы получим ключ.
    Достаточно перехватить два пакета, письма, cookie и у нас будет ключ.

  16. Сергей

    Если для шифрования использовать “My test password”, то для дешифрования подходит любой, который начинается с этой фразы. к примеру идеально подходят “My test passworddddd”, “My test passwordasdfk” и т.д. Абалдеть какая защита. Впрочем, чему удивляться, у китайцев мало надежных вещей. Ищите люди в японии :-)

  17. Serj

    Сергей, вы внимательно читали текст статьи? Судя по всему невнимательно. Автор ясно и четко написал в конце статьи: “Длина ключа может быть не более 128 бит, т.е. 16 байт. Поэтому если мы зададим в качестве второго аргумента функции xxtea_encrypt/xxtea_decrypt значение длиной больше 16 байт, она примет во внимание только первые 16 байт” Длинна пароля “My test password” как раз и составляет 16 байт (пробелы тоже учитываются, один символ кодируется одним байтом, байт равен восьми битам), поэтому те буквы которые вы добавляете и меняете уже не играют никакой роли. Ключ длинной в 16 байт (128 бит) достаточно надежен, если кому то нужен ключ большей длинны можно использовать другой алгоритм. Лично я выражаю автору благодарность за статью, и готовый код который пригодится.

  18. Алексей

    Большое спасибо автору!

  19. Вася

    Один большой минус! Очень долго работает.

  20. […] Шифрование алгоритмом XXTEA на PHP […]

  21. Давно не заходила сюда, проект живет и розвивается … Отдельное спасибо автору этого проекта, продолжайте, вы нам нужны :-)
    Есть проблема. Хочу скрыть информацию которая передается через url Например index.php? Go = m_resave & id = 91
    Думаю это можно реализовать с помощью xxtea и base64
    У кого какие идеи?
    require_once ‘xxtea.inc.php';
    $n = “Я самая красивая”;
    $cipher = xxtea_encrypt($n, ‘1234567890123456’);
    $cod = base64_encode($cipher);
    $decode = base64_decode($cod);

    $decode_xx = xxtea_decrypt($decode, ‘1234567890123456’);
    echo “шифруем xxtea_encrypt строку:Я самая красивая “;
    echo “получаем: $cipher “;
    echo “шифруем base64_encode строку: $cipher “;
    echo “получаем: $cod “;
    echo “дешифруем base64_encode строку: $decode “;
    echo “дешифруем xxtea_encrypt строку: $decode_xx “;

  22. Rob72

    >>Хочу скрыть информацию которая передается через url…
    Ну не передавайте через урл, используйте сессии.

  23. ntldr

    Для использования в этой реализации XXTEA ключей любой длины достаточно в 2-х местах добавить 2 строки:

    1) после
    function xxtea_encrypt($str, $key) {
    добавить
    $key=md5(md5($key).strrev($key));

    2) после
    function xxtea_decrypt($str, $key) {
    добавить
    $key=md5(md5($key).strrev($key));

    Т.е. перед шифровкой-дешифровкой получаем 128-битный уникальный md5-хеш и уже его используем как ключ.

    В результате длинна ключа может быть использована ЛЮБАЯ и стойкость (с точки зрения брутфорса) вырастает в разы.

  24. В таком случае можно шифровать файл по блочно. Например блоками размером в 1 mb. Существуют разные режимы шифрования. Поблочный, если не ошибаюсь называется CBC?


© Copyright. . I-Novice. All Rights Reserved. Terms | Site Map