CIPE
****

CIPE (the name is shortened from Crypto IP Encapsulation) is a package for an encrypting IP tunnel device. This can be used to build encrypting routers for VPN (Virtual Private Networks) and similar applications.

         Copyright © 1996--1998 Olaf Titz. All rights reserved.

         This program including its documentation is free software; you can
         redistribute it and/or modify it under the terms of the GNU General
         Public License as published by the Free Software Foundation; either
         version 2 of the License, or (at your option) any later version.

         This program is distributed in the hope that it will be useful, but
         WITHOUT ANY WARRANTY; without even the implied warranty of
         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
         General Public License for more details.

         You should have received a copy of the GNU General Public License
         along with this program; if not, write to the Free Software
         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

         The author can be contacted through the electronic mail address
         Olaf.Titz@inka.de.

$Id: cipe.texinfo,v 1.3.4.3 1998/11/14 20:27:49 olaf Exp $

Introduction
************

Network layers and encryption
=============================

There are several different places where encryption can be built into an existing network infrastructure, corresponding to the different protocol layers:

 1. On the network level: Packets travelling between hosts on the network are encrypted. The encryption engine is placed near the driver which sends and receives packets. An implementation is found in CIPE.

 2. On the socket level: A logical connection between programs running on different hosts (TCP connection; transport or session layer in OSI) is encrypted. The encryption engine intercepts or proxies connections. SSH works this way.

 3. On the application level: Applications contain their own encryption engine and encrypt data themselves. The best known example is PGP for encrypting mail.

Low-level encryption as implemented with CIPE has the advantage that it can be made to work transparently, without any change to application software. In the case of encrypting IP packets, it can be built into IP routers which usually act as "black boxes" that only route traffic between hosts, the hosts themselves don't see at all how the routing works. So an encrypting router looks exactly like a non-encrypting one, without any difference to other hosts and applications. It can thus be used in places where software changes at higher levels are not feasible.

Low-level encryption has the disadvantage that it does not guard against intruders on a higher level, e.g. Trojaned applications, bug exploits in system software or rogue administrators "sniffing" on terminal devices.

IP routing and Virtual Private Networks
=======================================

A virtual private network (VPN for short) is a network (As CIPE is an IP routing application, this manual talks only about IP-based networks.) belonging to one organization, using its own address range, but overlayed on existing network infrastructure. IP-in-IP tunneling makes it possible to build IP-based VPNs on top of other IP-based carrier networks, such as the Internet. Encrypted tunneling guards against passive (sniffing) and active (faked message injection) attacks on the carrier network. The carrier network sees only encrypted data.

Depending on the choice of protocol, all information the original packets carry can be encrypted. This includes not only the actual (payload) data but also the TCP/IP headers, leaving no trace as to which addresses and services are actually used. Traffic analysis attacks, which attempt to gain useful information out of sniffing by "who contacts whom", are thus made unfeasible. An even more sophisticated technique to thwart traffic analysis employs the injection of dummy packets into the network which carry no useful information at all but are (at the carrier level) indistinguishable from real data packets.

IP routing in a VPN situation consists of the routing of the carrier network, which in most situations is just a standard Internet setup, and routing of the overlayed VPN. This is easiest when the address ranges of carrier and VPN do not overlap in any way. It is common for VPNs to use the 10.0.0.0/8 and 192.168.0.0/16 address ranges, which are not part of the Internet and thus do never conflict with actual Internet routing: any address in this range must be local to the organization using it. See Example 1, for a typical example.

The IPSEC standards define a set of protocols which can be used (among other things) to build encrypted VPNs. However, IPSEC is a rather heavyweight and complicated protocol set with a lot of options, implementations of the full protocol set are still rarely used and some issues (such as key management) are still not fully resolved. CIPE uses a simpler approach, in which many things which can be parameterized (such as the choice of the actual encryption algorithm used) are an install-time fixed choice. This limits flexibility but allows for a simple (and therefore efficient, easy to debug...) implementation.

How CIPE works
==============

CIPE encapsulates encrypted IP datagrams in UDP datagrams and sends them via the normal UDP mechanism. This is different from standard IPIP encapsulation. UDP was chosen because this way many different endpoints can easily be distinguished by port numbers, because an IP protocol number would warrant a formal registration, and because handling of UDP datagrams is easier than using a separate IP protocol number, especially in firewalled setups. Specifically, UDP can be handled by user-level applications such as a SOCKS5 relayer. See SOCKS.

