          Copyright (c) mjh-EDV Beratung, 1996-1999
     mjh-EDV Beratung - 63263 Neu-Isenburg - Rosenstrasse 12
          Tel +49 6102 328279 - Fax +49 6102 328278
                Email info@mjh.teddy-net.com

    Author: Jordan Hrycaj <jordan@mjh.teddy-net.com>

   $Id: README.PROTOCOL,v 1.5 2000/01/02 18:55:55 jordan Exp $

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

   This library 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
   Library General Public License for more details.

   -----------------------------------------------------------------

This library implements an io-crypto layer to handle data tunneling.
The interface is reduced to using send/receive calls tranparently.


Modular architecture:

  +---------------------------------------------+
  |    Application                              |
  +---------------------------------------------+
               
  +----------------------+ 
  |    <peks>            |  
  +----------------------+

  +---------------------------------------------+ 
  |              <iostream>                     |
  +---------------------------------------------+

                           +--------------------+
                           |    <cbc-frame>     |
                           +--------------------+

                           +--------------------+
                           |    <cipher>        |
                           +--------------------+

  +---------------------------------------------+
  |   Operating System                          |
  +---------------------------------------------+

The idea behind the <iostream> module is, that registered calls 
to the io-functions are passed to the <cbc-frame> module, 
unregistered ones are passwd to the operating system.  As with 
SOCKS, the source code must be iostreamified (source code 
replacement by macro directives) in order to work.

When the session starts, any socket is opened, listened for and
accepted as usual.

Then the <peks> module does the inital handshake in order to get 
session keys exchanged and the <iostream> module initialized.

And that's all.  Io now runs transparently as un-streamified, 
before.  There might be some control settings available for
dynamically tuning the iostream parameters.  Such control 
functions are effectles unless registered (so they can always
remain in the source code.)


The cipher protocol(s):

After the (TCP-) channels has been opened by the client and
accepted by the server, control is simultaneously passed to 
the public key handshake modules <peks>. This is the initial
handshake between client and server:

       +--------+              |                +--------+
       | client |              |                | server |
       +--------+              *                +--------+
                               |
 (1)       <------------- public key ---------------
                               |
 (2) checks public key against *
     against the servers list  |
                               |
 (3) make client key at random *
                               |
 (4)       -- pub key encrypted client session key -->
                               |
 (5)                           *      generates random key for
                               |        the DH key exchange
                               |
 (6)       <---------- Diffie Hellman key -----------
                               |
 (7) generates random key for  *
       the DH key exchange     |
                               |
 (8)       ------- Diffie Hellman key exchange ------>
                               |
 (9)  calculates session key   *       calculates session key
     from the DH key exchange  |      from the DH key exchange
                               |
(10) makes new client key as a *      makes new client key as a 
     hash using the old client |      hash using the old client
      key and the session key  |       key and the session key
                               *
(11) installs client key for   |       installs client key for
    reading iostreamified data |      sending iostreamified data
                               *
(12)                           |      generates random server key
                               |
(13)       <------- iostreamified server key ---------
                               |
(14) makes new server key as a *      makes new server key as a
     hash using the old server |      hash using the old server
      key and the session key  |      key and the session key 
	                       *
(15) installs server key for   |        installs server key for
    sending iostreamified data |      receiving iostreamified data
                               *
(16) makes new session key as  |      makes new session key as
     a hash over all, session, |      a hash over all, session,
      server and client key    *       server and client key 
                               |
(17)       <<====== iostreamified key refresh ======>>
                               |
                               *
                               |
(18)       ------ iostreamified known plaintext ----->
                               |
(19)                           *      checks that plain text
                               |
(20)       <<===== iostreamified data transfer =====>>
                               |
                               *
                               |
                           untrusted
                          commnication
                            channel


