<!--
     The FreeBSD Russian Documentation Project

     $FreeBSD$
     $FreeBSDru: frdp/doc/ru_RU.KOI8-R/articles/ipsec-must/article.sgml,v 1.4 2001/07/19 08:26:25 phantom Exp $

     Original revision: 1.3
-->

<!DOCTYPE article PUBLIC "-//FreeBSD//DTD DocBook V4.1-Based Extension//EN" [
<!ENTITY % man PUBLIC "-//FreeBSD//ENTITIES DocBook Manual Page Entities//EN">
%man;
]>

<article>
  <articleinfo>
    <title>Независимое исследование работы IPsec во FreeBSD</title>

    <author>
      <firstname>David</firstname>
      <surname>Honig</surname>

      <affiliation>
        <address><email>honig@sprynet.com</email></address>
      </affiliation>
    </author>

    <pubdate>3 May 1999</pubdate>

    <abstract>
      <para>Вы только что установили и настроили IPsec, и оно,
        кажется, заработало.  Как это можно проверить?  Я опишу метод
        экспериментальной проверки правильного функционирования
        IPsec.</para>
    </abstract>
  </articleinfo>

  <sect1>
    <title>Постановка задачи</title>

    <para>Для начала предположим, что Вы <link linkend="ipsec-install">
      настроили <emphasis>IPsec</emphasis></link>. Как Вы
      узнаете, что IPsec <link linkend="caveat">работает</link>?
      Несомненно, соединения не будет, если Вы неверно его
      сконфигурировали.  И оно конечно появится в выводе команды
      &man.netstat.1;, когда Вы всё сделаете верно.  Но можно ли
      как-то подтвердить сам факт функционирования IPsec?</para>
  </sect1>

  <sect1>
    <title>Решение</title>

    <para>Для начала немножко криптографической теории:</para>

    <orderedlist>
      <listitem>
        <para>шифрованные данные равномерно распределены по области
          определения, то есть каждый символ имеет максимальную
          энтропию;</para>
      </listitem>

      <listitem>
        <para><quote>сырые</quote> и несжатые данные как правило
          избыточны, то есть их энтропия меньше максимально
          возможной.</para>
      </listitem>
    </orderedlist>

    <para>Предположим, что у Вас имеется возможность измерить энтропию
      входящего и исходящего трафика на сетевом интерфейсе.  В этом
      случае Вы сможете легко отличить зашифрованные данные от
      открытых, причём даже в том случае, когда часть данных в
      <quote>режиме шифрования</quote> передаётся в открытом виде, к
      примеру внешние заголовки IP, которые используются для
      маршрутизации.</para>

    <sect2 id="MUST">
      <title>MUST</title>

      <para><quote>Универсальный Статистический Тест для Генераторов
        Случайных Чисел</quote> Уэли Маурера (Ueli Maurer's Universal
        Statistical Test for Random Bit Generators), сокращённо <ulink
        url="http://www.geocities.com/SiliconValley/Code/4704/universal.pdf">
        <acronym>MUST</acronym></ulink> позволяет быстро измерить
        энтропию последовательного набора данных.  Используемый
        алгоритм похож на алгоритм сжатия.  <link linkend="code"> В
        приложении</link> приведён исходный код, позволяющий измерять
        энтропию последовательных кусков данных размером около
        четверти мегабайта.</para>
    </sect2>

    <sect2 id="tcpdump">
      <title>Tcpdump</title>

      <para>Ещё нам нужен способ сохранения информации,
        проходящей через интерфейс. Программа &man.tcpdump.1;
        позволяет сделать это в случае, если Вы <link
        linkend="kernel">сконфигурировали своё ядро</link> с
        поддержкой <emphasis>Пакетного Фильтра Беркли (Berkeley Packet
        Filter)</emphasis>.</para>

      <para>Команда

        <screen>
        <userinput><command>tcpdump</command> -c 4000 -s 10000 -w <replaceable>dumpfile.bin</replaceable></userinput>
        </screen>

        сохранит 4000 пакетов в файл
        <replaceable>dumpfile.bin</replaceable>.  В данном примере объём
        записываемой информации в каждом пакете не может превышать
        10,000 байтов.</para>
    </sect2>
  </sect1>

  <sect1>
    <title>Эксперимент</title>

    <para>В этом разделе описано, в чём собственно заключается суть
      эксперимента.</para>

    <procedure>
      <step>
        <para>Откройте два окна терминала и свяжитесь в одном из них с
          каким-нибудь компьютером через канал IPsec, а в другом --- с
          обычным, <quote>незащищённым</quote> компьютером.</para>
      </step>

      <step>
        <para>Теперь начните <link linkend="tcpdump">сохранять
          пакеты</link>.</para>
      </step>

      <step>
        <para>В <quote>шифрованном</quote> окне запустите команду
          &man.yes.1;, которая будет выдавать бесконечный
          поток символов <quote>y</quote>.  Немножко подождите и
          завершите её.  Затем переключитесь в обычное окно (не
          использующее канал IPsec) и сделайте то же самое.</para>
      </step>

      <step>
        <para>Заключительный этап: запустите <link linkend="code">
          MUST</link>, передав ему для обработки только что
          сохранённые пакеты через командную строку.  Вы должны
          увидеть что-то вроде изображённого чуть ниже.  Заметьте, что
          безопасное соединение имеет 93% (6,7) от ожидаемого значения
          (7,18), а обычное соединение --- всего лишь 29%
          (2,1).</para>

    <screen>
