``Why encrypt ident/TAP replies ?''
Damien Doligez
1994.02.22


This text is a companion to ``Why TAP?'' by Daniel J. Bernstein.
I will explain the reasons why your ident server should encrypt its
replies before sending them.

This is written from the point of view of a system administrator
who wants to install an ident server.  The local machine is the machine
running the ident server, and the remote machine any machine on the
Internet that keeps a log of ident replies from the local machine.

This starts as a structured document and ends in random comments
and implementation remarks.


Problems with ident.

The ident protocol, as implemented by pidentd return a cleartext
identification of the user.  This approach has the following problems:

1. The remote administrator is tempted to interpret the ident logs
   without asking the local administrator.  Everybody is supposed
   to know that ident replies are only meaningful to the local
   administrator, but in the real world, the remote administrator
   will forget that, especially if the ident data is mixed with
   data from his own machines (which is almost always the case).

2. Any user on the remote system can call the local ident server
   and collect login names for guessing passwords, and usage
   patterns.

3. The remote administrator might be malevolent and lie to you about
   the contents of his ident logs.

4. Some network attacks on the ident protocol have been described
   on Usenet (comp.security.*).  They involve intercepting ident
   requests and replying with bogus information, from another host
   on the network, with forged IP packets.


The crypto solution.

Dan Bernstein writes:
>An easy solution to [problems 2 and 3] is to encrypt your usernames
>(along with a timestamp, perhaps, though this defeats the selective
>blocking application outlined in the next section) in a secret key.

This also solves problem 1, but it is not a complete solution to
problems 3 and 4.  If you only encrypt the date and user ID, you
give to the remote administrator a piece of data that proves
that the user had some active connection at that date.  The remote
administrator could still lie about what machines were involved
and what ports the connection used (was it finger or telnet ?)

And a network hacker could easily acquire such a piece of data
(e.g. via network sniffing) and use it to spoof your ident server.

And if you only encrypt the user ID (or user name), the situation
is even worse.  It is quite easy in this case to guess (by simple
traffic analysis) which user is associated with a given encrypted
user ID, and then encryption becomes useless.


My solution is to encrypt a packet of data that contains:
- The date
- The user ID
- Both machine addresses
- Both port numbers.

Then the piece of data becomes a proof that that user had an active
connection at that date, between these machines and with these port
numbers.

Problem 1 is solved by forcing the remote administrator to ask you
to decrypt the data.

Problem 2 is solved by making the data unuseable except by yourself.

Problem 3 and 4 are solved by making the piece of data self-contained
and unforgeable.

The biggest problem with this encryption is that the selective blocking
described by Dan Bernstein becomes impossible.  An other aspect of
this problem is that simple measures to counter SMTP forgery (echoing
his user ID back to the SMTP cracker) is also impossible.  But
identification of the hacker is still possible, with the help of the
local administrator.


Implementation.

The packet of data is a 24-byte record with the following layout:

block  bytes  contents
  1      4    checksum
         2    random
         2    user ID
  2      4    date
         4    local IP address
  3      4    remote IP address
         2    local port number
         2    remote port number

The plaintext is divided in three 8-byte blocks p0, p1, p2 and encrypted
into three 8-byte blocks of cyphertext c0, c1, c2 as follows:

  c0 = E (p0)
  c1 = E (p1 ^ c0)
  c2 = E (p2 ^ c1)

Where E is DES with a secret key.  The secret key is stored in a file
only readable by root on the local machine.

This is essentially CBC mode, without an initialization vector.
The block chaining is used to prevent replacement of one block from
another packet.  Replacing c0 will garble the decrypted p1;
replacing c1 will garble the decrypted p1 and p2; replacing c2 will
garble the decrypted p2; replacing c0 and c1 will garble p2;
replacing c1 and c2 will garble p1; and replacing c0 and c2 will garble
p1 and p2.  The checksum is here to ensure that the right key was used
for decrypting and that the packet was not tampered with.

The decryption program is a filter that will read stdin and copy
it to stdout, replacing any encrypted block with the corresponding
decrypted information.  The decryption program uses the same key file
as the encryption.  The file may contain several keys.  The encryption
will use only the first one, but the decryption program will try each
key in turn.  This way, you just have to add a new key at the beginning
of the file whenever you want to change the key (you should change your key
often enough, depending on the level of confidentiality that you want).

Be aware that a brute-force plaintext attack is very easy to set up
against this system, and that finding the key for one packet will
unlock all other packets encrypted with the same key.  Changing
the key often will force the attacker to redo the brute-force attack
again and again.

A key is a line of text (maximum 1023 characters) which is hashed into
a 56-bit DES key.  It might be a good idea to include the date in
each line of the key file.  The decryption program will only try
the first 1024 keys from the key file.  Be aware that having many keys
in this file will slow down the decryption considerably.  If this
becomes a real problem, I could implement a simple hashing scheme to
solve it.

There are a number of holes in Unix that allow users to read (parts of)
any file readable by group kmem.  (The "ps" command is one such hole.)
My advice is to make the key file only readable by root, and make pidentd
run as root.  The probability of a hole in pidentd itself is pretty small.

WARNING:  I am not a specialist in cryptology.  It may well be the case
that the absence of an IV in the CBC encryption weakens the encryption
considerably.  I do not guarantee any level of confidentiality whatsoever.
Go ask sci.crypt if you want some serious answers.

The DES implementation and hash function used are from the libdes
library, written by Eric Young (eay@psych.psy.uq.oz.au) and available
(among other sites) from ftp.funet.fi.

The code is not too well integrated with the rest of pidentd, and
somebody should change the man page to document the "-C" option
for encryption and the format of the key file.
The code is endian-independent, but I'm not sure it would work on
a 64-bit machine.

Maybe I should add an option to the decryption program for specifying
an alternate key file.