A CIPE link always connects exactly two endpoints. In many ways, the link works like a PPP dial-up link. At present, each link has its own secret 128-bit key which has to be known by both ends (and nobody else). This link key (called static key in the protocol description) is used to negotiate a frequently changed dynamic key, which encrypts the actual data.

It is planned that future versions of CIPE will negotiate their keys via a public key mechanism, similar to the SSH package. This would remove the need for shared secret keys.

CIPEs software components
=========================

The CIPE package consists of a kernel module and a driver program. The kernel module does the IP packet handling: sending and receiving packets, encapsulation including encryption. It implements a network device which is mostly handled like any other network device. Configuration and the whole key exchange process is done by the user level program ciped.

ciped looks and behaves rather similar to pppd. In particular, opening and closing a CIPE device is tied to starting and ending a ciped process (one per device), the specification of options to the daemon mimics pppd's setup and ciped invokes scripts on opening and closing a device.

Notes on internals
==================

(This section is only relevant to readers who want to understand the source, not to the regular user.)

The module consists of an output driver, an input driver, the encapsulation routines and some stuff to keep it all together. The output driver is largely an adapted version of new_tunnel from the Linux distribution. Its actual packet sending is done via the kernel IP forwarding engine. This implies that (a) forwarding must be enabled in the kernel and (b) the encrypted packets, being UDP packets with the source/dest addresses given as "me" and "peer", are checked against the forwarding (as well as the output) firewall. (If it doesn't work for you, first make sure that your firewall rules let the packets pass!)

The input driver is an adaptation from the kernel UDP receiver. To activate it, ciped has to set a socket into a special mode with an ioctl call. This has to be a connected UDP socket. The ioctl_attach(2cipe) call replaces the socket's sendto(2) and recvfrom(2) operations with special versions that do decryption of traffic internally and only pass key exchange blocks to the user layer. The whole work of decrypting and rerouting incoming traffic is done inside a blocking recvfrom(2). This means that unlike normal IP forwarding, it is called from user mode and the needed CPU time is charged to the ciped process, although the data never passes into user mode. sendto(2) encodes the block as a key exchange block and sends it to the peer. The socket should not use read(2), write(2), select(2) or nonblocking mode (yet).

Before attaching the socket, the operational parameters of the device have to be set using a ioctl_setpar(2cipe) call. The key exchange process supplies keys to the kernel via ioctl_setkey(2cipe).

The netdevice can only be opened (configured "UP") if it has a controlling socket. When the controlling socket is closed, the netdevice gets closed. Conversely, closing the netdevice (with ifconfig(8)) closes the socket too. Closing deletes all information that is set by ciped, but not the statistics which still can be read from /proc/net/dev (which means they accumulate over consecutive ciped runs).

Installing the CIPE software package
************************************

The CIPE software package is available via

http://www.inka.de/~bigred/devel/cipe.html. It is distributed in a tar.gz file, currently about 65k in size. After unpacking the distribution, set the necessary parameters at the top of the Makefile and run make.

Prerequisites
=============

CIPE runs under Linux 2.0.12 through 2.0.33. Work is under way to make it run under 2.1 kernels. It crashes under 2.0.0; don't use that buggy kernel any more. It was developed for the i386 architecture; other architectures should work, but only with the IDEA algorithm (no C version of Blowfish included by now).

Make sure you have the sources of the running kernel installed (usually in /usr/src/linux). The version and configuration of the kernel sources must match the running kernel exactly, or else you risk building a module which crashes. After reconfiguring and rebuilding the kernel, don't forget to rebuild the CIPE module too. This applies to all externally compiled modules.

The kernel needs "IP Forwarding/Gatewaying" enabled in the configuration. It needs the urandom device available.

A suited version of the module utilities (modprobe and friends) needs to be installed. When in doubt, consult the documentation in the kernel source.

Look at the Makefile for configurable items:

  * CRYPTO: Select which crypto algorithm you want.

  * VERS: Leave this at 3, which is the current protocol version.

  * ASM: "i386" for using handcoded i386 versions of IDEA and Blowfish, or nothing.

  * DEFS: Set -DDEBUG for including debugging code (recommended).

  * OPT: At least -O is needed by the kernel code.

  * KINC: Point this to the kernel include tree. You can compile CIPE for another machine than the one you're compiling on, provided you have the destination kernel's include tree available.

  * KDEFS: The default flags must be present. SMP is now handled elsewhere, s.b.

  * SMP: Define this if you have an SMP kernel.

  * MODVERSIONS: Define this if your kernel has versioned symbols.

  * BINDIR, MODDIR: Where the two components (module and ciped program) will get installed.

Installation
============

A simple make command compiles everything. Compiler warnings should not occur. Do make install as root to install the software components in their final location. These are a kernel module, named according to the protocol version and encryption algorithm selected, and the driver program ciped.

You need to create a directory /etc/cipe which contains at least two files, options and ip-up. You can copy the files from the samples directory in the distribution here, and edit them to suit your needs. See Configuration.

If Compiling doesn't work:

There is a known problem in that the various 2.0.30 and 2.0.31 pre-releases disagree on whether they have a certain feature (SO_BINDTODEVICE), and detecting this version dependency via the version number is not foolproof. Apparently, since 2.0.32, this problem is resolved. If output.c doesn't compile, change the line

     #ifdef SO_BINDTODEVICE

to #if 1 or #if 0 as needed.

Running CIPE
============

Once installed, the CIPE software is run by loading the module and running the ciped daemon.

Loading the module
------------------

The kernel module is loaded into the kernel via the command

     modprobe modulename parameter=value...

The module name is cip followed by the protocol version and the first letter of the encryption algorithm. E.g. cip3b for version 3, Blowfish (the default). The device names which this module manages are the module name followed by a number, e.g. cip3b0.

The CIPE module accepts the following additional parameters:

  * cipe_debug=(number) --- Set the debugging level. The file cipe.h defines different debugging levels which are ORed. Set this to 0 if you don't need debugging output. Debugging output is emitted via kernel messages, which means it usually winds up in the syslog somewhere.

  * cipe_maxdev=(number) --- Set the number of channels this module manages. E.g. with cipe_maxdev=4 (which is the default) the devices cip3b0 through cip3b3 are available. Maximum is 99.

The module can be autoloaded via kerneld. Advanced users will recognize the following options in /etc/conf.modules necessary to make it work correctly:

     alias cip3b0 cip3b
     alias cip3b1 cip3b
     options cip3b cipe_maxdev=2 cipe_debug=0

Running the ciped daemon
------------------------

The ciped daemon must be run as root. (Do not make it setuid.) It takes as command line arguments an optional -o file parameter specifying an options file followed by any number of individual option arguments. See Specifying options.

Except in debugging mode, the daemon puts itself in the background and uses syslog(3) for logging messages. Normal operation causes no log messages except for errors and a notice when the daemon terminates.

Shutting down (with ifconfig(8)) a CIPE device terminates its ciped process, and vice-versa terminating a ciped closes the device. When a device is closed, its configuration parameters including all keys are erased, but the statistics are kept (they can be read from /proc/net/dev) and accumulate over several runs. ciped does not keep any keys in memory.

When the device comes up, ciped spawns /etc/cipe/ip-up with the parameters described in the sample version. It waits for completion of this script before data can be sent over the device. The script is called with standard input, output and error to /dev/null. It typically sets routes and does some logging. Likewise, when a CIPE device goes down, /etc/cipe/ip-down is invoked.

ciped will terminate when an error occurs. This includes a "connection refused" message from the peer, to be able to detect non-working peers. This default error handling implies that no data may be sent over a link unless both ends are up and running, or the first one to come up will go down again immediately. In particular, the "ping" command in the sample ip-up should not be activated on both ends of a link. This behaviour can be customized. See Error handling, for more details.

Configuration of the CIPE software
**********************************

Specifying options
==================

All configuration parameters are processed by the ciped daemon. It takes parameters from

 1. the default options file (/etc/cipe/options),

 2. an options file specified as -o file on the command line,

 3. single options given on the command line,

in that order. Which means, parameters on the command line override those from files, and parameters from an explicit options file override those from the default options file.

Options are one of the types: boolean, integer, IP address, IP address with port number. Booleans are default false and specifying them as option makes them true. IP addresses are given as dot-quad notation or domain names which can be resolved using gethostbyname(3). UDP or TCP addresses are given as ip:port, where the port is a number or a name resolvable by getservbyname(3).

The syntax for specifying options is name=value on the command line, and name value (one option per line) in the options file.

List of all parameters
======================

Name                Type         Required
device       string       yes          Name of the
CIPE device.
debug        bool         no           Debug mode:
Don't go background, use stderr instead of syslog.
(Independent of the kernel driver debug option.)
ipaddr       IP           yes          IP address
of the CIPE device.
ptpaddr      IP           yes          IP address
of the peer device (i.e. the CIPE device on the other end).
mtu          int          no           Device MTU
(default: ethernet standard MTU minus all necessary headers)
metric       int          no           Device
metric (not sure if this is used anywhere...)
cttl         int          no           Carrier TTL
value. If not specified or 0, use the payload packet's TTL. Default
recommendation is 64.
me           UDP          no           Our carrier
UDP address. If either IP or port are not given, the system picks one and
reports it via ip-up.
peer         UDP          yes          The other
end's carrier UDP address.
key          string       (yes)        The link key.
For security reasons, the key has to be set via an options file and
options files must be owned by root, unreadable by anyone else. The key
should be 128 bits in hexadecimal encoding. (To generate such a beast
from random, try ps -auxw | md5sum.)
nokey        bool         no            Don't
encrypt at all, just encapsulate in UDP. With this option, key is
not needed. This option is not tested well.
socks        TCP          no           Address
(port required!) of the SOCKS5 server. See SOCKS.
tokxc        int          no           Timeout
(seconds) for key exchange. Default: 10.
tokey        int          no           Dynamic key
lifetime. Default: 600 (10 minutes).
ipup         string       no           Script to
run instead of /etc/cipe/ip-up.
ipdown       string       no           Script to
run instead of /etc/cipe/ip-down.
arg          string       no           Argument
to supply to ip-up.
maxerr       int          no           Maximum
number of errors before ciped exits. See Error handling.

Working with SOCKS
==================

With the socks option, CIPE uses a SOCKS5 server for sending and receiving the encrypted data. Since this is UDP, SOCKS4 (which doesn't support UDP) can not be used. SOCKS5 has a number of authentication methods. CIPE can use either no authentication or Username/Password. (GSSAPI/Kerberos authentication is not supported because (a) I don't have the environment to test it, and (b) it can specify that UDP packets be encrypted with its own method, which is unnecessary and causes only additional load here, and (c) it makes the implementation much more complicated.) Username and password are taken from the environment variables SOCKS5_USER and SOCKS5_PASSWD.

The implementation is not based on a SOCKS library, don't attempt to link ciped with it.

When one end of a CIPE link uses SOCKS, the other one must run a CIPE version 0.5.1 or newer. Reason: as the IP and port number of the SOCKS5 relayer get known only at run time, and there is no way for the SOCKS-using part to get this information at all, it needs to determine its peer dynamically. Older CIPE modules don't have this capability.

When both ends use SOCKS (this is not tested), exactly one of them should have a ping in its ip-up script, as described in the sample ip-up.

ciped periodically checks whether the SOCKS server has closed the control connection. If the SOCKS server goes down, there is no way to recover without restarting the client (in this case, ciped). This is a limitation in the SOCKS5 protocol. See Error handling.

Error handling in ciped
=======================

When the remote ciped is down or not available, the local ciped will get a "connection refused" error. Older versions always exited on this error. This has proven impractical in some situations, so an extra option has been added: maxerr determines how many network errors ciped will tolerate before exiting. This counter is reset when the connection proves OK (more precisely: when a key exchange packet is received). The default for maxerr is 8, like the non-changeable default in version 0.5.1. A value of -1 will cause ciped to ignore any network errors. In this case, it can only be brought down manually.

Error handling for SOCKS is independent of this option, however. When an error occurs on the SOCKS control connection (e.g., the SOCKS server goes down), ciped will exit. This behaviour is mandated by the SOCKS5 protocol.

Usage examples
**************

Here are some examples on how to design a network structure with CIPE and configure the devices accordingly.

General tips
============

  * The IP address of a CIPE device and it's UDP carrier must be different. Chose a transit network (e.g. 192.168 address) for the CIPE devices if these don't fit into existing structures.

  * The route to the UDP carrier ("peer" address) can not go through the CIPE device. If both are on the same route (e.g. both are on the same network, IP-address-wise), add a host route to the "peer" address through the right device or gateway.

  * The route add -host $5 dev $1 in ip-up is required. Without it the link won't work. This also means the ip-up script itself is mandatory.

  * Routes through a CIPE device should be set only in the ip-up script. Use case selections on $1 or $5 if you have several CIPE links. Use route add ... gw $5, not route add ... dev $1. Remember that Linux deletes any routes through a device when this device goes down.

  * If you have a default route, the addresses reachable via the CIPE link are routed via the default when the link is down. This can defeat the purpose of an encrypted link. To guard against this, set a reject route to the affected addresses with higher metric in the system startup script.

  * On a system running gated, gated is the only thing responsible for setting any routes and the routes through the CIPE devices belong in gated.conf as static routes, or are to be set via routing protocol. To gated, a CIPE link looks and behaves exactly like a dial-up link. It is strongly recommended to put gdc interface in ip-up as well as ip-down to tell gated about status changes. Otherwise, gated could get confused if a link goes down and up in short succession.

  * The configuration of both ends of a link is symmetric. One side's ipaddr is the other's ptpaddr, and one side's me is the other's peer. Since CIPE 0.5, peer is picked up dynamically and the real peer may be different from that set in the config file (but this config item must still be present, it should specify the other end's reverse as a reasonable default).

  * Always use different UDP ports for different links. For maintaining clarity, it helps to use a univeral numbering scheme like either "link 1 has port 21001 on both ends, link 2 has port 21002 on both ends..." or "cip3b0 has port 22000, cip3b1 has port 22001..."

  * When designing a network structure, draw the CIPE links as if they were SLIP/PPP links. Build the routing with these links enabled. Then look at the picture as if the CIPE links weren't there, so you can see the routing needed for the UDP adresses.

Example 1
=========

This basic example shows how to connect hosts and networks with unofficial network numbers through the Internet. Uses for this are classic VPN setups:

 1. Connecting two unofficial subnets through an Internet link

 2. Connecting a branch office to the head office through a one-address dialup

 3. Connecting a mobile host with varying access points

                    Internet               Internet
                       ^                      ^
                       |                      |                           hostz
                       |ppp0                  |eth1                  200.0.24.3
                       |200.0.24.65           |200.0.24.1                     |
          +---------routera                routerb         eth0 200.0.24.1    |
          |    eth0        \_ _ _ _ _ _ _ _/      \---------------+-------+---+
          |  10.0.1.1   cip3b0         cip3b0      eth0           |       |
        hosta           10.0.1.1      10.0.2.1     10.0.2.1       |       |
      10.0.1.88                                                hostx   hosty
                                                            10.0.2.5  10.0.2.6

As can be seen from the picture, a CIPE device and another network device can have the same IP address if there are no overlapping routes between them.

The CIPE devices are configured like this:

routes in ip-up10.0.2.0/24 gw 10.0.2.110.0.2.0/24 gw 10.0.2.1
  routera              routerb
  cip3b0               cip3b0
ipaddr              10.0.1.1             10.0.2.1
ptpaddr		  10.0.2.1		  10.0.1.1
me		  200.0.24.65:9999	  200.0.24.1:9999
peer		  200.0.24.1:9999	  200.0.24.65:9999
static routes	  10.0.1.0/24 dev eth0    10.0.2.0/24 dev eth0
  default dev ppp0        200.0.24.0/26 dev eth0
                          default dev eth1
routes in ip-up     10.0.2.0/24 gw 10.0.2.1
10.0.1.0/24 gw 10.0.1.1

For case 3, assume routera to be the mobile host, think of eth0 missing and ppp0 having a dynamic address. The routerb config remains unchanged. For routera simply omit the eth0 stuff. routerb picks up its peer dynamically. This even works when routerb is plugged behind a firewall and has to rely on a SOCKS5 server for outside access. (Yes, this can be used to punch holes into firewalls. No, it's not my intention to do anything about it. Local policy issues have to be dealt with locally.)

CIPE protocol description
*************************

     This chapter is copied verbatim from the earlier documentation texts
     and will be Texinfo-ized later. The text assumes some familiarity with
     cryptography basics.

The primary goal of this software is to provide a facility for secure (against eavesdropping, including traffic analsyis, and faked message injection) subnetwork interconnection across an insecure packet network such as the Internet.

1. Overview

This protocol was designed to be simple and efficient, and to work over existing communication facilities, especially by encapsulation in UDP packets. Compatibility with existing protocols such as the IPSEC RFCs were not a concern. The first test implementation was done entirely on the user level, while the now published one consists of a kernel module and a user level program.

The CIPE model assumes a fixed link between two peers which exchange datagrams (packetwise, not necessarily reliable). The most common way of implementing such a thing is sending UDP messages between them. (Another would be encapsulation in PPP, etc.)

Nothing that can be parameterized is inside the scope of this protocol and implementation. This is delegated to either prior arrangement or a yet-to-be-defined application level protocol. Most notably, this involves exchanging a shared secret key by now, and it involves choice of encryption algorithm.

The CIPE protocol consists of two parts: Encryption and checksumming of the data packets and dynamic key exchange.

2. Packet encryption

Each IP datagram is taken as a whole, including headers. It is padded at the end with zero to seven random octets so that the total length in octets is congruent three modulo eight. The padded packet is appended with one octet of the value P described below and the CRC-32 over the packet built up so far, up to and including P. (This makes the complete packet length a multiple of eight octets.)

This packet is then encrypted through a 64-bit block cipher in CBC mode with an IV as described below using either the static or the sending dynamic key of the outbound interface (for definition of keys see below). The default cipher algorithm is IDEA. The current implementation also supports Blowfish with 128 bit key.

The encrypted packet is prepended with the IV block. The highest order bit of the first octet of the IV is zero if the static key is used, one if the dynamic key is used. The remaining 63 bits are random, but the first 15 of them should not be all zeros (i.e. an IV/packet that starts with hex 0000 0000 or 8000 0000 is not allowed). Such packets are reserved for later protocol extensions.

The CRC is over the polynomial

     X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0

and represented in network byte order.

The value P is given as follows: bits 6,5,4 indicate the length of the padding between the original packet end and P. Bits 2,1 are a type code, indicating which kind of packet this is. The remaining bits 7,3,0 are reserved and must be zero.

The type codes are: 00 - data 01 - key exchange 10 - reserved 11 - reserved

For decryption, first check the highest bit of the first octet and use it to select the key. Decrypt the packet, calculate the CRC over the packet minus the last four octets, compare that with the last four octets. If valid, strip off the last octet as value P, strip off the padding as given by bits 6,5,4 of P and process the packet as indicated by bits 2,1 of P.

3. Key exchange

Every interface is associated with a static key, a sending dynamic key and a receiving dynamic key. (An interface is an endpoint of a connection, which may use protocols like UDP for transport but for the purpose of CIPE are always point-to-point links.) On startup, only the static key is valid. Encryption uses the static key if and only if the sending dynamic key is invalid. The value 0 (all bits zero) for the static key is reserved for future extensions and should not be used.

The dynamic key is set by a dialogue procedure involving messages with type code bits 01. These are encrypted just like above. The packets consist of a type octet followed by protocol data followed by a random amount of padding random data, so that the packet is at least 64 octets long. A key consists of 16 octets, a key CRC is the CRC-32 over the key, transferred in network order.

The following messages exist:

NK_REQ: Type code 1, no data: Requests the peer to immediately start a key negotiation (send NK_IND). This should be sent when a packet is received encrypted with a dynamic key but no dynamic receive key is valid. (Which can happen when the receiving side of a connection is rebooted while the sending side remains running.)

NK_IND: Type code 2, data is new key followed by key CRC. Specifies a new sending dynamic key for this sender. Requests the peer to immediately answer with NK_ACK.

NK_ACK: Type code 3, data is CRC of the previously accepted key. Confirms receipt of NK_IND.

The key negotiation procedure normally runs as follows: The sender sends a NK_IND with the new key, then invalidates its own sending key. Upon receipt of NK_IND, the receiver starts using this key as its receiving key and sends a NK_ACK. When the sender receives NK_ACK, it starts using the new key as its sending key. If either of NK_IND or NK_ACK is lost in transmission, no new key will be used. The sender should send a new NK_IND (with new key) if no matching NK_ACK is received within a reasonable amount of time (current specification: 10 seconds).

If any of the checksums contained in the key negotiation data mismatches the contained or stored key, this packet is ignored and no further action taken.

A sending dynamic key should be invalidated after being used for a certain period of time or amount of data and a new NK_IND sent. The process is symmetric and both sides act independently for their own sending key. The dynamic key lifetime should not exceed 15 minutes and the amount of data sent using one dynamic key should not exceed 2^32 packets.

4. Security considerations

The packets that actually get transmitted don't carry any usable information related to the original IP datagram other than its length, padded to a multiple of 8. This should effectively guard against most aspects of traffic analysis. The only information visible prior (attempt) to decrypting the packet is the bit that tells whether the static or dynamic key was used. Because the static key has a potentially long lifetime it is expected to be used as rarely as possible. It is normally used only in the short period of time during a key exchange. The dynamic key is changed often. These precautions are there because the application is prone to known and chosen plaintext attacks and the intention is to inhibit feeding of large amounts of data through one key.

Because the type code and padding length are encrypted with the packet, they can not be deduced from the ciphertext. Especially, it is not possible to determine whether the packet is a data or key exchange packet. (Usually, the last packet of a sequence of dynamic key packets followed by a sequence of static key packets is a NK_IND, but the NK_ACK and a possible second NK_IND can't be guessed this way, so there is no provision to tell whether the key exchange succeeded. However, this is a small but real weakness.)

The CRC serves as a check whether the encryption key was valid - i.e. some sort of signature for authenticity of the packet. Additionally, data packets should still have to form valid IP headers (with their own 16-bit checksum) and key exchange packets carry their own checksum as defined above.

IP packets carry some known or easily guessable plaintext in certain positions of their header. Potential exploitation of this fact should be mitigated by the limited key usage described above. The use of a random IV for each packet means at least that identical (retransmitted) packets encrypt to different ciphertexts.

The protocol gives only limited protection against replay attacks. A packet remains valid as long as the key it is encrypted with remains valid. However, active exploitation is unlikely as the packet carries no indication of its meaning. (Except for the note about sequences and NK_IND above. Replay of NK_IND could be dangerous. Possible remedy: store the last N accepted key CRCs [for large-ish N] and refuse to accept NK_INDs with the same CRC as an already stored one.)

Denial of service attacks are possible e.g. by sending large amounts of bogus packets, which should affect performance only. A vulnerability against disruption of the key generation process exists if the sender is overrun with bogus packets so that it fails to process the NK_ACK, effectively being forced to use its static sending key for a prolonged period of time. A possible way out of this problem is to stop sending data completely after a long burst of static key sends, sending only NK_INDs and resuming only after a valid NK_ACK has been processed. Then this attack would become a simple denial-of-service.

5. Practical test, Conclusion

The mentioned prototype implementations, one on the user level and one as a kernel module, have been in use for several months now on a live network, where they provide a transparent connection between subnetworks through an insecure transit network based on UDP encapsulation. This does work flawlessly. However, it is too early to draw final conclusions about the feasibility of this approach.

It is planned to replace the simple secret key based key exchange process described above by a signed Diffie-Hellman scheme, which would eliminate the need for secret keys.

Odds and ends
*************

  * Ideas and code for this project came from various parts of the Linux 2.0.12 kernel, most notably the ipip protocol, the new_tunnel driver, and the udp protocol.

  * NOTE: This software contains a data encryption facility. Use of it is restricted by law in some countries including France and Russia. In the United States of America it is not allowed to export such systems without special permission. The IDEA algorithm included herein is patented and subject to licensing conditions at least in parts of Europe and America (see http://www.ascom.ch/systec).

  * To Do list for future development:

       - Add C version of Blowfish algorithm.

       - Profiling and optimization for speed. Check C implementation of IDEA for possible optimization.

       - Make IDEA run in constant time to harden against timing attack? This would impose a serious performance penalty. It is at least possible in C and i486 and higher; probably not for the i386. The Blowfish algorithm always runs in constant time.

       - Test various combinations of crypto algorithm and implementation selected.

       - Implement all of the attack protections outlined in the protocol chapter. (Keeping log of recent keys is implemented.)

       - Implement dummy packet generation.

  * There is a mailing list for CIPE users and development. To subscribe, send mail to majordomo@inka.de containing the line

          subscribe cipe-l

     in the message body. Please subscribe before posting to the list.