Мой сайт... :)
Вы находитесь в разделе:
Почеркушки
Поиск по блогу
Вы просматриваете архив Почеркушки блога Сентябрь, 2007 .
Рубрики

Сентябрь, 2007

Простая и надежная PHP функция для обратимого шифрования

Понедельник, 24/09/2007

Всем привет! :)

Сегодня столкнулся с такой проблемой, нужно было шифровать ключи в базе данных паролем администратора. А тут, вот те раз, оказалось, что в PHP нет встроенной функции обратимого шифрования, даже самой простой. “Хм…” подумал я и полез в инет.

Как оказалось в инете с этим тоже глухо, не нашел при беглом взгяде ни одной готовой процедуры или скрипта. Правда нашел библиотеку к PHP для шифрования - mcrypt, но что бы ее поставить, нужно пересобирать ядро PHP или просить поставить техподдержку хостинга эту библиотеку и не на всех хостингах это возможно, в общем с mcrypt настоящий гемммморой. :)

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

Итак подумав решил организовать классическое и эффективное наложение шифруемой строки на надежную гамму (псевдослучайную последовательность) с помощью XOR. Вопрос только, где взять приемлимую по надежности гамму. Конгруэнтные генераторы отлетают сразу. Регистры сдвига долго, да и легко они ломаются по куску открытого текста. В общем подумав еще минут 10 придумал использовать для генерации гаммы обычную хэш функцию. :)

Т.е. математика такая:
K(i+1) = sha1(K[i])

Но, если вдуматься, в таком виде ее использовать для гаммы нельзя, ибо такая гамма будет уязвима к куску открытого текста размером примерно в 20 байт (sha1 выдает хэш размером в 20 байт).

Однако если для гаммы брать только, например, первый байт от K[i] (сам он по себе 20 байт), то проблема уходит. Однако встает вопрос производительности на относительно больших текстах.

По этому я решил брать первые 8 байт (можно меньше или больше - на ваш выбор и соответственно решаемой задаче). В этом случае криптостойкость (по открытому куску текста) пораждаемой гаммы будет составлять сложность взлома sha1 по оставшимся 12 байтам от 20. Что более чем достаточно для большинства задач.

Реализовав это все в код у меня получилось:

//PHP функция для обратимого шифрования
//————————————-
function encode($String, $Password)
{
$Salt=’BGuxLWQtKweKEMV4′;
$StrLen = strlen($String);
$Seq = $Password;
$Gamma = ”;
while (strlen($Gamma)< $StrLen)
{
$Seq = pack(”H*”,sha1($Seq.$Salt)); //в PHP5 эту строку можно заменить на $Seq = sha1($Seq.$Salt, true);
$Gamma.=substr($Seq,0,8);
}return $String^$Gamma;
}

Переменную $Salt=’BGuxLWQtKweKEMV4′; я ввел для того, что бы случайно не возникло коллизии, если вы будете хранить пароль, которым шифровали рядом в виде хэша (того же sha1). В принципе, вы можете подставить в нее свое значение, главное, что бы она была не пустая! :)

Ну и еще один момент, если хотите еще усилить криптостойкость ко взлому, то можно строку $Seq = pack(”H*”,sha1($Seq.$Salt)); переделать на такую: $Seq = pack(”H*”,sha1($Gamma.$Seq.$Salt)); что сделает бесполезной попытку взлома по открытому куску текста из середины.

В общем, в конце концов у меня получилось так:

//PHP функция для обратимого шифрования
//————————————-
function encode($String, $Password)
{
$Salt=’BGuxLWQtKweKEMV4′;
$StrLen = strlen($String);
$Seq = $Password;
$Gamma = ”;
while (strlen($Gamma)< $StrLen)
{
$Seq = pack(”H*”,sha1($Gamma.$Seq.$Salt));
$Gamma.=substr($Seq,0,8);
}return $String^$Gamma;
}

Пользуйтесь на здоровье! :)

Ах да, совсем громадные объемы текста этой функцией лучше не шифровать, т.к. у хешей последовательности кончаются короткими циклами, но это нужно очень постараться с размером шифровки, что бы дойти до этих “коротких циклов”. :) Хотя вы можете поэкспериментировать и доабгрейдить этот код, как вам будет необходимо, благо он простой, понятный и достаточно надежный.

Надеюсь, вам смог помочь этот пост. А если у вас есть пожелания замечания к моим выкладкам обязательно пишите, буду очень рад! :)

С уважением, Владимир.

Добавлено 9 марта 2010

Поскольку топик вызвал интерес и некоторое вопросы о том, как же все-таки расшифровывать и зашифровывать, решил сделать добавку к топику и выложить более расширеннй код.

В расширенном коде есть две процедуры encode и decode, а также встроена простая проверка правильности расшифровки (один байт):

function encode($String, $Password)
{
    //Author: Vladimir Kim (www.vkim.ru) 2010
    //Free for use

    if (!$Password) die ("Не задан пароль шифрования");

    $Salt='BGuxLWQtKweKEMV4';
    $String = substr(pack("H*",sha1($String)),0,1).$String;
    $StrLen = strlen($String);
    $Seq = $Password;
    $Gamma = '';
    while (strlen($Gamma)< $StrLen)
    {
        $Seq = pack("H*",sha1($Seq.$Gamma.$Salt));
        $Gamma.=substr($Seq,0,8);
    }

    return base64_encode($String^$Gamma);
}

function decode($String, $Password)
{
    //Author: Vladimir Kim (www.vkim.ru) 2010
    //Free for use

    if (!$Password) die ("Не задан пароль для расшифровки");

    $Salt='BGuxLWQtKweKEMV4';
    $StrLen = strlen($String);
    $Seq = $Password;
    $Gamma = '';
    while (strlen($Gamma)<$StrLen)
    {
        $Seq = pack("H*",sha1($Seq.$Gamma.$Salt));
        $Gamma.=substr($Seq,0,8);
    }

    $String = base64_decode($String);
    $String = $String^$Gamma;

    $DecodedString = substr($String, 1);
    $Error = ord(substr($String, 0, 1)
             ^ substr(pack("H*",sha1($DecodedString)),0,1)); 

    //проверяем
    if ($Error) return false;
    else return $DecodedString;
}

Вот, если будут вопросы, задавайте :)

С уважением, Владимир

Прокрутить страницу вверх! :)
Copyright (C) 2000-2008 Vladimir Kim.
All rights reserved.
Содержание сайта охраняется законом о защите авторских прав. Допускается ограниченое цитирование текста статей данного сайта на любых публичных ресурсах без уведомления автора, но с обязательной активной ссылкой (URL) на источник (www.vkim.ru). Публикация и распространение полных версий статей с данного сайта возможна только с письменного разрешения автора!