Remarks:
 
 (1) The public key scheme is derived from El Gamal and implemented
    as \0 terminated ASCII-string:

        <idf> <p> <g> <g^a> <crc>

    where

      all the fields are separated by whitespaces

      <idf> ::= the text "peks/x.y:" denoting the current version x.y
                of the cipher protocol

      <p>   ::= a base 64 encoded prime

      <g>   ::= a base 64 encoded generator for the multiplicative
                group {x % p : x != 0} generated by p

      <g^a> ::= the base 64 encoded a-th power of g (mod p) for
                some (random) number a

      <crc> ::= a RIPEMD160 hash over the fields from left to right,
                separated by exactly one blank


 (2) Public keys are stored in a file as \n-terminated lines

        <host> <p> <g> <g^a> <crc>

    where

      all the fields are separated by whitespaces

      <host> ::= name or ip-address of the server host followed
                 by a colon ':'

      <p>, <g> and <g^a> are the same as in (1)

      <crc>  ::= a RIPEMD160 hash over the fields from left to right,
                 separated by exactly one blank


 (4) The client sends either a \0 terminated stop message . (and the
    dialogue stops completely, here) or the wrapped session as:

          <idf> <g^b> "A" <k * g^ab> <crc>

    where

      all the fields are separated by whitespaces

      <idf>      ::= the text "elg/x.y:" denoting the current version x.y
                     of the cipher protocol

      <g^b>      ::= the base 64 encoded b-th power of g (mod p) for
                     some (random) number b

      "0"        ::= the digit 0

      <k * g^ab> ::= the base 64 encoded number k, multiplied by the
                     number g^ab (mod p), where g^ab is calculated
                     as the b-th power of g^a (mof p) for some
                     some (random) number b

      <crc>      ::= a RIPEMD160 hash over the fields from left to right,
                     separated by exactly one blank


 (6) The Diffie Hellman key scheme is implemented as a \0 terminated 
    ASCII-string:

        <idf> <q> <h> <h^x> <crc>

    where

      all the fields are separated by whitespaces

      <idf> ::= the text "dhs/x.y:" denoting the current version x.y
                of the cipher protocol

      <q>   ::= a base 64 encoded prime

      <h>   ::= a base 64 encoded generator for the multiplicative
                group {x % p : x != 0} generated by p

      <h^x> ::= the base 64 encoded x-th power of h (mod q) for
                some (random) number x

      <crc> ::= a RIPEMD160 hash over the fields from left to right,
                separated by exactly one blank


 (8) The Diffie Hellman key scheme is implemented as a \0 terminated 
    ASCII-string:

        <idf> <h^y> <crc>

    where

      all the fields are separated by whitespaces

      <idf> ::= the text "dhr/x.y:" denoting the current version x.y
                of the cipher protocol

      <h^y> ::= the base 64 encoded y-th power of h (mod q) for
                some (random) number y

      <crc> ::= a RIPEMD160 hash over the fields from left to right,
                separated by exactly one blank

     
 (9) The Diffie Hellman session key is calculated as 

      h^xy = <h^x>^y = <h^y>^x


(10) The new client key is calculated as
 
      client key ::= RIPEMD160 (session key, client key)

    We need both, the Diffie Hellman key to make up a secure connection
    and the server key to verify, that the server that sent the public key
    also has the corresponding private key.  Also, if the server key has
    been compromised, the clinet->server connection is still secure because
    of the Diffie Hellman session key.


(13) Either direction of the full duplex data channel is encrypted 
    independently with different keys.  This makes it harder to collect
    data material for cryptanalysis.  See also (18), below.


(14) The new server key is calculated as

      server key ::= RIPEMD160 (session key, server key)

    The server key is not used, directly.  So if the server key has been
    compromised, the client<-server reverse connection is still secure 
    because of the Diffie Hellman session key.   See also (18), below.


(16) The new session key is calculated as

      session key ::= RIPEMD160 (session key, server key, client key)

    and used as a master key for both, sender and receiver.  Using a
    hashed key makes it harder to guess a weak random key.
    
(17) The cipher protocol usually will tranparently exhchange a new session
    key, once the master session session key has been set or changed.

(18) This verifies that step (17) has been done, correctly.
    