&prompt.user; <userinput>tcpdump -c 4000 -s 10000 -w <replaceable>ipsecdemo.bin</replaceable></userinput>
&prompt.user; <userinput>uliscan <replaceable>ipsecdemo.bin</replaceable></userinput>

Uliscan 21 Dec 98
L=8 256 258560
Measuring file ipsecdemo.bin
Init done
Expected value for L=8 is 7.1836656
6.9396 --------------------------------------------------------
6.6177 -----------------------------------------------------
6.4100 ---------------------------------------------------
2.1101 -----------------
2.0838 -----------------
2.0983 -----------------
</screen>
      </step>
    </procedure>
  </sect1>

    <sect1 id="caveat">
      <title>Замечание</title>

    <para>Этот эксперимент показывает, что IPsec
      <emphasis>действительно</emphasis> распределяет передаваемые
      байты по области определения <emphasis>равномерно</emphasis>,
      как и любое другое шифрование.  Однако этот метод <emphasis>не
      может</emphasis> обнаружить множество других изъянов в системе
      (хотя я таковых не знаю).  Для примера можно привести плохие
      алгоритмы генерации или обмена ключами, нарушение
      конфиденциальности данных или ключей, использование слабых в
      криптографическом смысле алгоритмов, взлом ядра и т. д. Изучайте
      исходный код, узнавайте, что там происходит.</para>
  </sect1>

  <sect1 id="IPsec">
    <title>Определение IPsec</title>

    <para>IPsec представляет собой протокол безопасного обмена
      информацией по Internet. Существует в виде расширения к IPv4;
      является неотъемлемой частью IPv6.  Содержит в себе протокол
      шифрования и аутентификации на уровне IP (межмашинное
      <quote>host-to-host</quote> взаимодействие).  SSL защищает
      только лишь конкретный прикладной сокет;
      <application>SSH</application> защищает вход на машину;
      <application>PGP</application> защищает определённый файл или
      письмо. IPsec шифрует всю информацию, передаваемую между двумя
      машинами.</para>
  </sect1>

  <sect1 id="ipsec-install">
    <title>Установка IPsec</title>

    <para>Большинство современных версий FreeBSD уже имеют поддержку
      IPsec.  Вероятно, Вы должны будете лишь добавить опцию
      <option>IPsec</option> в конфигурационный файл ядра, и после
      сборки и инсталляции нового ядра, сконфигурировать соедения
      IPsec с помощью команды &man.setkey.8;.</para>

    <para>Более подробно о том, как заупстить IPsec во FreeBSD можно
      прочесть в <ulink
      url="http://www.freebsd.org.ua/handbook/ipsec.html">Руководстве
      пользователя</ulink>.</para>
  </sect1>

  <sect1 id="kernel">
    <title>usr/src/sys/i386/conf/KERNELNAME</title>

    <para>Следующие строки должны присутствовать в конфигурационном
      файле ядра, чтобы оно поддерживало Berkeley Packet Filter.  Не
      забудьте после модификации запустить &man.config.8;, и, как
      обычно, пересобрать и установить новое ядро.</para>

