/* diffie-socket.h: socket wrapper with key exchange and authentication - main file
   This has nothing to do with cryptography.
   Copyright (C) 1998 Paul Sheer

   This program 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.
 */

#ifndef _DIFFIE_SOCKET_H
#define _DIFFIE_SOCKET_H

#ifdef __cplusplus
extern "C" {
#endif

/* 
   HOW TO USE:

   Include this header file after including sys/socket.h to
   transparently turn all your ordinary sockets into secure sockets.

   By default the accept()'ing socket will allow both non-encrypted
   and encrypted connections. All programs that normally connect to
   the socket using ordinary tcp will continue to work. Client
   programs compiled with this library will then connect to the
   socket in encrypted mode using a diffie-hellman 1024 bit key
   exchange.

   Although server programs (using accept) can serve both encrypted
   and non-encrypted connections, client programs can only connect
   with encryption enabled. The client programs should set the flag
   ARC_SOCKET_FLAGS_CRYPTO_OFF to do normal connections. Client
   programs should have command-line options --secure, --no-secure
   to enable/disable secure connections, where these command-line
   options clear or set this flag.

   Server programs need not set any flags unless they specifically
   want to only accept encrypted connections.
 */

/*
   HOW SECURE IS THIS:

   This theoretically gives perfect, impenetrable security. The
   only part I am not sure of is my implementation of the p-NEW
   signature scheme. I have done it by the book, but I would
   still like someone else to go through my implementation.
   Programming bugs are not part of the `theoretically'.

   I spent a good deal of time looking through different
   encryption methods to find the best ones. The following
   paragraphs are probably paranoid views, but then thats all
   part of the fun of cryptography :-)

   DES is not secure. Triple-DES may be secure, but then
   Triple-DES is painfully slow. Neither can other block
   encryption techniques be trusted. RSA also cannot be trusted,
   because we don't know when some guy is going to come up with
   a better factorisation method. I also don't like techniques
   that dictate a key size.

   Many people use DES because they know that if someone ever
   does hack DES, they are able to say `well its not my fault
   because DES was the trusted standard'. This is not an excuse.
   DES has been around to long for large governments not to have
   hacked it already. The same goes for quite a few other
   encryption algorithms.

   Now because we don't like slow insecure block encryption, we
   have to use stream cyphers. Stream cyphers cannot work on
   packets because packets get lost, creating discontinuities.
   Stream cyphers can work over tcp because tcp is a stream. So
   we have to drop the idea of ip level encryption.

   I have implented a 12 * 12 version of the stream cypher in
   the file arc.c (I have never seen this used before because I
   doubt anyone before me has been this paranoid). This is a
   most secure cypher. Its also 10 times faster than DES and
   trivial to impliment.

   INSECURITIES:

   Non-linux system don't have a /dev/urandom device, so I can't
   get strong random keys. To get keys, I use various mutating
   results like getpid, time etc. (see get_random_chars) and
   hash the thing with md5 (another untrustworthy, but commonly
   used algorythm.)

   PROTOCOL SUMMARY:

   First the client sends a magic number to the server to tell it
   that it wants encryption. Then it calculates X = g^x mod p,
   where x is random, and sends X. Server recieves X, calculates
   Y = g^y mod p, where y is random, and sends back a reply magic
   number and then Y. Now both calculate k = g^(xy) mod p (client
   calculates k = Y^x mod p and server X^y mod p). That concludes
   the classic Diffie-Hellman key exchange. Encryption is now
   turned on with the key k. The the server then looks in
   /usr/etc/ssocket and get its public, y, and private, x, signature
   keys. (If it can't find them then it calculates y = g^x mod p,
   where x is random and is the private key, and y is the public
   key, and stores x and y in the appropriate files. (i.e. first
   time use of the library)) Then it sends y to the client. The
   client recieves y and checks in the users ~/.ssocket/
   directory for a file named that ip address, to verify the
   public key against the file, and hence that the server is who
   it claims to be. If the file does not exist then it creates it
   (i.e. first time connection). The server then signs the
   encryption key k with private key x to to produce r = k g^v
   mod p, s = v - r x mod q, where v is random, and q = (p - 1) /
   2 is also prime. r and s are sent to the client. The client
   recieves r and s and calculates m = g^s y^(r mod q) r mod p. m
   must equal k as verification of the servers identity. Normal
   tcp traffic then ensues with encryption enabled.

   WHAT THIS DOES NOT PROTECT AGAINST:

   First time connections: The first time you connect you do not
   know the public key of the server, so you could be given a
   fake public key while someone performs a man in the middle
   attack. You can prevent this by copying the servers public
   file to your .ssocket directory (calling it the dotted ip of
   the server) via some secure channel (secure = manually
   copying it with a stiffy disk.)

   If someone spoofs a server (masquerading as its ip address)
   and you connect to that ip, you won't have a public key in
   your .ssocket directory. It is then assumed that the server
   is a new server and a new public key file will be created.
   You will then unknowingly be connecting to an untrusted
   server. The socket library can have a callback set to ask you
   if you really want to connect if it finds it doesn't have a
   public key file. Use arc_socket_add_warning_callback() for
   this.

   User authentication: The protocol is meant to authenticate
   the server and prevent snooping of traffic. It fundementally
   offers user protection. After the last step in the above
   protocol it is up to a higher level protocol to ensure that
   users are you they claim to be. For instance, ftp, telnet,
   rlogin etc would all rely on their usual password
   authentication, albeit over a secure channel.

   Flood attacks???: The daemon that serves the connections can
   be hit sequentially at a high rate to give info on the types
   of random keys its generating.

   Note that the weekest links in security are:
   Number 1: Integration
   Number 2: Implementation
   Number 3: Protocol
   Number 4: Algorithm
   Number 5: Key size

   This library covers 5, 4, 3 and part of 2. But it in no way
   means that your client/deamon is going to be rock solid.

   WHY NOT SSL:

   (Correct me if I'm wrong about any of this.) One of the
   purposes of SSL is to provide negotiable encryption. The
   reason is because some encryption algorithms and key sizes
   might not be available to either party either because of
   licensing restrictions or because of legislation on key size
   or algorithms.

   Hence SSL is really there to provide insecurity rather than
   security.

   This implementation does not use RSA, was developed in South
   Africa (which has no cryptography laws), and is under the
   GPL. It can hence be used almost anywhere in the world.

   WOULD I TRUST MY LIFE THIS:

   No, but I would trust any of my banking transactions. This is
   of course only after it has been peer reviewed a bit to get
   rid of any bugs/implementation errors.

   (BTW We are using this code for a chain food store that needs
   to upload securely to its head office how many burgers it
   sold in every one of its stores. I think their burger sales
   will remain a secret ;-)

   FREESWAN:

   I have not really gone into how secure the swan
   implementation is. It obviously fails on systems where you
   can't patch the kernel. There may not really be any point in
   having a system that is more secure than Freeswan.

   AM I SAFE:

   Don't jump to the conclusion that you are unsafe just because
   you are not using the most paranoid algorithms available.
   Jump to those conclusions only after have researched a lot in
   cryptography.
 */

/* `arc' is an encryption method */

#undef accept
#undef connect
#undef rcmd
#undef send
#undef recv
#undef read
#undef write
#undef shutdown
#ifdef WIN32
#undef closesocket
#else
#undef close
#endif
#undef dup
#undef dup2

int arc_socket_accept (int sock, struct sockaddr *addr, unsigned int *addrlen);
int arc_socket_accept_fd (int fd);
int arc_socket_connect (int fd, struct sockaddr *addr, int addrlen);
int arc_socket_send (int s, const void *msg, int len, unsigned int flags);
int arc_socket_recv (int s, void *buf, int len, unsigned int flags);
int arc_socket_write (int s, void *buf, int len);
int arc_socket_read (int s, void *buf, int len);
int arc_socket_shutdown (int s, int how);
int arc_socket_close (int s);
int arc_socket_dup2 (int fd, int fd_new);
int arc_socket_dup (int fd);

#define accept		arc_socket_accept
#define connect		arc_socket_connect
#define send		arc_socket_send
#define recv		arc_socket_recv
#define read		arc_socket_read
#define write		arc_socket_write
#define shutdown	arc_socket_shutdown
#ifdef WIN32
#define closesocket	arc_socket_close
#else
#define close		arc_socket_close
#endif
#define dup		arc_socket_dup
#define dup2		arc_socket_dup2

#define ARC_SOCKET_FLAGS_PRIME		(0xFF)
#define ARC_SOCKET_FLAGS_PRIME_ERROR	(0)
#define ARC_SOCKET_FLAGS_PRIME_512	(1)
#define ARC_SOCKET_FLAGS_PRIME_768	(2)
#define ARC_SOCKET_FLAGS_PRIME_1024	(3)
#define ARC_SOCKET_FLAGS_PRIME_1536	(4)
#define ARC_SOCKET_FLAGS_PRIME_2048	(5)
#define ARC_SOCKET_FLAGS_PRIME_3072	(6)
#define ARC_SOCKET_FLAGS_PRIME_4096	(7)
#define ARC_SOCKET_FLAGS_PRIME_6144	(8)
#define ARC_SOCKET_FLAGS_PRIME_8192	(9)
#define ARC_SOCKET_FLAGS_PRIME_12288	(10)
#define ARC_SOCKET_FLAGS_PRIME_16384	(11)
#define ARC_SOCKET_FLAGS_PRIME_24576	(12)
#define ARC_SOCKET_FLAGS_PRIME_32768	(13)
#define ARC_SOCKET_FLAGS_PRIME_49152	(14)
#define ARC_SOCKET_FLAGS_PRIME_65536	(15)
#define ARC_SOCKET_FLAGS_PRIME_98304	(16)
#define ARC_SOCKET_FLAGS_PRIME_131072	(17)
#define ARC_SOCKET_FLAGS_PRIME_196608	(18)
#define ARC_SOCKET_FLAGS_PRIME_262144	(19)
#define ARC_SOCKET_FLAGS_PRIME_393216	(20)
#define ARC_SOCKET_FLAGS_PRIME_524288	(21)
#define ARC_SOCKET_FLAGS_PRIME_786432	(22)
#define ARC_SOCKET_FLAGS_PRIME_1048576	(23)

#define ARC_SOCKET_FLAGS_CRYPTO_OFF	(1<<8)
#define ARC_SOCKET_FLAGS_NONCRYPTO_OFF	(1<<9)


#define ARC_SOCKET_EXCHANGE_TYPE_DIFFIE	1

/* not supported yet */
#define ARC_SOCKET_EXCHANGE_TYPE_RSA	2
/* not supported yet */
#define ARC_SOCKET_EXCHANGE_TYPE_ELLIPS	3



void arc_socket_set_flags (unsigned int f);
unsigned int arc_socket_get_flags (void);
void diffie_add_functions (void);

extern int diffie_errno;

void arc_socket_add_warning_callback (int (*warn_callback) (char *, void *), void *);

/* errors */
char *arc_socket_error_string (int e);

enum {
    DE_NOERROR,			/* dummy */
    DE_HOSTSIGNDIR,		/* permission or other problem with hosts /usr/etc/ key directory */
    DE_HOSTSIGNPRIV,		/* permission or other problem with hosts private key file */
    DE_HOSTSIGNPRIVFMT,		/* format problem with hosts private key file */
    DE_HOSTSIGNPUBL,		/* permission or other problem with hosts public key file */
    DE_HOSTSIGNPUBLFMT,		/* format problem with hosts public key file */
    DE_MAGIC,			/* error reading magic number */
    DE_MYPUB,			/* error writing public key for dh key exchange */
    DE_PNEWVERIFY,		/* pnew signature scheme failed to generate a verified key */
    DE_PRIVATE,			/* something wrong with calculated dh private key */
    DE_PROTO,			/* error reading protocol version */
    DE_PROTOVERSION,		/* bad protocol version */
    DE_PUBSIG,			/* error sending or recieving hosts public signature */
    DE_READ,			/* error reading from socket */
    DE_REMOTPUB,		/* error reading public key for dh key exchange */
    DE_SIGNRS,			/* error reading or writing signed dh key */
    DE_TOHUGE,			/* a huge number somewhere was to big */
    DE_USERPUBFMT,		/* format problem with users public signature key file of a host */
    DE_USERPUBKEY,		/* users public signature key file of a host does not match received */
    DE_USERSIGNDIR,		/* permission or other problem with users signature key directory */
    DE_USERSIGNFILE,		/* permission or other problem with public signature key file */
    DE_USERSIGNVERI,		/* verified signed key does not match */
    DE_WRITE			/* error writing to socket */
};

#define DIFFIE_ARC_SOCKET_MAGIC		"dIffIe--HelLmaN\n"
#define DIFFIE_ARC_SOCKET_MAGIC_REPLY	"DIfFiE--hEllMan\n"
#define DIFFIE_ARC_SOCKET_MAGIC_LEN	16
#define MAX_FEASABLE_HUGE		(4096 / 8)

#ifdef WIN32

#define SCRIPT_ACCEPT		"\\ssocket\\accept.cs"
#define SCRIPT_CONNECT		"\\ssocket\\connect.cs"

#define KEY_DIR			"\\ssocket"
#define PRIVATE_KEY_DIR		"\\ssocket\\private"
#define PUBLIC_KEY_DIR		"\\ssocket\\public"
#define PRIVATE_KEY_FILE	"\\ssocket\\private/%d"
#define PUBLIC_KEY_FILE		"\\ssocket\\public/%d"
#define USER_KEY_DIR		"\\ssocket\\remote"

#else

#define SCRIPT_ACCEPT		SYSCONFDIR "/ssocket/accept.cs"
#define SCRIPT_CONNECT		SYSCONFDIR "/ssocket/connect.cs"

#define KEY_DIR			SYSCONFDIR "/ssocket"
#define PRIVATE_KEY_DIR		SYSCONFDIR "/ssocket/private"
#define PUBLIC_KEY_DIR		SYSCONFDIR "/ssocket/public"
#define PRIVATE_KEY_FILE	SYSCONFDIR "/ssocket/private/%d"
#define PUBLIC_KEY_FILE		SYSCONFDIR "/ssocket/public/%d"
#define USER_KEY_DIR		".ssocket"

#endif

#ifdef __cplusplus
}
#endif

#endif				/* ! _DIFFIE_SOCKET_H */





