diff --git a/ja_JP.eucJP/articles/ipsec-must/article.sgml b/ja_JP.eucJP/articles/ipsec-must/article.sgml index 85be9b017e..79be56d311 100644 --- a/ja_JP.eucJP/articles/ipsec-must/article.sgml +++ b/ja_JP.eucJP/articles/ipsec-must/article.sgml @@ -1,317 +1,317 @@ - - + + FreeBSD の IPSec 機能を独立検証するには

FreeBSD 3.0 における IPSec 機能を独立検証するには

IPsec をインストールした時, それがきちんと動作しているかどうか調べるにはどうしたら良いでしょう? ここでは, IPsec の動作を検証する実験的な方法を紹介します.

問題

まず, IPsec がインストールされていることを前提に話を進めます. IPsec がきちんと動作しているかどうか知るにはどうしたら良いでしょう? もちろん設定が間違っていればネットワーク接続が行なえないでしょうし, 接続できたということは設定が合っているからだ, という認識は間違っていません. 接続状態は Netstat コマンドで確かめることができます. しかし, それを独立して検証することは可能なのでしょうか?

-

最初に, 暗号に関連する次のような情報理論を考えます.

+

最初に, 暗号に使われている情報理論について考えます.

  1. 暗号化されたデータは, 一様に分布している. つまり, 各情報源シンボルは最大のエントロピーを持っている.

  2. 通常, 未処理のデータや圧縮されていないデータは冗長である. つまり, 各情報源シンボルのエントロピーは最大ではない.

ネットワークインターフェイスを入出力するデータのエントロピーを測定できると仮定すると, 「暗号化されていないデータ」と「暗号化されたデータ」の両者に, 違いを見ることができるはずです. このことは, パケットのルーティングが行なわれる場合の一番外側の IP ヘッダなど, データの一部が「暗号化モード」で暗号化されなかったとしても成立します.

MUST

Ueli Maurer 氏の "Universal Statistical Test for Random Bit Generators" ("MUST") は, サンプルデータのエントロピーを高速に測定します. これには圧縮と良く似たアルゴリズムが使われています. 文末に示すのは, 一つのファイル中で連続するデータ (最大 0.25 メガバイト) を測定するコードです.

Tcpdump

さて次に, 上記に加えてネットワーク上の生データを捕捉するための手段も必要になります. それを実現するプログラムに, "tcpdump" と呼ばれるものがあります. ただし, tcpdump を使うには, カーネルコンフィグレーションファイルにおいて bpf (Berkeley Packet Filter) インターフェイスが有効化されていなければなりません.

次のコマンド

tcpdump -c 4000 -s 10000 -w dumpfile.bin

は, 4000 個の生パケットを捕捉し, dumpfile.bin に記録します. この例のでは 10,000 バイト以下のパケットのみ記録されます.

実験

では, 実験してみましょう. まず, IPsec ホストと IPsec を使っていないホストの両方にネットワーク接続してください.

そしてパケットの捕捉を開始します.

次に, IPsec を使っている接続で "yes" という unix コマンドを実行します. これは, "y" という文字の連続データを出力するものです. しばらくしたらコマンドを停止させ, IPsec を使っていない接続に対して同じコマンドを実行します. こちらも, しばらくしたらコマンドを停止させてください.

ここで, MUST を捕捉したパケットに実行すると, 次のような出力が得られるはずです. この中で重要なのは, 期待値 (7.18) に対して, IPsec を使った接続が 93% (6.7), 通常の接続が 29% (2.1) という結果になっていることです.

% tcpdump -c 4000 -s 10000 -w ipsecdemo.bin
 % uliscan ipsecdemo.bin
 
 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 -----------------

注意

この実験は暗号化の理論が示すとおり, IPsec を使った通信では確かにペイロード中のデータに含まれるシンボルの生起確率が一様に分布する, ということを示しています. しかし, ここで示した実験ではシステム上の欠陥 (あるのかどうか知りませんが) を検出することはできません. ここで言う「欠陥」とは, たとえば暗号鍵生成や交換の不備や, データや暗号鍵が他人に見られていないかどうかといった問題, あるいはアルゴリズムの強度はどうか, カーネルのバージョンは合っているかといったことです. これらはソースを調べれば確かめることができます.

IPsec の定義

インターネットプロトコル セキュリティ拡張 (Internet Protocol security extensions) は IP v4 と IP v6 に適用され, IP v6 への実装は必須となっています. このプロトコルは IP (ホスト間) レベルで暗号化と認証を実現するためのものです. たとえば SSL は一つのアプリケーションソケット, SSH はログイン, PGP は特定のファイルやメッセージのみに対してそれぞれ安全性を提供しますが, IPsec は 2 ホスト間のすべての通信を暗号化します.

IPsec のインストール

ここでは FreeBSD 3.0 stable を想定しています.

  1. IPsec v0.04 をインストールして, カーネル再構築とインストールを行なう.

  2. 管理用のツール (たとえば ipsecadm) を実行し, 暗号鍵を配布 (もしくは Photuris を使って鍵交換) する.

  3. ネットワーク経路 (rt) を適切に設定する.

ipsecadm および rt を実行して IPsec トンネルを確立するための "ipsec_setup" スクリプトを作成しても良いでしょう. スクリプトは, 起動時に /etc/rc.local から自動で実行させることができます. ipsec_setup でトンネルを確立するには, 少なくとも 2 つの ipsecadm コマンドと, 1 つの rt コマンドが含まれている必要があるでしょう.

usr/src/sys/i386/conf/KERNELNAME

IPsec を実行するには, カーネルコンフィグレーションファイルに以下の行が含まれていなければなりません. これらの行を追加して config を実行し, カーネルの再構築とインストールを行なってください.

# The `bpfilter' pseudo-device enables the Berkeley Packet Filter. Be
 # aware of the legal and administrative consequences of enabling this
 # option. Heh heh. The number of devices determines the maximum number of
 # simultaneous BPF clients programs runnable.
 pseudo-device bpfilter 2 #Berkeley packet filter
 
 # IPSEC
 options IPSEC
 options "MD5"
 pseudo-device enc 1

Maurer's Universal Statistical Test (ブロックサイズ = 8 ビット)


 #include 
 
 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 < 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 < V; i++) {
     table[i] = 0;
   }
 
   for (i = 0; i < 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 < Q + K; i++) {
         j = i;
         b = fgetc(fptr);
 
         if (b < 0)
           run = 0;
 
         if (run) {
           if (table[b] > 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 < (int)(sum*8.0 + 0.50); i++)
       printf("-");
 
     printf("\n");
 
     /* refill initial table */
     if (0) {
       for (i = 0; i < Q; i++) {
         b = fgetc(fptr);
         if (b < 0) {
           run = 0;
         } else {
           table[b] = i;
         }
       }
     }
   }
 }]]>