Несанкционированный доступ к терминалам серверов с операционными системами семейства UNIX
Министерство
образования российской федерации
Липецкий
государственный технический университет
Кафедра АСОИУ
Индивидуальное
домашнее задание по дисциплине «Операционные системы»
«Несанкционированный доступ к терминалам серверов с
операционными системами семейства UNIX. На
примере octopus.stu.lipetsk.ru »
Выполнил:
Архипов Н.А.
Группа:
АС-99-2
Принял: Журавлева
М.Г.
Липецк
2001
Предисловие
План, что и говорить, был превосходный: простой и
ясный, лучше не придумаешь. Недостаток у него был только один: было совершенно
неизвестно, как привести его в исполнение.
Л. Кэрролл. Алиса в стране чудес
В данном
отчете мы попытаемся выявить «дыры» и «изъяны» локальной компьютерной сети ЛГТУ
(LSTU) в целом и в частности сервера для изучения
операционных систем UNIX – octopus.lstu. Для этого мы расскажем о возможных попытках получения
доступа к терминалам серверов, в том числе и с правами root’a, а так же попытка перегрузить сервер. Здесь не
рассматривается такой вид атаки как «Социальная инженерия», поскольку наша
задача – изучение операционных систем, а не психологии. Сразу предупреждаю, что
на практике не использовалось ни каких деструктивных действий (в том
числе перегрузки сервера), кроме тех действий которые использовались только для
изучения сети. Поэтому, мы ни какой ответственности за использование этого
документа не несем.
Особенности безопасности компьютерных сетей
Основной
особенностью любой сетевой системы является то, что ее компоненты распределены
в пространстве, а связь между ними осуществляется физически, при помощи
сетевых соединений (коаксиальный кабель, витая пара, оптоволокно и т. п.), и программно, при помощи механизма сообщений.
При этом все управляющие сообщения и данные, пересылаемые между объектами
распределенной вычислительной системы, передаются по сетевым соединениям в виде
пакетов обмена.
К сетевым системам, наряду с обычными
(локальными) атаками, осуществляемыми в пределах одной компьютерной системы,
применим специфический вид атак, обусловленный распределенностью
ресурсов и информации в пространстве так называемые сетевые (или удаленные)
атаки (remote или network attacks). Они характеризуются, во-первых, тем, что злоумышленник может
находиться за тысячи километров от атакуемого объекта, и, во-вторых, тем, что
нападению может подвергаться не конкретный компьютер, а информация, передающаяся
по сетевым соединениям. С развитием локальных и глобальных сетей именно
удаленные атаки становятся лидирующими как по количеству попыток, так и по
успешности их применения, и, соответственно, обеспечение безопасности ВС с
точки зрения противостояния сетевым атакам приобретает первостепенное
значение.
удаленные атаКИ НА ХОСТЫ iNterNet
Многое наша Земля
повидала, Но не видала Такого скандала!
Б. Заходер. География всмятку
Анализ сетевого трафика Internet
В Internet базовыми протоколами
удаленного доступа являются TELNET и FTP (File Transfer Protocol). TELNET - это протокол виртуального терминала
(ВТ), позволяющий с удаленных хостов подключаться к серверам Internet в режиме ВТ. FTP -
протокол, предназначенный для передачи файлов между удаленными хостами. Для
получения доступа к серверу по данным протоколам пользователю необходимо пройти
процедуры идентификации и аутентификации. В качестве информации,
идентифицирующей пользователя, выступает его имя, а для аутентификации используется пароль.
Особенностью протоколов FTP и TELNET является то, что пароли
и идентификаторы пользователей передаются по сети в открытом, незашифрованном
виде. Таким образом, необходимым и достаточным условием для получения
удаленного доступа к хостам по протоколам FTP и TELNET являются имя и пароль пользователя.
Одним из способов получения таких
паролей и идентификаторов в Internet является анализ
сетевого трафика. Этот анализ осуществляется с помощью специальной
программы-анализатора пакетов (sniffer), перехватывающей все
пакеты, передаваемые по сегменту сети, и выделяющей среди них те, в которых
передаются идентификатор пользователя и его пароль. Сетевой анализ протоколов FTP и TELNET показывает, что TELNET
разбивает пароль на символы и пересылает их по одному, помещая каждый символ
пароля в соответствующий пакет, a FTP, напротив, пересылает пароль целиком в одном пакете.
Возникает вопрос: а почему бы не
сделать передачу имени пользователя и пароля в зашифрованном виде? Видимо,
проблема в том, что базовые прикладные протоколы семейства TCP/IP разрабатывались очень давно, в период с конца
60-х до начала 80-х годов, и с тех пор абсолютно не изменились. При этом точка
зрения на построение глобальных сетей стала иной. Инфраструктура Сети и ее протоколы
разрабатывались исходя, в основном, из соображений надежности связи, но не из
соображений безопасности.
Таким образом
возможно отследить сетевой поток и выявить пакеты содержащие необходимые данные
(Имя, пароль, и т.д.). Так как в данном документе рассматривается только сервер
ЛГТУ octopus.lstu, то я
проанализировав сеть, пришел к выводу, что сервер не всегда находится в
активном состоянии. Таким образом, данный вариант атаки отпадает, да и еще
чтобы постоянно отслеживать трафик, необходимо, чтобы все это время в сети
находился хотя бы один компьютер, что невозможно из-за финансовых трудностей.
Перебор
паролей в файле /etc/passwd
В ранних
версиях операционных системах семейства UNIX
зашифрованные пароли (точнее их хэш-копии) хранились в файле /etc/passwd. В современных UNIX’ах пароли
хранятся в /etc/shadow.
Хранение зашифрованных паролей в /etc/passwd
делает систему сервера octopus.lstu
уязвимой. Здесь используется хэш-функция Data Encryption Standard (DES 48/64 4K). Поскольку данная шифровка работает только «в одну
сторону», а проверка подлинности пароля заключается в том, что при вводе пароля
пользователя, операционная система шифрует введенную последовательность и
сравнивает ее со строкой в файле /etc/passwd.
Вот пример записи паролей и имен пользователей в /etc/passwd:
root:LyavHDdahFcwU:0:1:Superuser:/:
…
malysh:7DnDkTMD9/wG2:1007:25:Olga A. Bocharnikova,
AS-98-1:/user/students/as98/malysh:
|
|
|
|
|
|
|
|
Для перебора
паролей мы используем тот же метод, что и операционная система: перебираю все
возможные комбинации букв латинского алфавита (причем имеет значение прописная
буква или строчная), цифр и специальных знаков. Здесь можно использовать как
функции самой операционной системы, так и написать свою функцию шифровки. Но
нужно быть точно уверенным что за алгоритм используется в данном случае, иначе
перебор не приведет ни к каким результатам. На компьютере octopus
используется алгоритм шифрования DES [48/64 4K]. Так как на octopus’e столь неважные, по сегодняшним меркам, аппаратные средства
(см. следующий пункт), то ни о каком переборе пароля не может идти и речи. Тем
более, даже на более быстрых машинах (Pentium III – 650MHz)
расшифровка заняла примерно 30 суток (!!!). Да и сервер не все время находится
в рабочем состоянии, как уже было замечено выше. В отчете прилагается часть
программы, для расшифровки паролей файла /etc/passwd.
Deny of Service (DoS) атака.
Дословно Deny of Service переводится как «отказ в
обслуживании». Это означает например, что операционная система не может
обслужить запрос пользователя или другой системы.
Рассмотрим нарушение работоспособности хоста в
сети при использовании направленного шторма ложных TCP-запросов на создание
соединения либо при переполнении очереди запросов. Из рассмотренной в
предыдущем пункте схемы создания TCP-соединения следует, что на каждый
полученный TCP-запрос (TCP SYN)
операционная система должна сгенерировать начальное значение идентификатора ISN
и отослать его на запросивший хост. Но так как в Internet (стандарта IPv4) не предусмотрен контроль за IP-адресом
отправителя сообщения, то проследить истинный маршрут, пройденный IP-пакетом,
невозможно и, следовательно, у конечных абонентов сети нет способа ограничить
число запросов, принимаемых в единицу времени от одного хоста. Поэтому возможно
осуществление типовой удаленной атаки «отказ в обслуживании», которая будет
заключаться в передаче на объект атаки как можно большего числа ложных
TCP-запросов на создание соединения от имени любого хоста в сети (направленный
шторм запросов TCP SYN,
схема которого приведена на рисунке).
|
|
|
При
этом атакуемая сетевая ОС в зависимости от вычислительной мощности компьютера
либо перестает реагировать на легальные запросы на подключение (отказ в
обслуживании), либо, в худшем случае, практически зависает. Это происходит
потому, что система должна, во-первых, сохранить в памяти полученную в ложных
сообщениях информацию и, во-вторых, выработать и отослать ответ на каждый
запрос. Таким образом, «съедаются» все ресурсы системы: переполняется очередь
запросов, и ОС вынуждена заниматься только их обработкой. Эффективность
данного воздействия тем выше, чем больше пропускная способность канала между
атакующим и его целью, и тем ниже, чем больше вычислительная мощность
атакуемого компьютера (число и быстродействие процессоров, объем ОЗУ и т.п.).
Такую атаку можно было предсказать еще лет двадцать назад, когда появилось
семейство протоколов TCP/IP: ее корни находятся в самой
инфраструктуре сети Internet, в ее базовых протоколах - IP и TCP. Но каково же было наше удивление, когда
выяснилось, что на информационном . WWW-сервере CERT (Computer Emergency Respone Team) первое упоминание об удаленном воздействии такого рода датировано
только 19 сентября 1996 года! Там эта атака носила название «TCP SYN Flooding and IP Spoofing Attacks» («наводнение» TCP-запросами с ложных IP-адресов). Другая разновидность
атаки «отказ в обслуживании» состоит в передаче на атакуемый хост нескольких
десятков (сотен) запросов TCP SYN в секунду (направленный мини-шторм
TCP-запросов) на подключение к серверу, что может привести к временному (до 10
минут) переполнению очереди запросов на сервере (см. атаку К. Митника). Это
происходит из-за того, что некоторые сетевые ОС обрабатывают только первые
несколько запросов на подключение, а остальные игнорируют, Таким образом,
получив N запросов на подключение, ОС сервера ставит их в
очередь и генерирует соответственно N ответов. Затем в течение определенного
промежутка времени (тайм-аут < 10 минут) сервер будет дожидаться сообщения
от предполагаемого клиента, чтобы завершить handshake и подтвердить создание виртуального канала с сервером. Если атакующий
пришлет такое количество запросов на подключение, которое равно максимальному
числу одновременно обрабатываемых сервером сообщений, то в течение тайм-аута
остальные запросы будут игнорироваться и установить связь с сервером не
удастся.
Мы провели ряд экспериментов с направленным
штормом и направленным миништормом запросов на различных по вычислительным
мощностям компьютерах с разными операционными системами.
Тестирование направленным штормом запросов TCP SYN, проводимое на различных
сетевых ОС в экспериментальных 10-мегабитных сегментах сети, дало следующие
результаты: все описанные далее атаки осуществлялись по определенной методике.
Подготавливался TCP-запрос, который при помощи специально разработанной
собственной программы в цикле передавался в сеть с соответствующими задержками
(вплоть до нулевой) между запросами. При этом циклически изменялись такие
параметры запроса, как порт отправителя и значение 32-битного идентификатора
SYN. IP-адрес отправителя запроса был выбран так, чтобы, во-первых, этот хост
в настоящий момент не был активен в сети и, во-вторых, чтобы соответствующий
маршрутизатор, в чьей зоне ответственности находится данный хост, не присылал
сообщения Host Unreachable (Хост недоступен). В противном случае хост, от имени (с IP-адреса)
которого посылался запрос TCP SYN, получив «неожиданный» ответ TCP АСК от атакуемого сервера, перешлет на него пакет TCP RST, закрывая таким образом
соединение.
При передаче по каналу связи максимально возможного числа TCP-запросов и
при нахождении кракера в одном сегменте с объектом атаки атакуемые системы
вели себя следующим образом: ОС Windows 95, установленная на
486DX2-66 с 8 Мб ОЗУ, «замирала» и переставала
реагировать на любые внешние воздействия (в частности, нажатия на клавиатуру);
ОС Linux 2.0.0 на 486DX4-133
с 8 Мб ОЗУ также практически не функционировала, обрабатывая одно нажатие на
клавиатуре примерно 30 секунд. В результате к этим хостам невозможно было
получить не только удаленный, но и локальный доступ.
Не менее интересным было поведение атакуемых
систем после снятия воздействия: ОС Windows 95 практически сразу
же после прекращения атаки начала нормально функционировать; в ОС Linux 2.0.0 с 8 Мб ОЗУ, по-видимому, переполнился буфер, и более получаса
система не функционировала ни для удаленных, ни для локальных пользователей, а
занималась только передачей ответов на полученные ранее запросы. CyberGuard сразу же после снятия воздействия стал доступным
для удаленного доступа.
Если кракер находился в смежных сегментах с
объектом, то во время атаки ОС Windows 95 на Pentium 100 с 16 Мб ОЗУ обрабатывала каждое нажатие с клавиатуры примерно
секунду, ОС Linux 2.0.0 на Pentium 100 с 16 Мб ОЗУ
практически «повисала» - одно нажатие за 30 секунд, зато после снятия
воздействия нормальная работа возобновлялась.
Не нужно обманываться, считая, что ОС Windows 95 показала себя с лучшей стороны. Такой результат объясняется
следующим: Windows 95 - операционная система, не имеющая
FTP-сервера, а следовательно, ей не нужно было сохранять в памяти параметры
передаваемого TCP-запроса на подключение к этому серверу и дожидаться
окончания handshake.
Таким образом, учитывая аппаратные средства сервера octopus.lstu (Olivetti 80286) можно без
труда осуществить на него DoS атаку. Даже если локальная сеть будет загружена.
Можно предположить, что и остальные сервера университета могут быть
«обездвижены» таким способом. Например сервер кафедры прикладной математики: IBM 486DX66 16RAM. По аппаратной части
серверы кафедры АСУ (здесь не имеется ввиду octopus.lstu) более устойчивы к DoS атаке.
Превышение максимально возможного размера IP-пакета, или Ping Death
В максимальный размер IP-пакета (65 535 байт)
включаются длина IP-заголовка и длина ноля данных в IP-пакете. Так как
минимальный размер IP-заголовка - 20 байт (максимальный - 60), то соответственно
размер данных, передаваемых в одном IP-пакете, не может превышать 65 535- 20 =
65 515 байт. А что будет, если превысить это число? Тестировать свои программы
на предельных критических значениях -стандартный для любого программиста ход.
Подобные тесты позволяют выявить такие неприятные ошибки, как всевозможные
переполнения (буфера, стека, переменной и т. д.). Но вернемся к IP. В принципе ничто не мешает атакующему сформировать набор фрагментов,
которые после сборки превысят максимально возможный размер IP-пакета.
Собственно в этой фразе и сформулирована основная идея данной атаки.
Итак, 18 декабря 2000 года на
информационном сервере СЕКТ появились сообщения о том, что большинство сетевых
операционных систем, поддерживающих протоколы TCP/IP, обладают следующей уязвимостью: при передаче на них IP-пакета длиной,
превышающей максимально допустимое значение, в этих ОС переполняется буфер или
переменная, в результате система «зависает» или перезагружается, то есть
налицо отказ в обслуживании. Был приведен и список потенциально опасных
платформ:
• Berkeley Software Design, Inc.
(BSD);
• Computer Associates, Intl. (products
for NCR);
• Cray Research;
• Digital Equipment Corporation;
• FreeBSD, Inc.; ' Hewlett-Packard
Company;
• IBM Corporation;
• Linux Systems;
• NEC Corporation;
• Open Software Foundation (OSF);
• The Santa Cruz Operation, Inc.
(SCO);
• Sun Microsystems, Inc.
Мы с удивлением прочитали этот перечень
операционных систем на различных платформах, а потом принялись за эксперименты.
Наше глубочайшее изумление вызвал тот факт, что элементарную ошибку переполнения
буфера в модуле IP ядра ОС за почти 20 лет активного функционирования
протокола IP разработчики сегодняшних систем до сих пор не
замечали. Поэтому мы позволили себе не поверить столь уважаемой организации,
как CERT. Но прежде чем начать эксперименты, было решено
посмотреть по указанной в CERT ссылке (#"65586.files/image007.gif">Подведем
итоги.
Учитывая все вышесказанное, я
думаю, что студентам кафедры АСОИУ уже сейчас не представляется никакой
сложности для несанкционированного доступа к терминалам серверов с правами
администраторов (причем это не необоснованное высказывание). Другой вопрос –
целесообразности всего этого. Я думаю что не стоит проверять все вышесказанное
на практике в целях своей же безопасности.
В целом, вычислительная сеть
университета администрируется весьма неплохо, нужно отдать должное системным
администраторам. На серверах стоят последние версии операционных систем. Однако
на chuck.stu.lipetsk.ru почему-то у обычных пользователей нет прав на
компилирование Си программ. Почему? Может это и есть слабое звено в
администрировании, или это еще одна предосторожность администратора? Хотя на tomcat.am.lstu
обычным смертным разрешено…
Вообще-то взлом octopus.stu.lipetsk.ru был бы неуважением своей же кафедры. Ведь та защита
которая там присутствует направлена не для того, чтобы предотвратить
проникновение злоумышленника, а для элементарной защиты от неопытных
пользователей.
ПРИЛОЖЕНИЕ.
В целях безопасности, приводим
только фрагменты программы. Файл john.c
#include
<stdio.h>
#include
<string.h>
#include
<stdlib.h>
#include
<sys/stat.h>
#include
"misc.h"
#include
"params.h"
#include
"path.h"
#include
"memory.h"
#include
"list.h"
#include
"tty.h"
#include
"signals.h"
#include
"idle.h"
#include
"common.h"
#include
"formats.h"
#include
"loader.h"
#include
"logger.h"
#include
"status.h"
#include
"options.h"
#include
"config.h"
#include
"bench.h"
#include
"charset.h"
#include
"single.h"
#include
"wordlist.h"
#include
"inc.h"
#include
"external.h"
#include
"batch.h"
#if CPU_DETECT
extern int
CPU_detect();
#endif
extern struct
fmt_main fmt_DES, fmt_BSDI, fmt_MD5, fmt_BF;
extern struct
fmt_main fmt_AFS, fmt_LM;
extern int
unshadow(int argc, char **argv);
extern int
unafs(int argc, char **argv);
extern int
unique(int argc, char **argv);
static struct
db_main database;
static struct
fmt_main dummy_format;
static void
john_register_one(struct fmt_main *format)
{
if
(options.format)
if
(strcmp(options.format, format->params.label)) return;
fmt_register(format);
}
static void
john_register_all()
{
if
(options.format) strlwr(options.format);
john_register_one(&fmt_DES);
john_register_one(&fmt_BSDI);
john_register_one(&fmt_MD5);
john_register_one(&fmt_BF);
john_register_one(&fmt_AFS);
john_register_one(&fmt_LM);
if
(!fmt_list) {
fprintf(stderr,
"Unknown ciphertext format name requested\n");
error();
}
}
static void
john_load()
{
struct
list_entry *current;
umask(077);
if
(options.flags & FLG_EXTERNAL_CHK)
ext_init(options.external);
if
(options.flags & FLG_MAKECHARS_CHK) {
options.loader.flags
|= DB_CRACKED;
ldr_init_database(&database,
&options.loader);
if
(options.flags & FLG_PASSWD) {
ldr_show_pot_file(&database,
LOG_NAME);
database.options->flags
|= DB_PLAINTEXTS;
if
((current = options.passwd->head))
do
{
ldr_show_pw_file(&database,
current->data);
}
while ((current = current->next));
}
else {
database.options->flags
|= DB_PLAINTEXTS;
}
return;
}
if
(options.flags & FLG_STDOUT) {
ldr_init_database(&database,
&options.loader);
database.format
= &dummy_format;
memset(&dummy_format,
0, sizeof(dummy_format));
dummy_format.params.plaintext_length
= options.length;
dummy_format.params.flags
= FMT_CASE | FMT_8_BIT;
}
if
(options.flags & FLG_PASSWD) {
if
(options.flags & FLG_SHOW_CHK) {
options.loader.flags
|= DB_CRACKED;
ldr_init_database(&database,
&options.loader);
ldr_show_pot_file(&database,
LOG_NAME);
if
((current = options.passwd->head))
do
{
ldr_show_pw_file(&database,
current->data);
}
while ((current = current->next));
printf("%s%d
password%s cracked, %d left\n",
database.guess_count
? "\n" : "",
database.guess_count,
database.guess_count
!= 1 ? "s" : "",
database.password_count
-
database.guess_count);
return;
}
if
(options.flags & (FLG_SINGLE_CHK | FLG_BATCH_CHK))
options.loader.flags
|= DB_WORDS;
else
if
(mem_saving_level)
options.loader.flags
&= ~DB_LOGIN;
ldr_init_database(&database,
&options.loader);
if
((current = options.passwd->head))
do
{
ldr_load_pw_file(&database,
current->data);
}
while ((current = current->next));
ldr_load_pot_file(&database,
LOG_NAME);
ldr_fix_database(&database);
printf("Loaded
%d password%s%s",
database.password_count,
database.password_count
!= 1 ? "s" : "",
database.password_count
? "" : ", exiting...");
if
(database.password_count > 1) {
printf("
with ");
printf(database.salt_count
!= 1 ? "%d" : "no",
database.salt_count);
printf("
different salts");
}
if
(database.password_count)
printf("
(%s [%s])\n",
database.format->params.format_name,
database.format->params.algorithm_name);
else
putchar('\n');
if
((options.flags & FLG_PWD_REQ) && !database.salts) exit(0);
}
}
static void
john_init(int argc, char **argv)
{
#if CPU_DETECT
if
(!CPU_detect()) {
#if CPU_REQ
fprintf(stderr,
"Sorry, %s is required\n", CPU_NAME);
error();
#endif
}
#endif
path_init(argv);
cfg_init(CFG_NAME);
opt_init(argc,
argv);
john_register_all();
common_init();
sig_init(idle_yield);
john_load();
}
static void
john_run()
{
if
(options.flags & FLG_TEST_CHK)
benchmark_all();
else
if
(options.flags & FLG_MAKECHARS_CHK)
do_makechars(&database,
options.charset);
else
if
(options.flags & FLG_CRACKING_CHK) {
if
(!(options.flags & FLG_STDOUT)) log_init(LOG_NAME);
tty_init();
if
(options.flags & FLG_SINGLE_CHK)
do_single_crack(&database);
else
if
(options.flags & FLG_WORDLIST_CHK)
do_wordlist_crack(&database,
options.wordlist,
(options.flags
& FLG_RULES) != 0);
else
if
(options.flags & FLG_INC_CHK)
do_incremental_crack(&database,
options.charset);
else
if
(options.flags & FLG_EXTERNAL_CHK)
do_external_crack(&database);
else
if
(options.flags & FLG_BATCH_CHK)
do_batch_crack(&database);
status_print();
tty_done();
if
(!(options.flags & FLG_STDOUT)) log_done();
}
}
static void
john_done()
{
path_done();
check_abort();
}
int main(int
argc, char **argv)
{
char
*name;
#ifdef __DJGPP__
if
(--argc <= 0) return 1;
if
((name = strrchr(argv[0], '/')))
strcpy(name
+ 1, argv[1]);
name
= argv[1];
argv[1]
= argv[0];
argv++;
#else
if
(!argv[0])
name
= "";
else
if
((name = strrchr(argv[0], '/')))
name++;
else
name
= argv[0];
#endif
#ifdef
__CYGWIN32__
if
(strlen(name) > 4)
if
(!strcmp(strlwr(name) + strlen(name) - 4, ".exe"))
name[strlen(name)
- 4] = 0;
#endif
if
(!strcmp(name, "john")) {
john_init(argc,
argv);
john_run();
john_done();
}
if
(!strcmp(name, "unshadow"))
return
unshadow(argc, argv);
if
(!strcmp(name, "unafs"))
return
unafs(argc, argv);
if
(!strcmp(name, "unique"))
return
unique(argc, argv);
fprintf(stderr,
"Sorry, I can't find myself\n");
return
1;
}
Файл des_bs.c
#include
<string.h>
#include
"arch.h"
#include
"DES_std.h"
#include
"DES_bs.h"
DES_bs_combined
DES_bs_all;
int
DES_bs_mem_saving = 0;
extern void DES_bs_body();
void
DES_bs_init()
{
int
index, bit;
for
(index = 0; index < 0x300; index++) {
bit
= DES_K_bits[index];
bit
-= bit >> 3;
DES_bs_all.Kp[index]
= &DES_bs_all.K[55 - bit];
}
}
void
DES_bs_set_salt(ARCH_WORD salt)
{
register
int src, dst;
register
ARCH_WORD mask;
mask
= 1;
for
(dst = 0; dst < 48; dst++) {
if
(dst == 24) mask = 1;
if
(salt & mask) {
if
(dst < 24) src = dst + 24; else src = dst - 24;
}
else src = dst;
DES_bs_all.E[dst]
= &DES_bs_all.B[DES_E[src]];
DES_bs_all.E[dst
+ 48] = &DES_bs_all.B[DES_E[src] + 32];
mask
<<= 1;
}
}
void
DES_bs_clear_keys()
{
memset(DES_bs_all.K,
0, sizeof(DES_bs_all.K));
}
void
DES_bs_set_key(char *key, int index)
{
register
char *ptr;
register
int ofs, bit;
register
ARCH_WORD value;
ofs
= 56;
for
(ptr = key; *ptr && ofs; ptr++) {
bit
= (ofs -= 7);
value
= *ptr & 0x7F;
do
{
DES_bs_all.K[bit++]
|= (value & 1) << index;
}
while (value >>= 1);
}
}
void
DES_bs_crypt(int count)
{
register
int bit;
register
ARCH_WORD R, L;
memset(DES_bs_all.B,
0, sizeof(DES_bs_all.B));
do {
DES_bs_body();
if
(!--count) break;
for
(bit = 0; bit < 32; bit++) {
R
= DES_bs_all.B[bit];
DES_bs_all.B[bit
+ 32] = R;
DES_bs_all.B[bit]
= L;
}
}
while (1);
}
ARCH_WORD
*DES_bs_get_binary(char *ciphertext)
{
static
ARCH_WORD out[64];
ARCH_WORD
*raw;
int
bit;
int
index, shift;
int
value;
raw
= DES_raw_get_binary(ciphertext);
out[1]
= out[0] = 0;
for
(bit = 0; bit < 64; bit++) {
index
= bit >> 4;
/* Swap L and R
here instead of doing it one more time in DES_bs_crypt() */
index
^= 2;
/* Calculate the
number of one of the 16 data bits in raw[index] */
shift
= ((bit & 0xC) << 1) + (bit & 3) + 1;
/* Get the bit
*/
value
= (raw[index] >> shift) & 1;
if
(DES_bs_mem_saving)
/* Memory
saving: pack the bits into two words */
out[bit
>> 5] |= value << (bit & 0x1F);
else
/* We either set
or clear all the bits in every word */
out[bit]
= value ? ~(ARCH_WORD)0 : 0;
}
return
out;
}
int
DES_bs_binary_hash(ARCH_WORD *binary, int count)
{
int
bit, result;
if
(DES_bs_mem_saving)
return
(int)*binary & ((1 << count) - 1);
result
= 0;
for
(bit = 0; bit < count; bit++)
if
(binary[bit]) result |= 1 << bit;
return
result;
}
int
DES_bs_get_hash(int index, int count)
{
register
int bit, result;
register
ARCH_WORD mask;
mask
= (ARCH_WORD)1 << index;
result
= 0;
for
(bit = 0; bit < count; bit++)
if
(DES_bs_all.B[bit] & mask) result |= 1 << bit;
return
result;
}
/*
* The trick I
used here allows to compare one ciphertext against all the
*
DES_bs_crypt() outputs in just O(log2(ARCH_BITS)) operations.
*/
int DES_bs_cmp_all(ARCH_WORD
*binary, int count)
{
register
int bit;
register
ARCH_WORD mask;
mask
= 0;
if
(DES_bs_mem_saving)
for
(bit = 0; bit < ((count < 32) ? count : 32); bit++) {
mask
|= DES_bs_all.B[bit] ^
((binary[0]
& (1 << bit)) ? ~(ARCH_WORD)0 : 0);
if
(mask == ~(ARCH_WORD)0) return 0;
}
else
for
(bit = 0; bit < count; bit++) {
mask
|= DES_bs_all.B[bit] ^ binary[bit];
if
(mask == ~(ARCH_WORD)0) return 0;
return
1;
}
int
DES_bs_cmp_one(ARCH_WORD *binary, int count, int index)
{
register
int bit;
register
ARCH_WORD mask;
if
(DES_bs_mem_saving) {
for
(bit = 0; bit < count; bit++)
if
(((DES_bs_all.B[bit] >> index) ^
(binary[bit
>> 5] >> (bit & 0x1F))) & 1) return 0;
return
1;
}
mask
= (ARCH_WORD)1 << index;
for
(bit = 0; bit < count; bit++)
if
((DES_bs_all.B[bit] ^ binary[bit]) & mask) return 0;
return
1;
}