<!--
    The FreeBSD Documentation Project

    $FreeBSD$
-->

<!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>Independent Verification of IPSec Functionality in 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>You installed IPsec and it seems to be working. How do you
        know?  I describe a method for experimentally verifying that IPsec is
        working.</para>
    </abstract>
  </articleinfo>

  <sect1>
    <title>The Problem</title>

    <para>First, let's assume you have <link linkend="ipsec-install">
      installed <emphasis>IPsec</emphasis></link>.  How do you know
      it is <link linkend="caveat">working</link>?  Sure, your
      connection will not work if it is misconfigured, and it will work
      when you finally get it right.  &man.netstat.1; will list it.
      But can you independently confirm it?</para>
  </sect1>

  <sect1>
    <title>The Solution</title>

    <para>First, some crypto-relevant info theory:</para>

    <orderedlist>
      <listitem>
	<para>encrypted data is uniformly distributed, i.e., has maximal
	  entropy per symbol;</para>
      </listitem>

      <listitem>
	<para>raw, uncompressed data is typically redundant, i.e., has
	  sub-maximal entropy.</para>
      </listitem>
    </orderedlist>

    <para>Suppose you could measure the entropy of the data to- and
      from- your network interface.  Then you could see the difference
      between unencrypted data and encrypted data.  This would be true
      even if some of the data in <quote>encrypted mode</quote> was
      not encrypted---as the outermost IP header must be, if the
      packet is to be routable.</para>

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

      <para>Ueli Maurer's <quote>Universal Statistical Test for Random
	Bit Generators</quote>(<ulink
	url="http://www.geocities.com/SiliconValley/Code/4704/universal.pdf">
	<acronym>MUST</acronym></ulink>) quickly measures the entropy
	of a sample.  It uses a compression-like algorithm.  <link
	linkend="code">The code is given below</link> for a variant
	which measures successive (~quarter megabyte) chunks of a
	file.</para>
    </sect2>

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

      <para>We also need a way to capture the raw network data.  A
	program called &man.tcpdump.1; lets you do this, if you have
	enabled the <emphasis>Berkeley Packet Filter</emphasis>
	interface in your <link linkend="kernel">kernel's config
	file</link>.</para>

      <para>The command</para>

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

      <para>will capture 4000 raw packets to
      <replaceable>dumpfile.bin</replaceable>.  Up to 10,000 bytes per
      packet will be captured in this example.</para>
    </sect2>
  </sect1>

  <sect1>
    <title>The Experiment</title>

    <para>Here is the experiment.</para>

    <procedure>
      <step>
	<para>Open a window to an IPsec host and another window to an
	  insecure host.</para>
      </step>

      <step>
	<para>Now start <link linkend="tcpdump">capturing
	  packets</link>.</para>
      </step>

      <step>
	<para>In the <quote>secure</quote> window, run the Unix
	  command &man.yes.1;, which will stream the <literal>y</literal>
	  character.  After a while, stop this.  Switch to the
	  insecure window, and repeat.  After a while, stop.</para>
      </step>

      <step>
	<para>Now run <link linkend="code">MUST</link> on the
	  captured packets.  You should see something like the
	  following.  The important thing to note is that the secure
	  connection has 93% (6.7) of the expected value (7.18), and
	  the <quote>normal</quote> connection has 29% (2.1) of the
	  expected value.</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>Caveat</title>

    <para>This experiment shows that IPsec <emphasis>does</emphasis>
      seem to be distributing the payload data
      <emphasis>uniformly</emphasis>, as encryption should.  However,
      the experiment described here <emphasis>cannot</emphasis>
      detect many possible flaws in a system (none of which do I have
      any evidence for).  These include poor key generation or
      exchange, data or keys being visible to others, use of weak
      algorithms, kernel subversion, etc.  Study the source; know the
      code.</para>
  </sect1>

  <sect1 id="IPsec">
    <title>IPsec---Definition</title>

    <para>Internet Protocol security extensions to IPv4; required for
      IPv6.  A protocol for negotiating encryption and authentication
      at the IP (host-to-host) level.  SSL secures only one application
      socket; <application>SSH</application> secures only a login;
      <application>PGP</application> secures only a specified file or
      message.  IPsec encrypts everything between two hosts.</para>
  </sect1>

  <sect1 id="ipsec-install">
    <title>Installing IPsec</title>

    <para>Most of the modern versions of FreeBSD have IPsec support
      in their base source.  So you will probably will need to include
      <option>IPSEC</option> option in your kernel config and, after
      kernel rebuild and reinstall, configure IPsec connections using
      &man.setkey.8; command.</para>

    <para>A comprehensive guide on running IPsec on FreeBSD is
      provided in <ulink
      url="../../books/handbook/ipsec.html">FreeBSD
      Handbook</ulink>.</para>
  </sect1>

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

    <para>This needs to be present in the kernel config file in order
      to be able to capture network data with &man.tcpdump.1;.  Be sure
      to run &man.config.8; after adding this, and rebuild and
      reinstall.</para>

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

    <sect1 id="code">
      <title>Maurer's Universal Statistical Test (for block size=8
        bits)</title>

        <para>You can find the same code at <ulink
          url="http://www.geocities.com/SiliconValley/Code/4704/uliscanc.txt">
          this link</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>