<programlisting>
device	bpf
</programlisting>
  </sect1>

    <sect1 id="code">
      <title>Универсальный Статистический Тест Маурера (размер блока
        --- 8 бит)</title>

        <para>Оригинал нижеприведённого кода находится по <ulink
          url="http://www.geocities.com/SiliconValley/Code/4704/uliscanc.txt">
          этому адресу</ulink>.</para>

<programlisting>
/*
  ULISCAN.c   ---blocksize of 8

  1 Oct 98
  1 Dec 98
  21 Dec 98       uliscan.c derived from ueli8.c

  This version has // comments removed for Sun cc

  This implements Ueli M Maurer's "Universal Statistical Test for Random
  Bit Generators" using L=8

  Accepts a filename on the command line; writes its results, with other
  info, to stdout.

  Handles input file exhaustion gracefully.

  Ref: J. Cryptology v 5 no 2, 1992 pp 89-105
  also on the web somewhere, which is where I found it.

  -David Honig
  honig@sprynet.com

  Usage:
  ULISCAN filename
  outputs to stdout
*/

#define L 8
#define V (1&lt;&lt;L)
#define Q (10*V)
#define K (100   *Q)
#define MAXSAMP (Q + K)

#include &lt;stdio.h&gt;
#include &lt;math.h&gt;

int main(argc, argv)
int argc;
char **argv;
{
  FILE *fptr;
  int i,j;
  int b, c;
  int table[V];
  double sum = 0.0;
  int iproduct = 1;
  int run;

  extern double   log(/* double x */);

  printf("Uliscan 21 Dec 98 \nL=%d %d %d \n", L, V, MAXSAMP);

  if (argc &lt; 2) {
    printf("Usage: Uliscan filename\n");
    exit(-1);
  } else {
    printf("Measuring file %s\n", argv[1]);
  }

  fptr = fopen(argv[1],"rb");

  if (fptr == NULL) {
    printf("Can't find %s\n", argv[1]);
    exit(-1);
  }

  for (i = 0; i &lt; V; i++) {
    table[i] = 0;
  }

  for (i = 0; i &lt; Q; i++) {
    b = fgetc(fptr);
    table[b] = i;
  }

  printf("Init done\n");

  printf("Expected value for L=8 is 7.1836656\n");

  run = 1;

  while (run) {
    sum = 0.0;
    iproduct = 1;

    if (run)
      for (i = Q; run && i &lt; Q + K; i++) {
        j = i;
        b = fgetc(fptr);

        if (b &lt; 0)
          run = 0;

        if (run) {
          if (table[b] &gt; j)
            j += K;

          sum += log((double)(j-table[b]));

          table[b] = i;
        }
      }

    if (!run)
      printf("Premature end of file; read %d blocks.\n", i - Q);

    sum = (sum/((double)(i - Q))) /  log(2.0);
    printf("%4.4f ", sum);

    for (i = 0; i &lt; (int)(sum*8.0 + 0.50); i++)
      printf("-");

    printf("\n");

    /* refill initial table */
    if (0) {
      for (i = 0; i &lt; Q; i++) {
        b = fgetc(fptr);
        if (b &lt; 0) {
          run = 0;
        } else {
          table[b] = i;
        }
      }
    }
  }
}
</programlisting>
  </sect1>
</article>