(20) All the data following are sent by a cipher block chaining method
    using some 64 or 128 bit block cipher. The cbc block cipher is 
    applied to full block frames with size a multiple of 8 or 16 bytes
    (for 64 or 128 bit block ciphers.) A block frame in non-threaded
    mode looks like
                                           <--- possibly compressed --->

              +-..-+--+--+-..-+---+- .. -+-  ... --+--+- .. -+--+-..-+--+
              |  LENX |  LENY | P | args |  padding   |  data   |  CRC  |
              +-..-+--+--+-..-+---+- .. -+-  ... --+--+- .. -+--+-..-+--+

               <- 4 -> <- 4 ->            <-- P&15 -->           <- 4 ->

	       <--------- encryption distance ------------------------->
               <------------ LENX ^ LENY ------------------------------>
               <------------ CRC DISTANCE ----------------------------->

    where (LENX ^ LENY) % 8 == 0 for 64 bit cbc mode, and (LENX ^ LENY) % 16
    == 0 for 128 bit cbc mode.  The current CRC is hashed while the last
    four bytes of the protocol block are filled with the CRC from the
    previous block.  
  
    This definition allows 8 and 16 bytes block sizes usable for 64 bits
    and 128 bits cipher block chaining mode.

    All numbers are stored in big endian.  
    
    When compressing is applied, for the sender it comes after the buffer
    is hashed (CRC calculation), and before the packet is encrypted.  After
    compressing, the LENY field is ajusted so that LENX ^ LENY is the real
    buffer length.  Then the buffer is padded at the end so that the total
    length becomes a multiple of the 8 or 16 bytes (depending on the cipher)
    block length.  Finally, Bit 4 of P is set (see commands, below).

    For the receiver, the compressed buffer is to be reconstructed in the
    reverse order.


    The value C = P & ~15 is reserved for embedded commands, the arguments 
    of follow immediately before the padding section, all four embedded
    commands can be sent together:

    command  argument           meaning
    -------  --------           -------
    0x80     2 bytes unsigned   channel id (useful in threaded mode, only)
    0x40     17 bytes           remote command execution
    0x20     4 bytes unsigned   set the maximal size of the data payload
    0x10     no args            compressed data, following

    The remote command execution argument defines a sub-command Q with at
    most 16 bytes argument data. There can only be one sub-command at a time:

   +---+--+--+--+--+- ... -+--+--+--+
   | Q | argument                   |
   +---+--+--+--+--+- ... -+--+--+--+
        <--------- 16 -------------> 

     Q   argument                    meaning
    ---  --------                    -------
     1   2 byte thread id            destroy thread corresponding to th id
     2   2 byte th id, 8 byte cookie create thread, name it with the th id
     3   2 byte thread id            possibly destroy thread with thread id
     4   4 byte pid                  destroy thread corresponding to pid
     5   4 byte pid                  possiblly destroy threads with pid
     6   4 byte pid                  assign process id to that thread
    10   8 or 16 byte key            change session key
    11   8 times short (2 bytes)     check my th id whether threads are alive
    12   4 times long (4 bytes)      check by pid whether threads are alive

   In threaded mode, the protocol block is extended by a leading tag which
   helps to quickly find the logic receiver channel. In this mode, the
   embedded command 0x80 (channel id) is always active.

                                   <------- possibly compressed ------->

   +-..-+--+--+-..-+--+--+-..-+---+- .. -+-  ... --+--+- .. -+--+-..-+--+
   |  COOKIE  | LENX  | LENY  | P | args |  padding   |  data   |  CRC  |
   +-..-+--+--+-..-+--+--+-..-+---+- .. -+-  ... --+--+- .. -+--+-..-+--+

    <-- 8 ---> <- 4 -> <- 4 ->            <-- P&15 -->           <- 4 ->

	       <--------- encryption distance ------------------------->
               <------------ LENX ^ LENY ------------------------------>
               <------------ CRC DISTANCE ----------------------------->

   Apart from the initial value, the current cookie is calculated from the
   previous protocol block by shifting right the most significant 4 bytes by
   4 spaces, and replacing the most significant 4 bytes by the LENX bytes of
   the previous block.  Finally, the resulting 8 bytes are hashed.

Was that it? 
jordan
