CanCode.c CanCode.h Client.c CRC.c CRC.h Crypto.c Crypto.h DateTime.c DateTime.h ErrorTxt.c ErrorTxt.h HiRes.cpp HiRes.h Server.c Try.cpp WriteCon.c WriteCon.h


AES Encrypted UDP Client/Server

The AES Encrypted UDP Client/Server implements a minimum case server on the local PC and a Client that talks to it. This is a Request/Response protocol - i.e. for every request there is a response. Each request and every response is encrypted using the Rijndael Advanced Encryption Standard (AES) with a random initialization vector and cypher block chaining. With both the client and server residing on the same PC, I have seen from 3,000 up to 15,000 request/response pairs per second, so this protocol can be very fast. The speed that you will see varies considerably depending on the hardware you are running and the software that is running on it.

Because of my ignorance about export control on encryption code, I am NOT making the AES code directly available. Sorry about that. You can, however, download a zip file, "aes-src-16-04-07.zip", and extract aescrypt.c, aeskey.c, aestab.c, aes.h, aesopt.h, aestab.h, brg_endian.h and brg_types.h directly into the project directory. Additional information about Dr. Gladman's cryptography code can be found here.

This code is provided in three parts:

  1. Server - This is an Example AES Encrypted UDP Protocol Server.
  2. Client - This is a Command Line Client to talk to the Server with.
  3. Try - This is an AES Encrypted UDP Protocol Testing and Timing Program.

Encryption Method Used

Both the requests and responses are sent embedded in UDPPACKET packets. This structure contains:

  1. the message sequence number (this keeps the response associated with the request).
  2. the size of the entire packet (this includes the checksum). This number allows us to determine the size of the transmitted payload.
  3. the date and time. The date is the Gregorian Day Index and the time is the number of milliseconds since midnight. This number is used to check that the time is within the specifed differential (i.e. that the response is within 5 seconds of the request). This limits a "Replay Attack" since messages that are mis-synchronized are ignored and discarded.
  4. the payload (either a request or a response).
  5. the whole packet is terminated with a CCITT CRC32 checksum. The checksum is computed before encryption. This assures, on the receiving side, that the packet was correctly decrypted since it is checked afterward.

This structure is what we want to send to the other system. It will be embedded in an array of 30 Encryption Blocks, each 16 byte long. The maximum number of encryption blocks is dictated by the maximum size of a UDP packet (limited to 512 bytes by external devices) minus the 20 byte IP Header and the 8 byte UDP Header (512 - 20 - 8 = 484 and 484/16 = 30.25).

The first encryption block is a 16 byte, random initialization vector. It is included so that repeated transmission of identical raw data blocks generates unique sequences of data. The remaining blocks are filled with the payload. These encryption blocks are Cipher-Block Chained together and then AES encrypted.

Notes and Comments

The encryption of a communication stream adds authentication to the incoming requests since the requester has to have the encryption key which acts as a password. This only gives you one-factor authentication. It is your responsibility to protect the encryption key and to change it regularly. It is best to require physical access to the client or server system to set a new encryption key and procedures to force resetting the key periodically and re-keying if there is even the least suspicion that the key has been compromised.

The server only recognizes a fixed set of incoming requests. Any incoming attack must be perpetrated using these commands. This limits the amount of damage that can be done to what can be achieved using this command set. Viruses and worms usually rely on executing code on the target machine. It is up to you to not implement anything that will allow foreign code to run on these systems. Don't open a hole for an attacker to use.

Do reasonableness checks on command requests and don't honor requests that you know will cause damage. One of the benefits of using an automated system is the layer of protection that it gives from yourself. Checking that interlocks are satisfied before operating equipment is one example of this. If you can protect the user from himself, do so. This also helps protect a system from malicious activity.


CanCode.h

/***************************************************************************************
* Copyright (c) 2007 - 2010 Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384_5342 *
***************************************************************************************/

#if !defined(AFX_CANCODE_H__15154517_D16D_4C9D_AD8D_26FCAAB8812F__INCLUDED_)
#define AFX_CANCODE_H__15154517_D16D_4C9D_AD8D_26FCAAB8812F__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif   /* _MSC_VER > 1000 */

#ifdef  __cplusplus
extern "C" {
#endif

#define CONST const

typedef char CHAR;
typedef CONST CHAR * LPCSTR, * PCSTR;
typedef unsigned long DWORD;
typedef unsigned int size_t;

extern unsigned long CanCode  ( LPCSTR strString );
extern void          Uncan    ( DWORD dwCanCode, char * pszAlphanumeric, size_t cbAlphanumeric );

#ifdef  __cplusplus
}
#endif

#endif   /* AFX_CANCODE_H__15154517_D16D_4C9D_AD8D_26FCAAB8812F__INCLUDED_ */

CRC.h

/*********************************************************************************************
* Copyright (c) 2002 - 2010 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
*********************************************************************************************/

#ifndef _CRC_H
#define _CRC_H

#ifdef _MSC_VER

#if _MSC_VER >= 1000
#pragma once
#endif   /* _MSC_VER >= 1000 */

#ifdef TRACE_HEADERS
#pragma message ( "NOTE:  Included header file:  \"" __FILE__ "\"" )
#endif   /* TRACE_HEADERS */

#endif   /* _MSC_VER */

/**********************************
* Windows-NT Compatiblity Defines *
**********************************/

#ifndef DWORD
typedef unsigned long int DWORD;
#endif   /* DWORD */

#ifndef BOOL
typedef int BOOL;
#endif   /* BOOL */

#ifndef _SIZE_T_DEFINED
typedef unsigned int size_t;
#define _SIZE_T_DEFINED
#endif   /* _SIZE_T_DEFINED */

/**********************
* Function Prototypes *
**********************/

#ifdef __cplusplus
extern "C" {
#endif   /* __cplusplus */

/* Function Prototypes for Functions in CRC.c */

extern unsigned long CCITT32CRC  ( const unsigned long ulAccumCCITT32CRC, void const * lpDataBuffer, const unsigned int cbDataBuffer );
extern void          PutCRC32    ( void * lpulCRC32, unsigned long ulCRC32 );
extern BOOL          SetCRC32    ( void const * lpDataBuffer, const size_t cbDataBuffer, DWORD * lpdwCRC32 );
extern BOOL          ChkCRC32    ( void const * lpDataBuffer, const size_t cbDataBuffer, DWORD * const lpdwCRC32 );

#ifdef __cplusplus
}
#endif   /* __cplusplus */

#endif   /* _CRC_H */

Crypto.h

/************************************************************************************************
*                                                                                               *
* Copyright (c) 2009 - 2010 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342    *
*                                                                                               *
*  This code implements the AES encryption,                                                     *
*                                                                                               *
*  The AES (Rijndael) Encryption code comes from:                                               *
*                                                                                               *
*     http://fp.gladman.plus.com/cryptography_technology/rijndael/                              *
*                                                                                               *
************************************************************************************************/

#if !defined(_SERVER_H_2A8C2B85_C3DF_4CDD_8509_F905E65235EA)
#define _SERVER_H_2A8C2B85_C3DF_4CDD_8509_F905E65235EA

#if _MSC_VER > 1000
#pragma once
#endif /* _MSC_VER > 1000 */

#ifdef TRACE_HEADERS
#pragma message ( "NOTE:  Included header file:  \"" __FILE__ "\"" )
#endif   /* TRACE_HEADERS */

#define AES_MAX_UDP_BLOCKS 30                            /* The Maximum Number of AES Blocks in a UDP Packet                  */
#define AES_BLOCK_LEN      16                            /* The Length of the AES Transfer Block                              */

#ifdef  __cplusplus
extern "C" {
#endif

extern unsigned long g_ulErrors;                         /* Debug Error Counter                                               */

typedef unsigned int u_int;
typedef u_int        SOCKET;

struct sockaddr_in;
struct sockaddr;

typedef struct sockaddr_in SOCKADDR_IN;

extern const size_t  g_cbMaxAESEncryptedUDPPacketSize;

extern void    InitCrypto                    ( void );

extern void    GetTimeNow                    ( long * plnDate, long * plnTime );

extern size_t  SvrPutAESEncryptedUDPPacket   ( unsigned int uUDPSocket, DWORD dwSequenceNumber, struct sockaddr_in * psinUDPClient, unsigned int cbsinUDPClient, void * pvBuffer, unsigned int cbBuffer );
extern size_t  SvrGetAESEncryptedUDPPacket   ( unsigned int uUDPSocket, DWORD * pdwSequenceNumber, struct sockaddr * pSinUDPClient, int * pnSinUDPClient, void * pvBuffer, unsigned int cbBuffer, BOOL fSynchTime );

extern size_t  CntPutAESEncryptedUDPPacket   ( unsigned int uUDPSocket, DWORD dwSequenceNumber, void * pvBuffer,unsigned int cbBuffer );
extern size_t  CntGetAESEncryptedUDPPacket   ( unsigned int uUDPSocket, DWORD * pdwSequenceNumber, void * pvBuffer,unsigned int cbBuffer );

#ifdef  __cplusplus
}
#endif

#endif /* !defined(_SERVER_H_2A8C2B85_C3DF_4CDD_8509_F905E65235EA) */

DateTime.h

/*********************************************************************************************
* Copyright (c) 2008 - 2010 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
*********************************************************************************************/

/*
 * DateTime.h - Header File for the Date/Time Functions
 */

#if !defined(DATETIME_H__4915DDA3_D454_4C36_AD25_4F2DF5E21C9B__INCLUDED_)
#define DATETIME_H__4915DDA3_D454_4C36_AD25_4F2DF5E21C9B__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif /* _MSC_VER > 1000 */

#ifdef TRACE_HEADERS
#pragma message ( "NOTE:  Included header file:  \"" __FILE__ "\"" )
#endif   /* TRACE_HEADERS */

#ifndef _INC_STDIO
#include <STDIO.H>
#endif   /* _INC_STDIO */

#ifndef _INC_TIME
#include <TIME.H>
#endif   /* _INC_TIME */

/**********************************
* Windows-NT Compatiblity Defines *
**********************************/

#ifndef BOOL
typedef int BOOL;
#endif   /* BOOL */

#ifndef VOID
typedef void VOID;
#endif   /* VOID */

#ifndef _SIZE_T_DEFINED
typedef unsigned int size_t;
#define _SIZE_T_DEFINED
#endif   /* _SIZE_T_DEFINED */

#ifndef  __SQLDATE

typedef short           SQLSMALLINT;
typedef unsigned short  SQLUSMALLINT;
typedef unsigned long   SQLUINTEGER;

typedef struct tagTIMESTAMP_STRUCT {

   SQLSMALLINT    year;
   SQLUSMALLINT   month;
   SQLUSMALLINT   day;
   SQLUSMALLINT   hour;
   SQLUSMALLINT   minute;
   SQLUSMALLINT   second;
   SQLUINTEGER    fraction;

} TIMESTAMP_STRUCT;

#endif   /* __SQLDATE */

#ifdef  __cplusplus
extern "C" {
#endif

long int          MDY2GD            ( int nMonth, int nDay, int nYear );
void              GD2MDY            ( long int lnDate, int * pnMonth, int * pnDay, int * pnYear );

double            CAL2JD            ( int nMo, int nDy, int nYear, int nHr, int nMn, int nSc, int nMs );
void              JD2CAL            ( double jdDateTime, int * lpnMo, int * lpnDy, int * lpnYear, int * lpnHr, int * lpnMn, int * lpnSc, int * lpnMs );

void              GetTzInfo         ( int * pnTimeZoneOffsetInHours, int * pfUseDaylightSavingsTime );

BOOL              Year2DST          ( int nYear, int nTimeZoneOffsetInHours, double * putcBeg, double * putcEnd );

double            UTC2Civil         ( double utcDateTime, BOOL * pfDaylightSavingsInEffect,  int nTimeZoneOffsetInHours, BOOL fUseDaylightSavingsTime );
double            Civil2UTC         ( double civDateTime, BOOL * pfDaylightSavingsAmbiguity, int nTimeZoneOffsetInHours, BOOL fUseDaylightSavingsTime );

double            CurrentTime       ( void );

TIMESTAMP_STRUCT  GetCivilTimeStamp ( double utcDateTime );

void              DumpJD2UTC        ( FILE * hFile, char * szLegend, double dblTimeUTC );
void              DumpJD2Civ        ( FILE * hFile, char * szLegend, double dblTimeUTC );

char *            myctime           ( const time_t * plnTime );

void              TimeStamp         ( long * plnUTCDate, long * plnUTCMilliseconds );

#ifdef   __cplusplus
}
#endif

#endif   /* !defined(DATETIME_H__4915DDA3_D454_4C36_AD25_4F2DF5E21C9B__INCLUDED_) */

ErrorTxt.h

/*********************************************************************************************
* Copyright (c) 2002 - 2009 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
*********************************************************************************************/

#ifndef _ERRORTXT_H
#define _ERRORTXT_H

#ifdef _MSC_VER

#if _MSC_VER >= 1000
#pragma once
#endif   /* _MSC_VER >= 1000 */

#ifdef TRACE_HEADERS
#pragma message ( "NOTE:  Included header file:  \"" __FILE__ "\"" )
#endif   /* TRACE_HEADERS */

#endif   /* _MSC_VER */

/**********************
* Function Prototypes *
**********************/

#ifdef __cplusplus
extern "C" {
#endif   /* __cplusplus */

/* Function Prototypes for Functions in CRC.c */

size_t GetErrorText ( DWORD dwErrorCode, char * szErrorText, size_t cbErrorText );

#ifdef __cplusplus
}
#endif   /* __cplusplus */

#endif   /* _ERRORTXT_H */

HiRes.h

/***************************************************************************************
* Copyright (c) 2002 - 2010 Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
***************************************************************************************/

#ifndef _HIRES_H_
#define _HIRES_H_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifndef QWORD_DEFINED
typedef unsigned __int64 QWORD;
#define QWORD_DEFINED
#endif

class CHiResTimer

   {

   public:

      CHiResTimer();

      void Start ( void );
      void Stop  ( void );

      double ElapsedTimeInSeconds ( void );

   private:

      QWORD qwBegTime;
      QWORD qwEndTime;
      QWORD qwFrequency;
   };

#endif // _HIRES_H_

WriteCon.h

/***************************************************************************************
* Copyright (c) 2002 - 2010 Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
***************************************************************************************/

#ifndef _WRITECON_H_
#define _WRITECON_H_

#if _MSC_VER > 1000
#pragma once
#endif /* _MSC_VER > 1000 */

/* Declare C Function Prototypes */

#ifdef  __cplusplus
extern "C" {
#endif   /* __cplusplus */

int   WriteCon             ( const char szFormat[], ... );

void  RedirectIoToConsole  ( const char * lpConsoleTitle );

#ifdef  __cplusplus
}
#endif   /* __cplusplus */

#endif   /* _WRITECON_H_ */

CanCode.c

/***************************************************************************************
* Copyright (c) 2007 - 2010 Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
***************************************************************************************/

#include "CanCode.h" /* CanCode Function Prototypes and Defines   */

/************************************************************************************
*                                                                                   *
* Derived from the ModComp CanCode concept of Compressed AlphaNumeric (CAN) Codes.  *
* The ASCII characters Space, A to Z, 0 to 9, ":", "." and "$", in that order, are  *
* converted into a 3 significant digit, base 40 number that fits nicely into an     *
* WORD value.                                                                       *
*                                                                                   *
* ModComps were a "big endian" architecture while Intel PCs are a "little endian"   *
* architecture.  CanCode() inverts the WORD order of the ModComp values but         *
* preserves the 3 character per WORD encoding.                                      *
*                                                                                   *
************************************************************************************/

#define FALSE  0
#define TRUE   1

#define min(a,b) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )

typedef int BOOL;

typedef union utagCanCode

   {
   unsigned long  ulCanCode;
   unsigned short usCanCode [ 2 ];

   } UCANCODE;

static const char acCanCode [ 40 ] = { ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
                                       'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
                                       'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2',
                                       '3', '4', '5', '6', '7', '8', '9', ':', '.', '$' };

unsigned long CanCode ( LPCSTR strString )

   {
   BOOL           fFinal            = FALSE;

   int            ixChar            = 0;
   int            ixCode            = 0;
   int            ixWord            = 0;

   char           ccChar            = '\0';

   UCANCODE       uCanCode          = { 0LU };

/*
 * Encode the First 6 Characters
 */
   for ( ixChar = 0; ixChar < 6; ixChar++ )
      {

   /*
    * Get the Character to Can Code
    */
      ccChar = strString [ ixChar ];

   /*
    * Find the Character in the Array
    */
      for ( ixCode = 0; ! fFinal && ixCode < 40; ixCode++ )
         if ( ccChar == acCanCode [ ixCode ] ) break;

   /*
    * Done if Not a CanCode Character
    */
      if ( ! fFinal && ixCode == 40 )
         fFinal = TRUE;

   /*
    * Convert it to a Base 40 Number
    */
      ixWord = ixChar / 3;

      uCanCode.usCanCode [ ixWord ] = ( unsigned short ) ( uCanCode.usCanCode [ ixWord ] * 40 );
      uCanCode.usCanCode [ ixWord ] = ( unsigned short ) ( uCanCode.usCanCode [ ixWord ] + ( fFinal ? 0 : ixCode ) );
      }

/*
 * Return the CanCoded Value
 */
   return uCanCode.ulCanCode;

   }  /* unsigned long CanCode ( LPCSTR strString ) */

void Uncan ( DWORD dwCanCode, char * pszAlphanumeric, size_t cbAlphanumeric )

   {
   int      ixChar            = 0;
   int      ixWord            = 0;
   int      ixByte            = 0;

   char     ccByte            = '\0';

   UCANCODE uCanCode;

   uCanCode.ulCanCode = dwCanCode;

   for ( ixChar = 0; ixChar < ( int ) min ( 6, cbAlphanumeric - 1 ); ixChar++ )
      {
      ixWord = ixChar / 3;
      ixByte = ixWord * 3 + 2 - ixChar % 3;
      ccByte = acCanCode [ uCanCode.usCanCode [ ixWord ] % 40 ];

      pszAlphanumeric [ ixByte ] = ccByte;

      uCanCode.usCanCode [ ixWord ] /= 40;
      }

   }  /* CString Uncan ( DWORD dwCanCode ) */

CRC.c

/*********************************************************************************************
* Copyright (c) 2002 - 2010 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
*********************************************************************************************/

#include "CRC.h"                       /* The CRC32 Prototypes and Defines */

#ifndef FALSE
#define FALSE 0
#endif   /* FALSE */

#ifndef TRUE
#define TRUE ( ~FALSE )
#endif   /* TRUE */

#ifndef VOID
typedef void VOID;
#endif   /* VOID */

/******************************************************************
*                                                                 *
*  Usage Example:                                                 *
*                                                                 *
*  BYTE  bBuffer [ 256 ];                                         *
*  DWORD ulCRC32;                                                 *
*                                                                 *
*  if ( ! SetCRC32 ( bBuffer, sizeof bBuffer, &ulCRC32 ) ) ...;   *
*  if ( ! ChkCRC32 ( bBuffer, sizeof bBuffer, &ulCRC32 ) ) ...;   *
*                                                                 *
******************************************************************/

/**************************************************************
* The Table of CCITT-32 CRC Remainders for All Possible Bytes *
**************************************************************/

/* CCITT - Consultative Committee on International Telegraph and Telephone */
/* CRC   - Cyclic Redundancy Check                                         */

static const unsigned long aulCCITT32CRCRemainderTable [ 256 ] = {

   0x00000000LU, 0x04C11DB7LU, 0x09823B6ELU, 0x0D4326D9LU, 0x130476DCLU, 0x17C56B6BLU, 0x1A864DB2LU, 0x1E475005LU,
   0x2608EDB8LU, 0x22C9F00FLU, 0x2F8AD6D6LU, 0x2B4BCB61LU, 0x350C9B64LU, 0x31CD86D3LU, 0x3C8EA00ALU, 0x384FBDBDLU,
   0x4C11DB70LU, 0x48D0C6C7LU, 0x4593E01ELU, 0x4152FDA9LU, 0x5F15ADACLU, 0x5BD4B01BLU, 0x569796C2LU, 0x52568B75LU,
   0x6A1936C8LU, 0x6ED82B7FLU, 0x639B0DA6LU, 0x675A1011LU, 0x791D4014LU, 0x7DDC5DA3LU, 0x709F7B7ALU, 0x745E66CDLU,
   0x9823B6E0LU, 0x9CE2AB57LU, 0x91A18D8ELU, 0x95609039LU, 0x8B27C03CLU, 0x8FE6DD8BLU, 0x82A5FB52LU, 0x8664E6E5LU,
   0xBE2B5B58LU, 0xBAEA46EFLU, 0xB7A96036LU, 0xB3687D81LU, 0xAD2F2D84LU, 0xA9EE3033LU, 0xA4AD16EALU, 0xA06C0B5DLU,
   0xD4326D90LU, 0xD0F37027LU, 0xDDB056FELU, 0xD9714B49LU, 0xC7361B4CLU, 0xC3F706FBLU, 0xCEB42022LU, 0xCA753D95LU,
   0xF23A8028LU, 0xF6FB9D9FLU, 0xFBB8BB46LU, 0xFF79A6F1LU, 0xE13EF6F4LU, 0xE5FFEB43LU, 0xE8BCCD9ALU, 0xEC7DD02DLU,
   0x34867077LU, 0x30476DC0LU, 0x3D044B19LU, 0x39C556AELU, 0x278206ABLU, 0x23431B1CLU, 0x2E003DC5LU, 0x2AC12072LU,
   0x128E9DCFLU, 0x164F8078LU, 0x1B0CA6A1LU, 0x1FCDBB16LU, 0x018AEB13LU, 0x054BF6A4LU, 0x0808D07DLU, 0x0CC9CDCALU,
   0x7897AB07LU, 0x7C56B6B0LU, 0x71159069LU, 0x75D48DDELU, 0x6B93DDDBLU, 0x6F52C06CLU, 0x6211E6B5LU, 0x66D0FB02LU,
   0x5E9F46BFLU, 0x5A5E5B08LU, 0x571D7DD1LU, 0x53DC6066LU, 0x4D9B3063LU, 0x495A2DD4LU, 0x44190B0DLU, 0x40D816BALU,
   0xACA5C697LU, 0xA864DB20LU, 0xA527FDF9LU, 0xA1E6E04ELU, 0xBFA1B04BLU, 0xBB60ADFCLU, 0xB6238B25LU, 0xB2E29692LU,
   0x8AAD2B2FLU, 0x8E6C3698LU, 0x832F1041LU, 0x87EE0DF6LU, 0x99A95DF3LU, 0x9D684044LU, 0x902B669DLU, 0x94EA7B2ALU,
   0xE0B41DE7LU, 0xE4750050LU, 0xE9362689LU, 0xEDF73B3ELU, 0xF3B06B3BLU, 0xF771768CLU, 0xFA325055LU, 0xFEF34DE2LU,
   0xC6BCF05FLU, 0xC27DEDE8LU, 0xCF3ECB31LU, 0xCBFFD686LU, 0xD5B88683LU, 0xD1799B34LU, 0xDC3ABDEDLU, 0xD8FBA05ALU,
   0x690CE0EELU, 0x6DCDFD59LU, 0x608EDB80LU, 0x644FC637LU, 0x7A089632LU, 0x7EC98B85LU, 0x738AAD5CLU, 0x774BB0EBLU,
   0x4F040D56LU, 0x4BC510E1LU, 0x46863638LU, 0x42472B8FLU, 0x5C007B8ALU, 0x58C1663DLU, 0x558240E4LU, 0x51435D53LU,
   0x251D3B9ELU, 0x21DC2629LU, 0x2C9F00F0LU, 0x285E1D47LU, 0x36194D42LU, 0x32D850F5LU, 0x3F9B762CLU, 0x3B5A6B9BLU,
   0x0315D626LU, 0x07D4CB91LU, 0x0A97ED48LU, 0x0E56F0FFLU, 0x1011A0FALU, 0x14D0BD4DLU, 0x19939B94LU, 0x1D528623LU,
   0xF12F560ELU, 0xF5EE4BB9LU, 0xF8AD6D60LU, 0xFC6C70D7LU, 0xE22B20D2LU, 0xE6EA3D65LU, 0xEBA91BBCLU, 0xEF68060BLU,
   0xD727BBB6LU, 0xD3E6A601LU, 0xDEA580D8LU, 0xDA649D6FLU, 0xC423CD6ALU, 0xC0E2D0DDLU, 0xCDA1F604LU, 0xC960EBB3LU,
   0xBD3E8D7ELU, 0xB9FF90C9LU, 0xB4BCB610LU, 0xB07DABA7LU, 0xAE3AFBA2LU, 0xAAFBE615LU, 0xA7B8C0CCLU, 0xA379DD7BLU,
   0x9B3660C6LU, 0x9FF77D71LU, 0x92B45BA8LU, 0x9675461FLU, 0x8832161ALU, 0x8CF30BADLU, 0x81B02D74LU, 0x857130C3LU,
   0x5D8A9099LU, 0x594B8D2ELU, 0x5408ABF7LU, 0x50C9B640LU, 0x4E8EE645LU, 0x4A4FFBF2LU, 0x470CDD2BLU, 0x43CDC09CLU,
   0x7B827D21LU, 0x7F436096LU, 0x7200464FLU, 0x76C15BF8LU, 0x68860BFDLU, 0x6C47164ALU, 0x61043093LU, 0x65C52D24LU,
   0x119B4BE9LU, 0x155A565ELU, 0x18197087LU, 0x1CD86D30LU, 0x029F3D35LU, 0x065E2082LU, 0x0B1D065BLU, 0x0FDC1BECLU,
   0x3793A651LU, 0x3352BBE6LU, 0x3E119D3FLU, 0x3AD08088LU, 0x2497D08DLU, 0x2056CD3ALU, 0x2D15EBE3LU, 0x29D4F654LU,
   0xC5A92679LU, 0xC1683BCELU, 0xCC2B1D17LU, 0xC8EA00A0LU, 0xD6AD50A5LU, 0xD26C4D12LU, 0xDF2F6BCBLU, 0xDBEE767CLU,
   0xE3A1CBC1LU, 0xE760D676LU, 0xEA23F0AFLU, 0xEEE2ED18LU, 0xF0A5BD1DLU, 0xF464A0AALU, 0xF9278673LU, 0xFDE69BC4LU,
   0x89B8FD09LU, 0x8D79E0BELU, 0x803AC667LU, 0x84FBDBD0LU, 0x9ABC8BD5LU, 0x9E7D9662LU, 0x933EB0BBLU, 0x97FFAD0CLU,
   0xAFB010B1LU, 0xAB710D06LU, 0xA6322BDFLU, 0xA2F33668LU, 0xBCB4666DLU, 0xB8757BDALU, 0xB5365D03LU, 0xB1F740B4LU

};

/****************************
* Generate the CCITT-32 CRC *
****************************/

unsigned long CCITT32CRC ( const unsigned long  ulAccumCCITT32CRC,
                           void                 const * lpDataBuffer,
                           const unsigned int   cbDataBuffer )

   {
   register unsigned long  i;
   register unsigned long  j;
   register unsigned long  ulCCITT32CRC = ulAccumCCITT32CRC;
   
   for ( j = 0LU; j < cbDataBuffer; j++ )
      {
      i  = ( ( ulCCITT32CRC >> 24LU ) ^ ( ( unsigned char * ) lpDataBuffer ) [ j ] ) & 0xFFLU;
      ulCCITT32CRC = ( ulCCITT32CRC << 8LU ) ^ aulCCITT32CRCRemainderTable [ i ];
      }
   
   return ulCCITT32CRC;
   
   }  /* CCITT32CRC() */

void PutCRC32 ( void * lpulCRC32, unsigned long ulCRC32 )

   {

   /* Store the CRC32 Value Into the CRC32 Address */

   ( ( unsigned char * ) lpulCRC32 ) [ 0 ] = ( unsigned char ) ( ( ulCRC32 & 0xFF000000LU ) >> 24U );
   ( ( unsigned char * ) lpulCRC32 ) [ 1 ] = ( unsigned char ) ( ( ulCRC32 & 0x00FF0000LU ) >> 16U );
   ( ( unsigned char * ) lpulCRC32 ) [ 2 ] = ( unsigned char ) ( ( ulCRC32 & 0x0000FF00LU ) >>  8U );
   ( ( unsigned char * ) lpulCRC32 ) [ 3 ] = ( unsigned char ) ( ( ulCRC32 & 0x000000FFLU ) >>  0U );

   }  /* void PutCRC32 ( unsigned long * lpulCRC32, ulCRC32 ) */

BOOL SetCRC32 ( void const * lpDataBuffer, const size_t cbDataBuffer, DWORD * lpulCRC32 )

   {
   unsigned long ulCRC32;

   /* Validate the Input Parameters */

   if ( ! lpDataBuffer || ! lpulCRC32 ) return FALSE;

   /* Get the One's Complement of the Computed CCITT-32 CRC */

   ulCRC32 = ~CCITT32CRC ( 0xFFFFFFFFLU, lpDataBuffer, cbDataBuffer );

   /* Store the Resultant Value Into the CRC32 Address */

   PutCRC32 ( lpulCRC32, ulCRC32 );

   /* Return Success! */

   return TRUE;

   }  /* SetCRC32 */

BOOL ChkCRC32 ( void const * lpDataBuffer, const size_t cbDataBuffer, unsigned long * const lpulCRC32 )

   {
   unsigned long ulCRC32;

   /* Validate the Input Parameters */

   if ( ! lpDataBuffer ) return FALSE;

   /* Get the Accumulated CCITT-32 CRC */

   ulCRC32 = CCITT32CRC ( 0xFFFFFFFFLU, lpDataBuffer, cbDataBuffer );

   /*
    * If lpulCRC32 is NOT specified, it is assumed to be the last 4 bytes of lpDataBuffer,
    * and counted in cbDataBuffer.  If lpulCRC32 IS specified, it is NOT counted in
    * cbDataBuffer, and will be accumlated in a seperate call to CCITT32CRC().
    */

   if ( lpulCRC32 )
      ulCRC32 = CCITT32CRC ( ulCRC32, lpulCRC32, sizeof ( DWORD ) );

   /* Return the Success Indicator */

   return ulCRC32 == 0xC704DD7BL;

   }  /* ChkCRC32() */

Crypto.c

/************************************************************************************************
*                                                                                               *
* Copyright (c) 2009 - 2010 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342    *
*                                                                                               *
*  This code implements the AES encryption,                                                     *
*                                                                                               *
*  The AES (Rijndael) Encryption code comes from:                                               *
*                                                                                               *
*     http://fp.gladman.plus.com/cryptography_technology/rijndael/                              *
*                                                                                               *
************************************************************************************************/

#pragma warning ( disable : 4514 )                       /* "unreferenced inline function has been removed"                   */

#include <MATH.H>                                        /* fabs()                                                            */

#include "aes.h"                                         /* The AES Encryption Prototypes and Defines                         */
#include "CRC.h"                                         /* CRC Error Checking Function Protypes and Defines                  */
#include "DateTime.h"                                    /* The Date and Time Prototypes and Defines                          */
#include "WriteCon.h"                                    /* WriteCon()                                                        */

#include "Crypto.h"                                      /* The Cryptography Code                                             */

/************************************************************************************************************************************
* The following function prototypes and defines have been seperated from WINDOWS.H so that we can disable the C language extensions *
************************************************************************************************************************************/

#define CONST           const
#define TRUE            1
#define FALSE           0

#define INVALID_SOCKET  ( SOCKET ) ( ~0 )
#define SOCKET_ERROR    ( -1 )

#define WSABASEERR      10000
#define WSAETIMEDOUT    ( WSABASEERR + 60 )

#define MSG_DONTROUTE   0x4

typedef unsigned short int WORD;
typedef unsigned long      DWORD;
typedef unsigned int       size_t;

typedef struct _SYSTEMTIME {

   WORD wYear;
   WORD wMonth;
   WORD wDayOfWeek;
   WORD wDay;
   WORD wHour;
   WORD wMinute;
   WORD wSecond;
   WORD wMilliseconds;

} SYSTEMTIME, * PSYSTEMTIME, * LPSYSTEMTIME;


extern __declspec ( dllimport ) void   __stdcall   GetSystemTime     ( LPSYSTEMTIME lpSystemTime );
extern __declspec ( dllimport ) void   __stdcall   SetSystemTime     ( CONST SYSTEMTIME * lpSystemTime );

extern __declspec ( dllimport ) void   __stdcall   SetLastError      ( DWORD dwErrCode );

extern __declspec ( dllimport ) int    __stdcall   send              ( SOCKET s, const char * buf, int len, int flags );
extern __declspec ( dllimport ) int    __stdcall   sendto            ( SOCKET s, const char * buf, int len, int flags, const struct sockaddr * to, int tolen );
extern __declspec ( dllimport ) int    __stdcall   WSAGetLastError   ( void );
extern __declspec ( dllimport ) int    __stdcall   recvfrom          ( SOCKET s, char * buf, int len, int flags, struct sockaddr * from, int * fromlen );
extern __declspec ( dllimport ) int    __stdcall   recv              ( SOCKET s, char * buf, int len, int flags );

void * __cdecl                                     memcpy            ( void *, const void *, size_t );
void * __cdecl                                     memset            ( void *, int, size_t );
size_t __cdecl                                     strlen            ( const char * );

/*****************************************
* Crypto.c Specific Typedefs and Defines *
*****************************************/

#ifndef min
#define min(a,b)  ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
#endif   // min

#ifndef max
#define max(a,b)  ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
#endif   // max

#define RANGE(SPECIFIED_VALUE,MIN_VALUE,MAX_VALUE) min ( max ( ( SPECIFIED_VALUE ), ( MIN_VALUE ) ), ( MAX_VALUE ) )

typedef enum tagEncryptError {

   E_ENCRYPT_NO_ERROR,

   E_ENCRYPT_SEND_ERROR,
   E_ENCRYPT_RECEIVE_ERROR,

   E_ENCRYPT_SHUTDOWN_REQUESTED,
   E_ENCRYPT_BAD_BUFFER_SIZE,
   E_ENCRYPT_BAD_AES_BLOCK,
   E_ENCRYPT_BAD_CHECKSUM,
   E_ENCRYPT_BAD_TIME,
   E_ENCRYPT_BAD_PACKET_SIZE,

   E_ENCRYPT_,

   E_ENCRYPT_NUM_ERRORS

} EENCRYPTERROR, * LPEENCRYPTERROR;

#pragma pack ( push, UDPPacket, 1 )

typedef struct tagUDPPacket {

   DWORD          dwSequenceNumber;                      /* The Packet Sequence Number to Associate Request with Response     */

   size_t         cbBytes;                               /* The Size of the Whole UDP Packet in Bytes                         */

   long           lnDate;                                /* The Gregorian Day Index                                           */
   long           lnTime;                                /* The Fraction of the Day in ms                                     */

   unsigned char  ucPayload [ 1 ];                       /* Placeholder for the Payload                                       */

   unsigned long  ulCRC32;                               /* CCITT CRC32 Checksum                                              */

} UDPPACKET, * LPUDPPACKET;

#pragma pack ( pop, UDPPacket )

/***********************
* Globally Shared Data *
***********************/

extern BOOL             g_fShutDownRequested;               /* Set to TRUE to Break the Wait Cycle                               */

extern const size_t     g_cbMaxAESEncryptedUDPPacketSize    = ( AES_MAX_UDP_BLOCKS - 1 ) * AES_BLOCK_LEN;

extern unsigned long    g_ulErrors  = 0LU;                  /* Debug Error Counter                                               */

static aes_encrypt_ctx  g_ctxAESEnc = { { 0U }, 0U };       /* The AES Encryption Context                                        */
static aes_decrypt_ctx  g_ctxAESDec = { { 0U }, 0U };       /* The AES Decryption Context                                        */

static unsigned char    g_ucAESKey [ AES_BLOCK_LEN ]        = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F };

static const double     g_dblOneSecond                      = 1.0 / ( 24.0 * 60.0 * 60.0 );
static const double     g_dblTimeDifferential               = 5.0 / ( 24.0 * 60.0 * 60.0 );

/******************************************
*  Return the Pentium Timestamp Counter   *
******************************************/

static void Cycles ( unsigned __int64 * pqwTimeCounter )

   {

   __asm /* read the Pentium Time Stamp Counter */
      {
      cpuid
      rdtsc
      mov      ecx,pqwTimeCounter
      mov      [ ecx ],eax
      mov      [ ecx + 4 ],edx
      cpuid
      }

   }  /* static void Cycles ( QWORD * pqwTimeCounter ) */

/*********************************************************************************
*                                                                                *
*  A Nonce (Number-Used-Once) is added as the starting block of the buffer to    *
*  randomize the Initialization Values of the remaining encrypted blocks (each   *
*  block depends on the previous block).  When decrypted, the Nonce sets the     *
*  dependencies and is then thrown away.  This adds a 16 byte block to an AES    *
*  (Rijndael) transmission buffer that wouldn't be there in an unencrypted       *
*  buffer.                                                                       *
*                                                                                *
*********************************************************************************/

extern void GetRandomIV ( unsigned char * ucInitialValue, const size_t cbInitialValue )

   {
   unsigned int      i        = 0;
   unsigned int      uCycle   = 3U;

   unsigned __int64  qwTime   = 0UI64;

   for ( i = 0; i < cbInitialValue; ++i )
      {
      if ( i % uCycle == 0 )
         Cycles ( &qwTime );

      ucInitialValue [ i ] = ( ( unsigned char * ) &qwTime ) [ i % uCycle ];
      }

   }  /* static void GetRandomIV ( unsigned char * ucInitialValue, const size_t cbInitialValue ) */

/******************************************
*  Initialize the AES Encryption Context  *
******************************************/

void InitCrypto ( void )

   {

   aes_encrypt_key128 ( g_ucAESKey, &g_ctxAESEnc );
   aes_decrypt_key128 ( g_ucAESKey, &g_ctxAESDec );

   }  /* void InitCrypto ( void ) */

void GetTimeNow ( long * plnDate, long * plnTime )

   {
   SYSTEMTIME stSystemTime = { 0 }; /* The Current System Time in UTC   */

   GetSystemTime ( &stSystemTime );

   * plnDate = MDY2GD ( stSystemTime.wMonth, stSystemTime.wDay, stSystemTime.wYear);
   * plnTime = stSystemTime.wHour * 3600000L + stSystemTime.wMinute * 60000L + stSystemTime.wSecond * 1000L + stSystemTime.wMilliseconds;

   }  /* void GetTimeNow (  long * plnDate, long * plnTime ) */

size_t SvrPutAESEncryptedUDPPacket ( SOCKET uUDPSocket, DWORD dwSequenceNumber, SOCKADDR_IN * psinUDPClient, size_t cbsinUDPClient, void * pvBuffer, size_t cbBuffer )

   {
   unsigned char  ucBuffer [ AES_MAX_UDP_BLOCKS ] [ AES_BLOCK_LEN ]  = { { 0 } };   /* The Raw Outgoing Buffer                */

   int            cbSent                                             = 0;           /* The Number of Bytes Transmitted        */

   int            nBlocks                                            = 0;           /* The Number of Encrypted Payload Blocks */
   int            i                                                  = 0;           /* Temporary Indexing Variable            */
   int            j                                                  = 0;           /* Temporary Indexing Variable            */

   LPUDPPACKET    lpUDPPacket                                        = NULL;        /* Pointer to the UDP Packet Structure    */

/*
 * Initialize to No Error
 */
   SetLastError ( E_ENCRYPT_NO_ERROR );

/*
 * Check for Packet Size Limit
 */
   if ( cbBuffer > g_cbMaxAESEncryptedUDPPacketSize )
      {
      WriteCon ( "SvrPutAESEncryptedUDPPacket():  Buffer Too Large!\n\a" );
      g_ulErrors++;

      SetLastError ( E_ENCRYPT_BAD_PACKET_SIZE );
      return 0U;
      }

/*
 * Fill in the UDP Packet
 */
   lpUDPPacket = ( LPUDPPACKET ) ucBuffer [ 1 ];

   lpUDPPacket->cbBytes = cbBuffer + sizeof ( UDPPACKET ) - 1U;

   lpUDPPacket->dwSequenceNumber = dwSequenceNumber;

   GetTimeNow ( &lpUDPPacket->lnDate, &lpUDPPacket->lnTime );

   memcpy ( lpUDPPacket->ucPayload, pvBuffer, cbBuffer );

   SetCRC32 ( lpUDPPacket, lpUDPPacket->cbBytes - sizeof lpUDPPacket->ulCRC32, ( unsigned long * ) ( ( char * ) lpUDPPacket + lpUDPPacket->cbBytes - sizeof lpUDPPacket->ulCRC32 ) );

/*
 * Get a Random Initialization Vector (IV)
 */
   GetRandomIV ( ucBuffer [ 0 ], AES_BLOCK_LEN );

/*
 * Chain the Blocks
 */
   nBlocks = ( lpUDPPacket->cbBytes + AES_BLOCK_LEN - 1 ) / AES_BLOCK_LEN;

   for ( i = 0; i < nBlocks; i++ )
      for ( j = 0; j <= AES_BLOCK_LEN - 1; j++ )
         ucBuffer [ i + 1 ] [ j ] ^= ucBuffer [ i ] [ j ];

/*
 * Encrypt the Chain Including the Initialization Vector
 */
   for ( i = 0; i < nBlocks + 1; i++ )
      aes_encrypt ( ucBuffer [ i ], ucBuffer [ i ], &g_ctxAESEnc );

/*
 * Send the Buffer
 */
   if ( ( cbSent = sendto ( uUDPSocket, ( const char * ) ucBuffer, ( nBlocks + 1 ) * AES_BLOCK_LEN, 0, ( struct sockaddr * ) psinUDPClient, cbsinUDPClient ) ) == SOCKET_ERROR )
      {
      WriteCon ( "SvrPutAESEncryptedUDPPacket():  sendto() returned %d!\n\a", WSAGetLastError() );
      g_ulErrors++;

      SetLastError ( E_ENCRYPT_SEND_ERROR );
      return 0U;
      }

/*
 * Return the Payload Size
 */
   return cbBuffer;

   }  /* BOOL SvrPutAESEncryptedUDPPacket ( SOCKET uUDPSocket, SOCKADDR_IN * psinUDPClient, size_t cbsinUDPClient, void * pvBuffer, size_t cbBuffer ) */

size_t SvrGetAESEncryptedUDPPacket ( SOCKET uUDPSocket, DWORD * pdwSequenceNumber, struct sockaddr * pSinUDPClient, int * pnSinUDPClient, void * pvBuffer, size_t cbBuffer, BOOL fSyncTime )

   {
   unsigned char  ucBuffer [ AES_MAX_UDP_BLOCKS ] [ AES_BLOCK_LEN ]  = { { 0 } };   /* The Raw Incoming Buffer                   */

   int            cbRecd                                             = 0;           /* The Number of Bytes Received              */

   int            nBlocks                                            = 0;           /* The Number of Unencrypted Payload Blocks  */
   int            i                                                  = 0;           /* Temporary Indexing Variable               */
   int            j                                                  = 0;           /* Temporary Indexing Variable               */

   LPUDPPACKET    lpUDPPacket                                        = NULL;        /* Pointer to the UDP Packet Structure       */

   SYSTEMTIME     stSystemTime                                       = { 0U };      /* The System Time Structure                 */

   double         dblTimeMsg                                         = 0.0;         /* The Time the Message Was Sent             */
   double         dblTimeNow                                         = 0.0;         /* The Time the Message Was Received         */
   double         dblTimeDiff                                        = 0.0;         /* The Time Difference of the Message and Us */
   double         dblTimeDriftInSeconds                              = 0.0;         /* The Time Drift in Seconds                 */


   size_t         cbPayload                                          = 0U;          /* The Number of Bytes in the Actual Payload */

/*
 * Initialize to No Error
 */
   SetLastError ( E_ENCRYPT_NO_ERROR );

/*
 * Receive the Buffer
 */
   while ( ! g_fShutDownRequested )
      {
      if ( ( cbRecd = recvfrom ( uUDPSocket, ( char * ) ucBuffer, sizeof ucBuffer, 0, pSinUDPClient, pnSinUDPClient ) ) != SOCKET_ERROR ) break;
      if ( WSAGetLastError() == WSAETIMEDOUT ) continue;

      WriteCon ( "SvrGetAESEncryptedUDPPacket():  recv() returned %d!\n\a", WSAGetLastError() );
      g_ulErrors++;

      SetLastError ( E_ENCRYPT_RECEIVE_ERROR );
      return 0U;
      }

   if ( g_fShutDownRequested )
      {
      SetLastError ( E_ENCRYPT_SHUTDOWN_REQUESTED );
      return 0U;
      }

/*
 * Assure cbRecd is a Multiple of AES_BLOCK_LEN
 */
   if ( cbRecd % AES_BLOCK_LEN )
      {
      WriteCon ( "SvrGetAESEncryptedUDPPacket():  Incorrect AES Buffer Size\n\a" );
      g_ulErrors++;

      SetLastError ( E_ENCRYPT_BAD_BUFFER_SIZE );
      return 0U;
      }

/*
 * Decrypt the Chain
 */
   nBlocks = cbRecd / AES_BLOCK_LEN - 1;  /* Number of Full Blocks Received - the Random Initialization Vector */

   for ( i = 0; i <= nBlocks; i++ )
      {
      if ( aes_decrypt ( ucBuffer [ i ], ucBuffer [ i ], &g_ctxAESDec ) == EXIT_FAILURE )
         {
         WriteCon ( "SvrGetAESEncryptedUDPPacket():  Bad AES Block!\n\a" );
         g_ulErrors++;

         SetLastError ( E_ENCRYPT_BAD_AES_BLOCK );
         return 0U;
         }
      }

/*
 * Unchain the Blocks
 */
   for ( i = nBlocks - 1; i >= 0; i-- )
      for ( j = AES_BLOCK_LEN - 1; j >= 0; j-- )
         ucBuffer [ i + 1 ] [ j ] ^= ucBuffer [ i ] [ j ];

/*
 * Locate the Unencrypted Payload
 */
   lpUDPPacket = ( LPUDPPACKET ) ucBuffer [ 1 ];

/*
 * Check the packet size.  If it is greater than the maximum packet size, the most likely
 * cause would be that the encryption failed and lpUDPPacket->cbBytes was improperly
 * decrypted.  Corrupted values that fall between 1 and the maximum packet size will be
 * detected via the checksum.
 */
   if ( lpUDPPacket->cbBytes < 1 || lpUDPPacket->cbBytes > g_cbMaxAESEncryptedUDPPacketSize )
      {
      WriteCon ( "SvrGetAESEncryptedUDPPacket():  The Packet Size is Invalid!\n\a" );
      g_ulErrors++;

      SetLastError ( E_ENCRYPT_BAD_PACKET_SIZE );
      return 0U;
      }

/*
 * Check the CRC Checksum
 */
   if ( ! ChkCRC32 ( lpUDPPacket, lpUDPPacket->cbBytes, NULL ) )
      {
      WriteCon ( "SvrGetAESEncryptedUDPPacket():  The CCITT-CRC32 Checksum Failed!\n\a" );
      g_ulErrors++;

      SetLastError ( E_ENCRYPT_BAD_CHECKSUM );
      return 0U;
      }

/*
 * Check that the Clock Times are Within 1/2 Second and Set the Time Drift Flag if Not
 */
   GetSystemTime ( &stSystemTime );

   dblTimeNow = CAL2JD ( stSystemTime.wMonth, stSystemTime.wDay, stSystemTime.wYear, stSystemTime.wHour, stSystemTime.wMinute, stSystemTime.wSecond, stSystemTime.wMilliseconds );
   dblTimeMsg = lpUDPPacket->lnDate + 1721424.5 + lpUDPPacket->lnTime / 86400000.0;

   dblTimeDiff = dblTimeNow - dblTimeMsg;

   dblTimeDriftInSeconds = fabs ( dblTimeDiff ) / g_dblOneSecond;

   /* Correct the Time Drift if it is More than 1/2 Second and Less than the Specified Time Differential */

   if ( fSyncTime && dblTimeDriftInSeconds > 0.5 && dblTimeDriftInSeconds < g_dblTimeDifferential )
      {
      SYSTEMTIME  stSystemTime   = { 0 };

      int         nMonth         = 0;
      int         nDay           = 0;
      int         nYear          = 0;
      int         nHour          = 0;
      int         nMinute        = 0;
      int         nSecond        = 0;
      int         nMillisecond   = 0;

      /* Convert the Message Time Julian Day Number into Months, Days, Years, Hours, Minutes, Seconds and Milliseconds */

      JD2CAL ( dblTimeMsg, &nMonth, &nDay, &nYear, &nHour, &nMinute, &nSecond, &nMillisecond );

      stSystemTime.wMonth        = ( WORD ) nMonth;
      stSystemTime.wDay          = ( WORD ) nDay;
      stSystemTime.wDayOfWeek    = ( WORD ) ( MDY2GD ( nMonth, nDay, nYear ) % 7 );
      stSystemTime.wYear         = ( WORD ) nYear;
      stSystemTime.wHour         = ( WORD ) nHour;
      stSystemTime.wMinute       = ( WORD ) nMinute;
      stSystemTime.wSecond       = ( WORD ) nSecond;
      stSystemTime.wMilliseconds = ( WORD ) nMillisecond;

      /* Set the New System Time */

      SetSystemTime ( &stSystemTime );
      }

/*
 * Check that the Clock Times are Within the Specified Time Differential
 */
   if ( fabs ( dblTimeDiff ) > g_dblTimeDifferential )
      {
      fprintf ( stderr, "SvrGetAESEncryptedUDPPacket():  The Message Time is Out of Range by %.3f sec!\n", dblTimeDiff / g_dblOneSecond );
      g_ulErrors++;

      SetLastError ( E_ENCRYPT_BAD_TIME );
      return 0U;
      }

/*
 * Return the Packet Sequence Number
 */
   if ( pdwSequenceNumber ) * pdwSequenceNumber = lpUDPPacket->dwSequenceNumber;

/*
 * Return the Payload
 */
   cbPayload = lpUDPPacket->cbBytes - sizeof ( UDPPACKET ) + 1U;

   memcpy ( pvBuffer, lpUDPPacket->ucPayload, min ( cbBuffer, cbPayload ) );

/*
 * Return the Payload Size
 */
   return cbPayload;

   }  /* size_t SvrGetAESEncryptedUDPPacket ( SOCKET uUDPSocket, struct sockaddr * pSinUDPClient, int * pnSinUDPClient, void * pvBuffer, size_t cbBuffer, BOOL * pfTimeDriftFlag ) */

size_t CntPutAESEncryptedUDPPacket ( SOCKET uUDPSocket, DWORD dwSequenceNumber, void * pvBuffer, size_t cbBuffer )

   {
   unsigned char  ucBuffer [ AES_MAX_UDP_BLOCKS ] [ AES_BLOCK_LEN ]  = { { 0 } };   /* The Raw Outgoing Buffer                */

   int            cbSent                                             = 0;           /* The Number of Bytes Transmitted        */

   int            nBlocks                                            = 0;           /* The Number of Encrypted Payload Blocks */
   int            i                                                  = 0;           /* Temporary Indexing Variable            */
   int            j                                                  = 0;           /* Temporary Indexing Variable            */

   LPUDPPACKET    lpUDPPacket                                        = NULL;        /* Pointer to the UDP Packet Structure    */

/*
 * Initialize to No Error
 */
   SetLastError ( E_ENCRYPT_NO_ERROR );

/*
 * Check for Packet Size Limit
 */
   if ( cbBuffer > g_cbMaxAESEncryptedUDPPacketSize )
      {
      WriteCon ( "CntPutAESEncryptedUDPPacket():  Buffer Too Large!\n\a" );
      g_ulErrors++;

      SetLastError ( E_ENCRYPT_BAD_PACKET_SIZE );
      return 0U;
      }

/*
 * Fill in the UDP Packet
 */
   lpUDPPacket = ( LPUDPPACKET ) ucBuffer [ 1 ];

   lpUDPPacket->cbBytes = cbBuffer + sizeof ( UDPPACKET ) - 1U;

   lpUDPPacket->dwSequenceNumber = dwSequenceNumber;

   GetTimeNow ( &lpUDPPacket->lnDate, &lpUDPPacket->lnTime );

   memcpy ( lpUDPPacket->ucPayload, pvBuffer, cbBuffer );

   SetCRC32 ( lpUDPPacket, lpUDPPacket->cbBytes - sizeof lpUDPPacket->ulCRC32, ( unsigned long * ) ( ( char * ) lpUDPPacket + lpUDPPacket->cbBytes - sizeof lpUDPPacket->ulCRC32 ) );

/*
 * Get a Random Initialization Vector (IV)
 */
   GetRandomIV ( ucBuffer [ 0 ], AES_BLOCK_LEN );

/*
 * Chain the Blocks
 */
   nBlocks = ( lpUDPPacket->cbBytes + AES_BLOCK_LEN - 1 ) / AES_BLOCK_LEN;

   for ( i = 0; i < nBlocks; i++ )
      for ( j = 0; j <= AES_BLOCK_LEN - 1; j++ )
         ucBuffer [ i + 1 ] [ j ] ^= ucBuffer [ i ] [ j ];

/*
 * Encrypt the Chain Including the Initialization Vector
 */
   for ( i = 0; i < nBlocks + 1; i++ )
      aes_encrypt ( ucBuffer [ i ], ucBuffer [ i ], &g_ctxAESEnc );

/*
 * Send the Buffer
 */
   if ( ( cbSent = send ( uUDPSocket, ( const char * ) ucBuffer, ( nBlocks + 1 ) * AES_BLOCK_LEN, MSG_DONTROUTE ) ) == SOCKET_ERROR )
      {
      WriteCon ( "CntPutAESEncryptedUDPPacket():  send() returned %d!\n\a", WSAGetLastError() );
      g_ulErrors++;

      SetLastError ( E_ENCRYPT_SEND_ERROR );
      return 0U;
      }

/*
 * Return the Payload Size
 */
   return cbBuffer;

   }  /* size_t CntPutAESEncryptedUDPPacket ( SOCKET uUDPSocket, SOCKADDR_IN * psinUDPClient, size_t cbsinUDPClient, void * pvBuffer, size_t cbBuffer ) */

size_t CntGetAESEncryptedUDPPacket ( SOCKET uUDPSocket, DWORD * pdwSequenceNumber, void * pvBuffer, size_t cbBuffer )

   {
   unsigned char  ucBuffer [ AES_MAX_UDP_BLOCKS ] [ AES_BLOCK_LEN ]  = { { 0 } };   /* The Raw Incoming Buffer                   */

   int            cbRecd                                             = 0;           /* The Number of Bytes Received              */

   int            nBlocks                                            = 0;           /* The Number of Unencrypted Payload Blocks  */
   int            i                                                  = 0;           /* Temporary Indexing Variable               */
   int            j                                                  = 0;           /* Temporary Indexing Variable               */

   LPUDPPACKET    lpUDPPacket                                        = NULL;        /* Pointer to the UDP Packet Structure       */

   SYSTEMTIME     stSystemTime                                       = { 0U };      /* The System Time Structure                 */

   double         dblTimeMsg                                         = 0.0;         /* The Time the Message Was Sent             */
   double         dblTimeNow                                         = 0.0;         /* The Time the Message Was Received         */

   size_t         cbPayload                                          = 0U;          /* The Number of Bytes in the Actual Payload */

// return recv ( uUDPSocket, pvBuffer, cbBuffer, 0 ); // !!! Fix !!!

/*
 * Initialize to No Error
 */
   SetLastError ( E_ENCRYPT_NO_ERROR );

/*
 * Receive the Buffer
 */
   memset ( ucBuffer, 0, sizeof ucBuffer );

   if ( ( cbRecd = recv ( uUDPSocket, ( char * ) ucBuffer, sizeof ucBuffer, 0 ) ) == SOCKET_ERROR )   /* 10060 == WSAETIMEDOUT   */
      {
      WriteCon ( "CntGetAESEncryptedUDPPacket():  recv() returned %d!\n\a", WSAGetLastError() );
      g_ulErrors++;

      SetLastError ( E_ENCRYPT_RECEIVE_ERROR );
      return 0U;
      }

/*
 * Assure cbRecd is a Multiple of AES_BLOCK_LEN
 */
   if ( cbRecd % AES_BLOCK_LEN )
      {
      WriteCon ( "CntGetAESEncryptedUDPPacket():  Incorrect AES Buffer Size\n\a" );
      g_ulErrors++;

      SetLastError ( E_ENCRYPT_BAD_BUFFER_SIZE );
      return 0U;
      }

/*
 * Decrypt the Chain
 */
   nBlocks = cbRecd / AES_BLOCK_LEN - 1;  /* Number of Full Blocks Received - the Random Initialization Vector */

   for ( i = 0; i <= nBlocks; i++ )
      {
      if ( aes_decrypt ( ucBuffer [ i ], ucBuffer [ i ], &g_ctxAESDec ) == EXIT_FAILURE )
         {
         WriteCon ( "CntGetAESEncryptedUDPPacket():  Bad AES Block!\n\a" );
         g_ulErrors++;

         SetLastError ( E_ENCRYPT_BAD_AES_BLOCK );
         return 0U;
         }
      }

/*
 * Unchain the Blocks
 */
   for ( i = nBlocks - 1; i >= 0; i-- )
      for ( j = AES_BLOCK_LEN - 1; j >= 0; j-- )
         ucBuffer [ i + 1 ] [ j ] ^= ucBuffer [ i ] [ j ];

/*
 * Locate the Unencrypted Payload
 */
   lpUDPPacket = ( LPUDPPACKET ) ucBuffer [ 1 ];

/*
 * Check the packet size.  If it is greater than the maximum packet size, the most likely
 * cause would be that the encryption failed and lpUDPPacket->cbBytes was improperly
 * decrypted.  Corrupted values that fall between 1 and the maximum packet size will be
 * detected via the checksum.
 */
   if ( lpUDPPacket->cbBytes < 1 || lpUDPPacket->cbBytes > g_cbMaxAESEncryptedUDPPacketSize )
      {
      WriteCon ( "CntGetAESEncryptedUDPPacket():  The Packet Size is Invalid!\n\a" );
      g_ulErrors++;

      SetLastError ( E_ENCRYPT_BAD_PACKET_SIZE );
      return 0U;
      }

/*
 * Check the CRC Checksum
 */

   if ( ! ChkCRC32 ( lpUDPPacket, lpUDPPacket->cbBytes, NULL ) )
      {
      WriteCon ( "CntGetAESEncryptedUDPPacket():  The CCITT-CRC32 Checksum Failed!\n\a" );
      g_ulErrors++;

      SetLastError ( E_ENCRYPT_BAD_CHECKSUM );
      return 0U;
      }

/*
 * Check that the Clock Times are Within the Specified Time Differential
 */
   GetSystemTime ( &stSystemTime );

   dblTimeNow = CAL2JD ( stSystemTime.wMonth, stSystemTime.wDay, stSystemTime.wYear, stSystemTime.wHour, stSystemTime.wMinute, stSystemTime.wSecond, stSystemTime.wMilliseconds );
   dblTimeMsg = lpUDPPacket->lnDate + 1721424.5 + lpUDPPacket->lnTime / 86400000.0;

   if ( fabs ( dblTimeNow - dblTimeMsg ) > g_dblTimeDifferential )
      {
      fprintf ( stderr, "CntGetAESEncryptedUDPPacket():  The Message Time is Out of Range by %.3f sec!\n", ( dblTimeNow - dblTimeMsg ) / g_dblOneSecond );
      g_ulErrors++;

      SetLastError ( E_ENCRYPT_BAD_TIME );
      return 0U;
      }

/*
 * Return the Packet Sequence Number
 */
   if ( pdwSequenceNumber ) * pdwSequenceNumber = lpUDPPacket->dwSequenceNumber;

/*
 * Return the Payload
 */
   cbPayload = lpUDPPacket->cbBytes - sizeof ( UDPPACKET ) + 1U;

   memcpy ( pvBuffer, lpUDPPacket->ucPayload, min ( cbBuffer, cbPayload ) );

/*
 * Return the Payload Size
 */
   return cbPayload;

   }  /* size_t CntGetAESEncryptedUDPPacket ( SOCKET uUDPSocket, void * pvBuffer, size_t cbBuffer ) */

DateTime.c

/*********************************************************************************************
* Copyright (c) 2008 - 2010 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
*********************************************************************************************/

#include <TIME.H>

#include "DateTime.h"

#pragma warning ( disable : 4996 )

#define FALSE 0
#define TRUE ( ~FALSE )

typedef unsigned short int WORD;

typedef struct _SYSTEMTIME {

   WORD wYear;
   WORD wMonth;
   WORD wDayOfWeek;
   WORD wDay;
   WORD wHour;
   WORD wMinute;
   WORD wSecond;
   WORD wMilliseconds;

} SYSTEMTIME, * PSYSTEMTIME, * LPSYSTEMTIME;

extern __declspec ( dllimport ) void __stdcall GetSystemTime ( LPSYSTEMTIME lpSystemTime );

static BOOL g_fTzSet = FALSE;

/*********************************************************************************************************************
*                                                                                                                    *
*  MDY2GD and GD2MDY Derived from Algorithm 199 of the Collected Algorithms of the ACM                               *
*  see http://portal.acm.org/citation.cfm?doid=366707.390020                                                         *
*                                                                                                                    *
*  The functions MDY2GD() and GD2MDY() convert integer Gregorian Day Number back and forth between calendar dates.   *
*  The Gregorian Calendar was established in 1582 by Pope Gregory XIII and is the calendar that we currently use.    *
*  The Gregorian Day Number, modulo 7, returns a day of the week index where Sunday = 0.                             *
*                                                                                                                    *
*  The functions CAL2JD() and CALUTC() convert double precision floating point astronomical Julian Day number        *
*  back and forth between calendar dates.  Because of its astronomical origins, the Julian Day number changes        *
*  at noon so that it remains the same during a night of observations.                                               *
*                                                                                                                    *
*  "A full discussion of 'Julian Date' is likewise beyond the scope of this manual. It is                            *
*  interesting to note, however, that 'Julian Date' 0,0 was Greenwich Mean Time at noon                              *
*  on January 1, 4713 BC. It is a time scale widely used by astronomers because it is                                *
*  unambiguous, employs no leap-years, and because a single number represents both date                              *
*  and time. For convenience, Gemini's display of 'Julian Date' also includes the day of the                         *
*  week for the longitude of Greenwich, England."                                                                    *
*                                                                                                                    *
*  http://www.losmandy.com/losmandygoto/gemini_manual.pdf                                                            *
*                                                                                                                    *
*  Convert from Month/Day/Year to the Gregorian Day Index                                                            *
*                                                                                                                    *
*  month = 1 to 12                                                                                                   *
*  day   = ? to ?                                                                                                    *
*  year  = 1 to < 32768                                                                                              *
*********************************************************************************************************************/

long int MDY2GD ( int nMonth, int nDay, int nYear )

   {  /*                                     Jan   Feb   Mar   Apr   May   Jun   Jly   Aug   Sep   Oct   Nov   Dec   */
   static const int  nDays [ 13 ] = {    0,    0,  -31,  306,  275,  245,  214,  184,  153,  122,   92,   61,   31 };
   static const int  nBias [ 13 ] = {    0,    1,    1,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0 };

   long  nYears, nDate;

   nYears = nYear - nBias [ nMonth ];

   nDate = ( ( nYears / 100 ) * 146097l ) / 4
         + ( ( nYears % 100 ) *    1461 ) / 4
         - nDays [ nMonth ]
         + nDay;

   return nDate;

   }  /* long MDY2GD ( int nMonth, int nDay, int nYear ) */

/* Convert from Gregorian Day Index to Month/Day/Year */

void GD2MDY ( long int lnDate, int * pnMonth, int * pnDay, int * pnYear )

   {     /*                            Jan   Feb   Mar   Apr   May   Jun   Jly   Aug   Sep   Oct   Nov   Dec   */
   static const int  nBias [ 12 ] = {    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,  -10,  -10 };
   long              lnLD, lnYr, lnMo, lnDy;

   lnLD = 4 * ( lnDate + 306 ) - 1;

   lnYr = ( lnLD / 146097l ) * 100;
   lnDy = ( lnLD % 146097l ) /   4;

   lnLD = 4 * lnDy + 3;

   lnYr = ( lnLD / 1461 )     + lnYr;
   lnDy = ( lnLD % 1461 ) / 4 + 1;

   lnLD = 5 * lnDy - 3;

   lnMo = ( lnLD / 153 )     + 1;
   lnDy = ( lnLD % 153 ) / 5 + 1;

   * pnMonth   = ( int ) ( lnMo + nBias [ lnMo - 1 ] );
   * pnDay     = ( int ) ( lnDy );
   * pnYear    = ( int ) ( lnYr + lnMo/11 );

   }  /* void GD2MDY ( long lnDate, int * pnMonth, int * pnDay, int * pnYear ) */

/* Convert From Mo/Dy/Year hh:mm:ss.ms to the Julian Day Number */

double CAL2JD ( int nMo, int nDy, int nYear, int nHr, int nMn, int nSc, int nMs )

   {

   return   ( ( double ) MDY2GD ( nMo, nDy, nYear )   /* Gregorian Day Index        */

            + ( double ) nHr /       24.0             /* Hours Fraction             */
            + ( double ) nMn /     1440.0             /* Minutes Fraction           */
            + ( double ) nSc /    86400.0             /* Seconds Fraction           */
            + ( double ) nMs / 86400000.0             /* Milliseconds Fraction      */

            + 1721424.5 );                            /* Julian Day Number Offset   */

   }  /* double CAL2JD ( int nMo, int nDy, int nYear, int nHr, int nMn, int nSc, int nMs ) */

/* Convert From Julian Day Number To Mo/Dy/Year hh:mm:ss.ms */

void JD2CAL ( double jdDateTime, int * lpnMo, int * lpnDy, int * lpnYear, int * lpnHr, int * lpnMn, int * lpnSc, int * lpnMs )

   {
   long     lnTime;
   double   gdDate;

   /* Convert the Julian Day Number to the Gregorian Day Number                           */

   gdDate = jdDateTime - 1721424.5;                   /* Julian Day Number Offset         */

   /* Convert the Gregorian Day to the Gregorian Calendar Month, Day and lpnYear          */

   GD2MDY ( ( long ) gdDate, lpnMo, lpnDy, lpnYear ); /* Gregorian Day Index              */

   /* Extract the Gregorian Day Fraction ( 0.0 <= fraction < 1.0 ) and convert            */
   /* it into Milliseconds per Day:                                                       */

   /* Milliseconds per Day = Milliseconds per Second                                      */
   /*                      * Seconds      per Minute                                      */
   /*                      * Minutes      per Hour                                        */
   /*                      * Hours        per Day                                         */

   /* 1000 * 60 * 60 * 24 = 86400000                                                      */

   /* ( 0 <= lnTime < 86400000 )                                                          */

   lnTime = ( long ) ( ( gdDate - ( double ) ( ( long ) gdDate ) ) * 86400000.0 + 0.5 );

   /* Convert the Milliseconds to Hours, Minutes, Seconds and Milliseconds:               */
   /*                                                                                     */
   /* Unit = mod ( Milliseconds / Milliseconds per Unit, Units )                          */

   if ( lpnHr ) * lpnHr = ( int ) ( ( lnTime /  3600000L ) %   24L );   /* Hours          */
   if ( lpnMn ) * lpnMn = ( int ) ( ( lnTime /    60000L ) %   60L );   /* Minutes        */
   if ( lpnSc ) * lpnSc = ( int ) ( ( lnTime /     1000L ) %   60L );   /* Seconds        */

   if ( lpnMs ) * lpnMs = ( int ) ( ( lnTime /        1L ) % 1000L );   /* Milliseconds   */

   }  /* void JD2CAL ( double jdDateTime, int * lpnMo, int * lpnDy, int * lpnYear, int * lpnHr, int * lpnMn, int * lpnSc, int * lpnMs ) */

void GetTzInfo ( int * pnTimeZoneOffsetInHours, int * pfUseDaylightSavingsTime )

   {

   _tzset();

   * pnTimeZoneOffsetInHours  = -( _timezone / 3600L );
   * pfUseDaylightSavingsTime = _daylight;

   }  /* void GetTzInfo ( int * pnTimeZoneOffsetInHours, int * pfUseDaylightSavingsTime ) */

/* Compute the Starting and Ending Daylight Savings Times, for this Timezone, Adjusted to UTC Julian Day Numbers (NOT Civil) */

BOOL Year2DST ( int nYear, int nTimeZoneOffsetInHours, double * putcBeg, double * putcEnd )

   {
   int      nMo = 0, nDy = 0;
   double   dblTimeZoneOffset = nTimeZoneOffsetInHours / 24.0;

   /***************************************************************************************************
   *  "Starting in 2007, daylight time begins in the United States on the second Sunday in March      *
   *  and ends on the first Sunday in November. On the second Sunday in March, clocks are set ahead   *
   *  one hour at 2:00 a.m. local standard time, which becomes 3:00 a.m. local daylight time. On      *
   *  the first Sunday in November, clocks are set back one hour at 2:00 a.m. local daylight time,    *
   *  which becomes 1:00 a.m. local standard time. These dates were established by the                *
   *  Energy Policy Act of 2005, Pub. L. no. 109-58, 119 Stat 594 (2005)."                            *
   *                                                                                                  *
   *  see http://aa.usno.navy.mil/faq/docs/daylight_time.php                                          *
   *                                                                                                  *
   *  Compute the First Day of Daylight Savings Time for the Specified Year                           *
   *                                                                                                  *
   *  Note: Remember that the gd() of the last day of the prior month is the                          *
   *        same as the gd() of day zero of the current month.  The expression                        *
   *        Lo = gd ( 5, 0, nYear ), or day zero of May, returns the Gregorian                        *
   *        Day Index of April 30 of the specified year.  By taking advantage                         *
   *        of the fact that the Gregorian Day Index, modulo 7, returns a value                       *
   *        of 0 - 6 where 0 = Sunday, the expression "Lo = gd(5,0,nYear)/7*7;"                       *
   *        effectively truncates the date to the last sunday of the prior                            *
   *        month (April).                                                                            *
   *                                                                                                  *
   *        The expression "Lo = gd(4,0,nYear)/7*7 + 7;" takes advantage of the                       *
   *        fact that the second Sunday of the current month occurs 14 days after                     *
   *        the last Sunday of the prior month and the first Sunday of the current                    *
   *        month occurs 7 days after the last Sunday of the prior month.                             *
   *                                                                                                  *
   *        It starts at 2:00 a.m. (3:00 a.m. DST)                                                    *
   *        It ends   at 1:00 a.m. (2:00 a.m. DST)                                                    *
   *                                                                                                  *
   *  Only Handle Years After 2007                                                                    *
   *                                                                                                  *
   ***************************************************************************************************/

   if ( nYear < 2007 )
      return FALSE;

   /* Compute the First Day of Daylight Savings Time for the Specified Year   */

   GD2MDY ( MDY2GD ( 3, 0, nYear ) / 7 * 7 + 14, &nMo, &nDy, &nYear );
   * putcBeg = CAL2JD ( nMo, nDy, nYear, 2, 0, 0, 0 ) - dblTimeZoneOffset;

   /* Compute the Last Day of Daylight Savings Time for the Specified Year    */

   GD2MDY ( MDY2GD ( 11, 0, nYear ) / 7 * 7 + 7, &nMo, &nDy, &nYear );
   * putcEnd = CAL2JD ( nMo, nDy, nYear, 1, 0, 0, 0 ) - dblTimeZoneOffset;

   /* Return Success!   */

   return TRUE;

   }  /* BOOL Year2DST ( int nYear, int nTimeZoneOffsetInHours, double * putcBeg, double * putcEnd ) */

/* Convert from a UTC Date/Time Index to a Civil Date/Time Index and Tell Me if Daylight Savings Time is In Effect */

double UTC2Civil ( double utcDateTime, BOOL * pfDaylightSavingsInEffect, int nTimeZoneOffsetInHours, BOOL fUseDaylightSavingsTime )

   {
   double   civDateTime    = 0.0;

   double   utcBegDST      = 0.0;
   double   utcEndDST      = 0.0;

   int      nMonth         = 0;
   int      nDay           = 0;
   int      nYear          = 0;

   int      nHour          = 0;
   int      nMinute        = 0;
   int      nSecond        = 0;

   int      nMillisecond   = 0;

   /* Default to NOT Using Daylight Savings Time               */

   if ( pfDaylightSavingsInEffect )
      * pfDaylightSavingsInEffect = FALSE;

   /* Convert from UTC to Civil Time                           */

   civDateTime = utcDateTime + nTimeZoneOffsetInHours / 24.0;

   /* Adjust for Daylight Savings Time if Required             */

   if ( fUseDaylightSavingsTime )
      {

      /* Determine the UTC Year                                */

      JD2CAL ( utcDateTime, &nMonth, &nDay, &nYear, &nHour, &nMinute, &nSecond, &nMillisecond );

      /* Only Handle Years After 2007                          */

      if ( nYear < 2007 )
         return 0.0;

      /* Find Out When Daylight Savings Time Starts and Stops  */

      Year2DST ( nYear, nTimeZoneOffsetInHours, &utcBegDST, &utcEndDST );

      /* Handle the Daylight Savings Time Adjustment           */

      if ( utcDateTime >= utcBegDST && utcDateTime < utcEndDST )
         {
         if ( pfDaylightSavingsInEffect )
            * pfDaylightSavingsInEffect = TRUE;

         civDateTime += 1.0 / 24.0;
         }

      }  /* End - Adjust for Daylight Savings Time if Required */

   /* Return the Adjusted Time                                 */

   return civDateTime;

   }  /* double UTC2Civil ( double utcDateTime, BOOL * pfDaylightSavingsInEffect, int nTimeZoneOffsetInHours, BOOL fUseDaylightSavingsTime ) */

/* Convert from a Civil Date/Time Index to a UTC Date/Time Index and Tell Me if Daylight Savings Time Ambiguity */

double Civil2UTC ( double civDateTime, BOOL * pfDaylightSavingsAmbiguity, int nTimeZoneOffsetInHours, BOOL fUseDaylightSavingsTime )

   {
   double   utcDateTime = 0.0;
   int      nMonth = 0, nDay = 0, nYear = 0, nHour = 0, nMinute = 0, nSecond = 0, nMillisecond = 0;
   double   utcBegDST = 0.0, utcEndDST = 0.0;

   /* Default to No Ambiguity                                  */

   if ( pfDaylightSavingsAmbiguity )
      * pfDaylightSavingsAmbiguity = FALSE;

   /* Convert from Civil Time to UTC                           */

   utcDateTime = civDateTime - nTimeZoneOffsetInHours / 24.0;

   /* Adjust for Daylight Savings Time if Required             */

   if ( fUseDaylightSavingsTime )
      {

      /* Determine the UTC Year                                */

      JD2CAL ( civDateTime, &nMonth, &nDay, &nYear, &nHour, &nMinute, &nSecond, &nMillisecond );

      /* Only Handle Years After 2007                          */

      if ( nYear < 2007 )
         return 0.0;

      /* Find Out When Daylight Savings Time Starts and Stops  */

      Year2DST ( nYear, nTimeZoneOffsetInHours, &utcBegDST, &utcEndDST );

      /* Handle the Daylight Savings Time Adjustment           */

      if ( utcDateTime >= utcBegDST && utcDateTime < utcEndDST )
         {
         utcDateTime -= 1.0 / 24.0;

         if ( pfDaylightSavingsAmbiguity )
            {
            * pfDaylightSavingsAmbiguity = utcDateTime < ( utcBegDST + 1.0 / 24.0 ) || utcDateTime > ( utcEndDST - 1.0 / 24.0 );
            }
         }

      }  /* End - Adjust for Daylight Savings Time if Required */

   /* Return the Adjusted Time                                 */

   return utcDateTime;

   }  /* double Civil2UTC ( double civDateTime, BOOL * pfDaylightSavingsAmbiguity, int nTimeZoneOffsetInHours, BOOL fUseDaylightSavingsTime ) */

double CurrentTime ( void )

   {
   SYSTEMTIME stSystemTime = { 0 };

   GetSystemTime ( &stSystemTime );

   return CAL2JD ( stSystemTime.wMonth, stSystemTime.wDay, stSystemTime.wYear, stSystemTime.wHour, stSystemTime.wMinute, stSystemTime.wSecond, stSystemTime.wMilliseconds );

   }  /* double CurrentTime ( void ) */

/*
 * GetCivilTimeStamp takes a UTC Julian Day Number and Converts it into a TIMESTAMP_STRUCT for ODBC and SQL Server
 */

TIMESTAMP_STRUCT GetCivilTimeStamp ( double utcDateTime )

   {
   TIMESTAMP_STRUCT  stCivilTime    = { 0 };

   double            civDateTime    = 0.0;

   int               nMonth         = 0;
   int               nDay           = 0;
   int               nYear          = 0;
   int               nHour          = 0;
   int               nMinute        = 0;
   int               nSecond        = 0;
   int               nMillisecond   = 0;

   /* Convert the UTC Julian Day Number to a Civil Time Julian Day Number */

   civDateTime = UTC2Civil ( utcDateTime, NULL, -( _timezone / 3600L ), _daylight );

   /* Convert the Civil Time Julian Day Number into Months, Days, Years, Hours, Minutes, Seconds and Milliseconds */

   JD2CAL ( civDateTime, &nMonth, &nDay, &nYear, &nHour, &nMinute, &nSecond, &nMillisecond );

   /* Store the Date and Time into the TIMESTAMP_STRUCT */

   stCivilTime.month    = ( SQLUSMALLINT  ) nMonth;
   stCivilTime.day      = ( SQLUSMALLINT  ) nDay;
   stCivilTime.year     = ( SQLSMALLINT   ) nYear;
   stCivilTime.hour     = ( SQLUSMALLINT  ) nHour;
   stCivilTime.minute   = ( SQLUSMALLINT  ) nMinute;
   stCivilTime.second   = ( SQLUSMALLINT  ) nSecond;
   stCivilTime.fraction = ( SQLUINTEGER   ) ( nMillisecond * 1000000LU );

   /* Return the TIMESTAMP_STRUCT Representing the Date and Time as Civil Time */

   return stCivilTime;

   }  /* TIMESTAMP_STRUCT GetCivilTimeStamp ( STDISHSIGNALS & stDishSignals ) */

void DumpJD2UTC ( FILE * hFile, char * szLegend, double dblTimeUTC )

   {
   int nMo     = 0;
   int nDy     = 0;
   int nYear   = 0;
   int nHr     = 0;
   int nMn     = 0;
   int nSc     = 0;
   int nMs     = 0;

   JD2CAL ( dblTimeUTC, &nMo, &nDy, &nYear, &nHr, &nMn, &nSc, &nMs );

   fprintf ( hFile, "%s%2.2d/%2.2d/%4.4d %2.2d:%2.2d:%2.2d.%3.3d GMT\n", szLegend, nMo, nDy, nYear, nHr, nMn, nSc, nMs ); 

   }  /* void DumpJD2UTC ( FILE * hFile, char * szLegend, double dblTime ) */

void DumpJD2Civ ( FILE * hFile, char * szLegend, double dblTimeUTC )

   {
   int   nMo   = 0;
   int   nDy   = 0;
   int   nYear = 0;
   int   nHr   = 0;
   int   nMn   = 0;
   int   nSc   = 0;
   int   nMs   = 0;

   BOOL fDST   = FALSE;

   /* Convert to Civil Time */

   if ( ! g_fTzSet )
      {
      _tzset();
      g_fTzSet = TRUE;
      }

   JD2CAL ( UTC2Civil ( dblTimeUTC, &fDST, -( _timezone / 3600L ), _daylight ), &nMo, &nDy, &nYear, &nHr, &nMn, &nSc, &nMs );

   fprintf ( hFile, "%s%2.2d/%2.2d/%4.4d %2.2d:%2.2d:%2.2d.%3.3d %s\n", szLegend, nMo, nDy, nYear, nHr, nMn, nSc, nMs, fDST ? "MDT" : "MST" ); 

   }  /* void DumpJD2Civ ( FILE * hFile, char * szLegend, double dblTime ) */

char * myctime ( const time_t * plnTime )

   {
   static const char * pszMonth     []       = { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly", "Aug", "Sep", "Oct", "Nov", "Dec" };
   static const char * pszDayOfWeek []       = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
   static char       szTime         [ 26 ]   = { 0 };

   long              lnTime                  = ( long ) ( * plnTime );
   long              gdNow                   = ( lnTime / 86400L ) + 719163L;
   double            dblTime                 = ( lnTime % 86400L ) / 86400.0;
   double            dblTimeUTC              = gdNow + dblTime + 1721424.5;

   int               nMo                     = 0;
   int               nDy                     = 0;
   int               nYear                   = 0;
   int               nHr                     = 0;
   int               nMn                     = 0;
   int               nSc                     = 0;
   int               nMs                     = 0;

   BOOL              fDST                    = FALSE;

   unsigned          uDayOfWeek              = 0U;

   /* Convert from UTC to Local Time */

   if ( ! g_fTzSet )
      {
      _tzset();
      g_fTzSet = TRUE;
      }

   JD2CAL ( UTC2Civil ( dblTimeUTC, &fDST, -( _timezone / 3600L ), _daylight ), &nMo, &nDy, &nYear, &nHr, &nMn, &nSc, &nMs );

   uDayOfWeek = MDY2GD ( nMo, nDy, nYear ) % 7L;

   /* Returned as "Mon Dec 15 19:41:22 2008\n\0" */

   _snprintf ( szTime, sizeof szTime, "%s %s %2d %2.2d:%2.2d:%2.2d %4.4d\n", pszDayOfWeek [ uDayOfWeek ], pszMonth [ nMo ], nDy, nHr, nMn, nSc, nYear );

   return szTime;

   }  /* char * myctime ( const time_t * plnTime ) */

void TimeStamp ( long * plnDate, long * plnMilliseconds )

   {
   SYSTEMTIME stSystemTime = { 0 };

   GetSystemTime ( &stSystemTime );

   * plnDate         = MDY2GD ( stSystemTime.wMonth, stSystemTime.wDay, stSystemTime.wYear );
   * plnMilliseconds = ( ( stSystemTime.wHour * 60L + stSystemTime.wMinute ) * 60L + stSystemTime.wSecond ) * 1000L + stSystemTime.wMilliseconds;

   }  /* void TimeStamp ( long * plnDate, long * plnMilliseconds ) */

ErrorTxt.c

/*********************************************************************************************
* Copyright (c) 2002 - 2009 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
*********************************************************************************************/

#define WIN32_LEAN_AND_MEAN                              /* Exclude Rarely-Used Stuff from Windows Headers  */

#include <WINDOWS.H>                                     /* Windows OS Prototypes and Defines               */

#include "ErrorTxt.h"

extern size_t GetErrorText ( DWORD dwErrorCode, char * szErrorText, size_t cbErrorText )

   {
   int      i        = 0;
   size_t   cbBytes  = 0U;

/*
 * Retrieve the Error Message from the System Message Table
 */
   memset ( szErrorText, 0, cbErrorText );               /* Zero Out the Error Text Buffer                  */

   cbBytes = FormatMessage (

      FORMAT_MESSAGE_FROM_SYSTEM,                        /* Search the System Message-Table                 */
      NULL,                                              /* Module Handle                                   */
      dwErrorCode,                                       /* Message ID                                      */
      MAKELANGID ( LANG_ENGLISH, SUBLANG_ENGLISH_US ),   /* Message Language                                */
      szErrorText,                                       /* Address of Buffer Pointer                       */
      cbErrorText - 1,                                   /* Minimum Buffer Size                             */
      NULL                                               /* No Other Arguments                              */

   );

   if ( ! cbBytes )
      return 0U;

   // Convert '\n' and '\r' to ' '

   for ( i = 0; szErrorText [ i ]; i++ )
      {
      if ( szErrorText [ i ] == '\r' ) szErrorText [ i ] = '~';
      if ( szErrorText [ i ] == '\n' ) szErrorText [ i ] = '~';
      }

   // Find Last Non-Blank Character

   for ( --i; i >= 0 && szErrorText [ i ] == '~'; i-- );

   // Addjust For Empty String

   for ( i++; i < 0; i++ );

   // Terminate String

   szErrorText [ i ] = '\0';

   return i;

   }  /* extern BOOL GetErrorText ( DWORD dwErrorCode, char * szErrorText, size_t cbErrorText ) */

WriteCon.c

/***************************************************************************************
* Copyright (c) 2002 - 2010 Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
***************************************************************************************/

#define _WIN32_WINNT 0x0400            // Use the Advanced Components of Windows NT ( includes SwitchToThread() )

#define WIN32_LEAN_AND_MEAN            // Exclude rarely-used stuff from Windows headers

#include <WINDOWS.H>                   // SwitchToThread()

#include <IO.H>                        // _open_osfhandle()
#include <FCNTL.H>                     // _O_TEXT
#include <conio.h>                     // _cprintf()
#include <stdio.h>                     // fprintf(), _vsnprintf(), stderr

#include "WriteCon.h"                  // The WriteCon() Prototype

static volatile LONG lSpinCount  = 0L; // The SpinLock

// Write a Message to the System Console.  This function is Thread Synchronized
// by the lSpinCount SpinLock to prevent interleaved messages.  Usinge _vsnprintf()
// to encode the message to a buffer allows the possibility of expanding this function to
// duplicate the message to a log file in the future.  A maximum of 8K - 1 Bytes can be
// output with a single write.

extern int WriteCon ( const char szFormat[], ... )

   {
   char     szBuffer [ 1024 * 8 ]   = { 0 };

   va_list  pArgPtr                 = NULL;
   size_t   cbBuffer                = sizeof szBuffer;
   int      nBytes                  = 0;

   // Use the Format and Argument List to Encode the Buffer

   va_start ( pArgPtr, szFormat );
   nBytes = _vsnprintf ( szBuffer, cbBuffer - 1, szFormat, pArgPtr );
   va_end   ( pArgPtr );

   if ( nBytes )
      {

      // Wait for Critical Section

      while ( InterlockedIncrement ( ( LPLONG ) &lSpinCount ) != 1 )
         {
         InterlockedDecrement ( ( LPLONG ) &lSpinCount );
         SwitchToThread();             // We are Blocked Because of Another Thread so Relinquish to Them
         }

      // Critical Section Begins

      __try
         {
         __try
            {

            // Output the Buffer to the Console

            _cprintf ( szBuffer );
            }
         __finally
            {
            InterlockedDecrement ( ( LPLONG ) &lSpinCount );
            }
         }
      __except ( EXCEPTION_EXECUTE_HANDLER )
         {
         DWORD dwException = GetExceptionCode();
#ifdef __AFX_H__  // Only Include in the AFX Version
         TRACE ( "WriteCon():  An Exception ( 0x%lX ) Occurred!\n", dwException );
#else    // __AFX_H__
         fprintf ( stderr, "WriteCon():  An Exception ( 0x%lX ) Occurred!\n", dwException );
#endif   // __AFX_H__         return 0;
         }
      }

   return nBytes;

   }  // extern int WriteCon ( const char szFormat[], ... )

// Allocate a Console and Redirect our I/O to it - see:  http://www.halcyon.com/~ast/dload/guicon.htm

void RedirectIoToConsole ( LPCTSTR lpConsoleTitle )

   {
   static const WORD          wMaxConsoleLines           = 25U;
   int                        hConsoleHandle             = 0;
   long                       lnStdHandle                = 0L;
   CONSOLE_SCREEN_BUFFER_INFO stConsoleScreenBufferInfo  = { 0LU };
   FILE                       * pFile                    = NULL;

   // Allocate a Console for This App

   AllocConsole();

   // Set the Console Title

   if ( lpConsoleTitle )
      SetConsoleTitle ( lpConsoleTitle );

   // Set the Screen Buffer to the Normal 25 Lines

   GetConsoleScreenBufferInfo ( GetStdHandle ( STD_OUTPUT_HANDLE ), &stConsoleScreenBufferInfo );

   stConsoleScreenBufferInfo.dwSize.Y = wMaxConsoleLines;

   SetConsoleScreenBufferSize ( GetStdHandle ( STD_OUTPUT_HANDLE ), stConsoleScreenBufferInfo.dwSize );

   // Set the Text Color

// SetConsoleTextAttribute ( GetStdHandle ( STD_OUTPUT_HANDLE ), FOREGROUND_GREEN | FOREGROUND_INTENSITY );

   // Redirect Unbuffered STDOUT to the Console

   lnStdHandle = ( long ) GetStdHandle ( STD_OUTPUT_HANDLE );

   hConsoleHandle = _open_osfhandle ( lnStdHandle, _O_TEXT );

   pFile = _fdopen ( hConsoleHandle, "w" );

   * stdout = * pFile;

   setvbuf ( stdout, NULL, _IONBF, 0 );

   // Redirect Unbuffered STDIN to the Console

   lnStdHandle = ( long ) GetStdHandle ( STD_INPUT_HANDLE );

   hConsoleHandle = _open_osfhandle ( lnStdHandle, _O_TEXT );

   pFile = _fdopen ( hConsoleHandle, "r" );

   * stdin = * pFile;

   setvbuf ( stdin, NULL, _IONBF, 0 );

   // Redirect Unbuffered STDERR to the Console

   lnStdHandle = ( long ) GetStdHandle ( STD_ERROR_HANDLE );

   hConsoleHandle = _open_osfhandle ( lnStdHandle, _O_TEXT );

   pFile = _fdopen ( hConsoleHandle, "w" );

   * stderr = * pFile;

   setvbuf ( stderr, NULL, _IONBF, 0 );

   }  // void RedirectIoToConsole ( LPCTSTR lpConsoleTitle )

HiRes.cpp

/***************************************************************************************
* Copyright (c) 2002 - 2010 Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
***************************************************************************************/

#define WIN32_LEAN_AND_MEAN            // Exclude rarely-used stuff from Windows headers

#include <WINDOWS.H>                   // SwitchToThread()

#include "HiRes.h"                     // CHiResTimer Prototypes and Defines

CHiResTimer::CHiResTimer()

   {

   QueryPerformanceFrequency ( ( LARGE_INTEGER * ) &qwFrequency );

   // Initialize Times to Zero

   qwBegTime = 0UI64;
   qwEndTime = 0UI64;

   }  // CHiResTimer::CHiResTimer()

void CHiResTimer::Start ( void )

   {

   QueryPerformanceCounter ( ( LARGE_INTEGER * ) &qwBegTime );

   }  // void CHiResTimer::Start ( void )

void CHiResTimer::Stop ( void )

   {

   QueryPerformanceCounter ( ( LARGE_INTEGER * ) &qwEndTime );

   }  // void CHiResTimer::Stop ( void )

double CHiResTimer::ElapsedTimeInSeconds ( void )

   {
   QWORD    qwTicks;
   double   ElapsedTime;

   if ( ! qwBegTime || ! qwEndTime ) return 0.0;

   qwTicks = qwEndTime - qwBegTime;

   ElapsedTime =   ( double ) ( ( unsigned long ) ( qwTicks / qwFrequency ) )
               + ( ( double ) ( ( unsigned long ) ( qwTicks % qwFrequency ) )
                 / ( double ) ( ( unsigned long ) ( qwFrequency           ) ) );

   return ElapsedTime;  // In Seconds

   }  // double CHiResTimer::ElapsedTimeInSeconds ( void )

Server.c

/************************************************************************************************
*                                                                                               *
* Copyright (c) 2009 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342           *
*                                                                                               *
*  This code implements the UDP Socket Server application with AES encryption,                  *
*                                                                                               *
*  The AES (Rijndael) Encryption code comes from:                                               *
*                                                                                               *
*     "http://gladman.plushost.co.uk/oldsite/AES/aes-src-16-04-07.zip"                          *
*     (see:  "http://gladman.plushost.co.uk/oldsite/AES/index.php " for more info)              *
*                                                                                               *
*  You will need to extract aescrypt.c, aeskey.c, aestab.c, aes.h, aesopt.h, aestab.h,          *
*  brg_endian.h and brg_types.h from aes-src-16-04-07.zip and put them in the same directory    *
*  as the rest of the source files.                                                             *
*                                                                                               *
*  To compile the application from the command line:                                            *
*                                                                                               *
*     "CL Server.c aescrypt.c aeskey.c aestab.c Cancode.c CRC.c Crypto.c DateTime.c WriteCon.c" *
*                                                                                               *
************************************************************************************************/

// #define VERBOSE

#define WIN32_LEAN_AND_MEAN

#pragma warning ( disable : 4514 )                                      /* "unreferenced inline function has been removed"                   */

#pragma warning ( push, 3 )                                             /* Suppress Warnings from WINDOWS.H and WINSOCK2.H                   */
#include <WINSOCK2.H>                                                   /* Windows Sockets Version 2.0                                       */
#pragma warning ( pop )                                                 /* Return to Normal Processing                                       */

#include <STDDEF.H>                                                     /* Definitions/Declarations for Common Constants, Types, Variables   */
#include <STDLIB.H>                                                     /* Definitions/Declarations for Commonly Used Library Routines       */

#include "CRC.h"                                                        /* CRC Error Checking Function Protypes and Defines                  */
#include "Crypto.h"                                                     /* The Cryptography Code                                             */
#include "CanCode.h"                                                    /* The Compressed Alphanumeric Function Prototypes and Defines       */
#include "DateTime.h"                                                   /* The Date and Time Prototypes and Defines                          */

#pragma comment ( lib, "ws2_32.lib" )                                   /* Include the Library to Link the Functions Defined in WINSOCK2.H   */

#define DEFAULT_PORT 50001U                                             /* The UDP Port Number                                               */

#define RANGE(SPECIFIED_VALUE,MIN_VALUE,MAX_VALUE) min ( max ( ( SPECIFIED_VALUE ), ( MIN_VALUE ) ), ( MAX_VALUE ) )

#define CMD_DES   0x000019DB                                            /* Des   - (RO) System Description                                   */
#define CMD_MAN   0x00005176                                            /* Man   - (RW) Manual Mode                                          */
#define CMD_REV   0x0000715E                                            /* Rev   - (RO) Software Revision Level                              */
#define CMD_VAL   0x000089B4                                            /* Val   - (RW) Example Values                                       */

static const char g_szDesc[]     = "AES Encrypted UDP Server Rev 1.0";  /* The UDP Server Description and Revision Number                    */
BOOL              g_fMan         = FALSE;                               /* TRUE = We are in Manual Mode, FALSE = We are in Automatic Mode    */
int               g_anVal [ 10 ] = { 0 };                               /* Array of Integer Values                                           */

/*
 * Detect and Honor all of the Normal Shutdown Events, Including Ctrl+C and Ctrl+Break
 */

BOOL g_fShutDownRequested = FALSE;

static BOOL WINAPI ControlHandler ( DWORD dwCtrlType )

   {

   switch ( dwCtrlType )
      {
      case CTRL_C_EVENT:               /* Ctrl+C at the Keyboard           */
      case CTRL_BREAK_EVENT:           /* Ctrl+Break at the Keyboard       */
      case CTRL_CLOSE_EVENT:           /* Close at System Menu or Button   */
      case CTRL_LOGOFF_EVENT:          /* User Logoff Event                */
      case CTRL_SHUTDOWN_EVENT:        /* System Shutdown Event            */

         g_fShutDownRequested = TRUE;  /* Set Shutdown Requested           */

         return TRUE;

      default:  return FALSE;
      }

   }  /* static BOOL WINAPI ControlHandler ( DWORD dwCtrlType ) */

int RespondText ( SOCKET uUDPSocket, DWORD dwSequenceNumber, SOCKADDR_IN * psinUDPClient, size_t cbsinUDPClient, char * szResponse )

   {

/*
 * Send the Response
 */
#ifdef VERBOSE
   printf ( "%s\t\t\n", szResponse );
#endif   // VERBOSE

   return SvrPutAESEncryptedUDPPacket ( uUDPSocket, dwSequenceNumber, psinUDPClient, cbsinUDPClient, szResponse, strlen ( szResponse ) );

   }  /* int RespondText ( SOCKET uUDPSocket, SOCKADDR_IN * psinUDPClient, size_t cbsinUDPClient, char * szResponse ) */

size_t ProcessCommands ( char * szRequest, char * szResponse, size_t cbResponse )

   {
   DWORD dwCommand      = 0LU;         /* The CanCoded Commmand Value      */
   char  * pszCommand   = NULL;        /* Pointer to the Command String    */
   char  * pszValue     = NULL;        /* Pointer to the Value String      */
   char  * pszIndex     = NULL;        /* Pointer to the Index String      */

   int   nIndex         = 0;           /* Set to the Requested Array Index */

/*
 * Initialize
 */
   memset ( szResponse, 0, sizeof szResponse );

/*
 * Get the Command
 */
   if ( ( pszCommand = strtok ( szRequest, " " ) ) == NULL )
      pszCommand = szRequest;

   dwCommand = CanCode ( strupr ( pszCommand ) );

   switch ( dwCommand )
      {

   /*
    * Process a "Des" Command
    */
      case CMD_DES:
         {
         return _snprintf ( szResponse, cbResponse, g_szDesc );
         }

   /*
    * Process a "Man" Command - This is an Example of Setting a Boolean Value
    */
      case CMD_MAN:
         {
         if ( ( pszValue = strtok ( NULL, " " ) ) != NULL )
            {
            g_fMan = RANGE ( atoi ( pszValue ), 0, 1 );
            }

         return _snprintf ( szResponse, cbResponse, "Man %d", g_fMan );
         }

   /*
    * Process a "Rev" Command
    */
      case CMD_REV:
         {
         return _snprintf ( szResponse, cbResponse, strstr ( g_szDesc, "Rev" ) );
         }

   /*
    * Process a "Val" Command - This is an Example of Setting an Element in an Array
    */
      case CMD_VAL:
         {

      /*
       * "Val" with No Parameters Returns All Values
       */
         if ( ( pszIndex = strtok ( NULL, " " ) ) == NULL )
            {
            char  szValue  [  16 ]  = { 0 };       /* Area to Print the Value          */
            char  szBuffer [ 128 ]  = { 0 };       /* Area to Concatenate the Values   */

            strcpy ( szBuffer, "Val " );

            for ( nIndex = 0; nIndex < sizeof g_anVal / sizeof g_anVal [ 0 ]; nIndex++ )
               {
               sprintf ( szValue, "%d,", g_anVal [ nIndex ] ),
               strcat ( szBuffer, szValue );
               }

            szBuffer [ strlen ( szBuffer ) - 1 ] = '\0'; /* Remove the Trailing ',' */

            return _snprintf ( szResponse, cbResponse, "%s", szBuffer );
            }

      /*
       * "Val <index>" - Test for Legal Index
       */
         else
            {
            nIndex = atoi ( pszIndex );
            if ( nIndex < 0 || nIndex >= sizeof g_anVal / sizeof g_anVal [ 0 ] )
               {
               return _snprintf ( szResponse, cbResponse, "Val %d Illegal Index - Must Range Between 0 and %d", nIndex, sizeof g_anVal / sizeof g_anVal [ 0 ] - 1 );
               }
            }

      /*
       * "Val <index> <newvalue>"
       */
         if ( ( pszValue = strtok ( NULL, " " ) ) != NULL )
            {

         /*
          * Only Set to New Value if in Manual Mode
          */
            if ( ! g_fMan )
               {
               return _snprintf ( szResponse, cbResponse, "Must be in Manual Mode" );
               }

         /*
          * Set Value [ <index> ] to <NewValue> Within Range of 0 to 100
          */
            g_anVal [ nIndex ] = RANGE ( atoi ( pszValue ), 0, 100 );
            }

         return _snprintf ( szResponse, cbResponse, "Val %d %d", nIndex, g_anVal [ nIndex ] );
         }

   /*
    * The Command is Invalid
    */
      default:
         {
         char szCanRequest [ 7 ] = "";
         Uncan ( dwCommand, szCanRequest, sizeof szCanRequest );
         return _snprintf ( szResponse, cbResponse, "#define CMD_%-6s 0x%8.8X", szCanRequest, dwCommand );
         }

      }  /* End - switch ( dwCommand ) */

   }  /* size_t ProcessCommand ( char * szRequest, char * szResponse, size_t cbResponse ) */

int main ( int argc, char * argv [], char * envp [] )

   {
   WSADATA        stWSAData            = { 0U };                        /* Winsock Library Information                  */

   SOCKET         uUDPSocket           = INVALID_SOCKET;                /* The UDP Socket                               */
   unsigned short usUDPPort            = DEFAULT_PORT;                  /* The Default UDP Port Number                  */

   int            nTimeoutMS           = 100;                           /* The Socket Timeout Value in milliseconds     */

   DWORD          dwSequenceNumber     = 0LU;                           /* The Packet Sequence Number                   */

   SOCKADDR_IN    sinUDPServer         = { AF_INET, 0U, INADDR_ANY };   /* Incoming Socket Address                      */
   SOCKADDR_IN    sinUDPClient         = { 0 };                         /* Outgoing Socket Address                      */

   BOOL           fSyncTime            = FALSE;                         /* Maintain Time Sync with the Client Message?  */

   char           szRequest   [ 128 ]  = { 0 };
   char           szResponse  [ 128 ]  = { 0 };

   size_t         cbRecd               = 0U;
   size_t         cbUsed               = 0U;
   size_t         cbSent               = 0U;

   UNREFERENCED_PARAMETER ( argc );
   UNREFERENCED_PARAMETER ( argv );
   UNREFERENCED_PARAMETER ( envp );

/*
 * Initiate the Windows Sockets Version 2.1
 */
   if ( WSAStartup ( MAKEWORD ( 2, 1 ), &stWSAData ) != 0 )
      {
      int nErrorCode = WSAGetLastError(); /* i.e. WSASYSNOTREADY  */

      fprintf ( stderr, "main():  WSAStartup() returned %d!\n", nErrorCode );
      WSACleanup();

      return 1;
      }

/*
 * Set the Port Number
 */
   sinUDPServer.sin_port = htons ( usUDPPort );

/*
 * Create the Datagram (UDP) Socket
 */
   if ( ( uUDPSocket = socket ( AF_INET, SOCK_DGRAM, 0 ) ) == INVALID_SOCKET )
      {
      int nErrorCode = WSAGetLastError();

      fprintf ( stderr, "main():  socket() returned %d!\n", nErrorCode );
      WSACleanup();

      return 2;
      }

/*
 * Set the Timeout to 100 ms
 */
   setsockopt ( uUDPSocket, SOL_SOCKET, SO_RCVTIMEO, ( char * ) &nTimeoutMS, sizeof ( nTimeoutMS ) );

/*
 * Connect the Socket to Our Address
 */
   if ( bind ( uUDPSocket, ( struct sockaddr * ) &sinUDPServer, sizeof sinUDPServer ) == SOCKET_ERROR)
      {
      int nErrorCode = WSAGetLastError(); // i.e. WSAEADDRINUSE (10048)

      fprintf ( stderr, "main():  bind() returned %d!\n", nErrorCode );
      WSACleanup();

      return 3;
      }

/*
 * Initialize the Cryptography
 */
   InitCrypto();

/*
 * Bump to the Maximum Process and Thread Priority for the Timings Below
 */
   if ( ! SetPriorityClass ( GetCurrentProcess(), REALTIME_PRIORITY_CLASS ) )
      {
      fprintf ( stderr, "SetPriorityClass() returned %d!\n\a", GetLastError() );
      return 4;
      }

   if ( ! SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL ) )
      {
      fprintf ( stderr, "SetThreadPriority() returned %d!\n\a", GetLastError() );
      return 5;
      }

/*
 * Main Processing Loop
 */
   fprintf ( stdout, "AES Encrypted UDP Port %u Online!\n", DEFAULT_PORT );

   SetConsoleCtrlHandler ( ControlHandler, TRUE );

   while ( ! g_fShutDownRequested )
      {
      int cbSinUDPClient = sizeof sinUDPClient;

   /*
    * Receive the Request
    */
      memset ( szRequest,  0, sizeof szRequest  );
      memset ( szResponse, 0, sizeof szResponse );

      if ( ( cbRecd = SvrGetAESEncryptedUDPPacket ( uUDPSocket, &dwSequenceNumber, ( struct sockaddr * ) &sinUDPClient, &cbSinUDPClient, szRequest, sizeof szRequest, fSyncTime ) ) == 0U )
         continue;

   /*
    * Process the Request
    */
      cbUsed = ProcessCommands ( szRequest, szResponse, sizeof szResponse );

   /*
    * Return the Response
    */
      cbSent = SvrPutAESEncryptedUDPPacket ( uUDPSocket, dwSequenceNumber, &sinUDPClient, cbSinUDPClient, szResponse, cbUsed );

   /*
    * Display the Audit Trail
    */
      #ifdef VERBOSE
      fprintf ( stdout, "\r==>  %s\t\t\n%s\n", szRequest, szResponse );
      #endif   // VERBOSE

      }  /* End - while ( ! fShutDownRequested ) */

/*
 * Close the UDP Socket
 */
   closesocket ( uUDPSocket );

   uUDPSocket = INVALID_SOCKET;

/*
 * Cleanup and Terminate Windows Sockets Version 2.1
 */
   WSACleanup();

/*
 * Return Success!
 */
   fprintf ( stdout, "\nBye!\n" );

   return 0;

   }  /* int main ( int argc, char * argv [], char * envp [] ) */

Client.c

/***************************************************************************************
*                                                                                      *
* Copyright (c) 2009 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342  *
*                                                                                      *
*  This code implements the UDP Socket Client application,                             *
*                                                                                      *
*     "http://gladman.plushost.co.uk/oldsite/AES/aes-src-16-04-07.zip"                 *
*     (see:  "http://gladman.plushost.co.uk/oldsite/AES/index.php " for more info)     *
*                                                                                      *
*  You will need to extract aescrypt.c, aeskey.c, aestab.c, aes.h, aesopt.h, aestab.h, *
*  brg_endian.h and brg_types.h from aes-src-16-04-07.zip and put them in the same     *
*  directory as the rest of the source files.                                          *
*                                                                                      *
*  To compile the application from the command line:                                   *
*                                                                                      *
*     "CL Client.c aescrypt.c aeskey.c aestab.c CRC.c Crypto.c DateTime.c WriteCon.c"  *
*                                                                                      *
***************************************************************************************/

#pragma warning ( disable : 4514 )     /* unreferenced inline function has been removed         */

#pragma warning ( push, 3 )            /* Suppress Warnings from WINDOWS.H and WINSOCK2.H       */
#include <WINSOCK2.H>                  /* Windows Sockets Version 2.0                           */
#pragma warning ( pop )                /* Return to Normal Processing                           */

#include <IO.H>                        /* _isatty ( _fileno ( stdin ) ) );                      */
#include <STDIO.H>                     /* Definitions/Declarations for Standard I/O Routines    */

#include "Crypto.h"                    /* The Cryptography Code                                 */

#pragma comment ( lib, "ws2_32.lib" )  /* Functions Defined in WINSOCK2.H                       */

#ifndef QWORD_DEFINED
typedef unsigned __int64 QWORD;
#define QWORD_DEFINED
#endif   /* QWORD_DEFINED */

/**************************************************************************************
* Detect and Honor all of the Normal Shutdown Events, Including Ctrl+C and Ctrl+Break *
**************************************************************************************/

BOOL g_fShutDownRequested = FALSE;

static BOOL WINAPI ControlHandler ( DWORD dwCtrlType )

   {

   switch ( dwCtrlType )
      {
      case CTRL_CLOSE_EVENT:           /* Close from System Menu or Button                      */

      /* ungetc ( '\x03', stdin ); */  /* Nope, This Didn't Work!                               */

      case CTRL_C_EVENT:               /* Ctrl+C from Keyboard                                  */
      case CTRL_BREAK_EVENT:           /* Ctrl+Break from Keyboard                              */
      case CTRL_SHUTDOWN_EVENT:        /* System Shutdown Event                                 */
      case CTRL_LOGOFF_EVENT:          /* User Logoff Event                                     */

         g_fShutDownRequested = TRUE;  /* Set Shutdown Requested                                */
         return TRUE;

      default:
         fprintf ( stdout, "ControlHandler() Received %lu\n\a", dwCtrlType );
         return FALSE;
      }

   }  /* static BOOL WINAPI ControlHandler ( DWORD dwCtrlType ) */

BOOL GetUDPAddress ( LPCSTR strComputerNameOrAddress, char * szAddress, size_t cbAddress )

   {
   struct hostent       * lpHostEntry  = gethostbyname ( strComputerNameOrAddress );
   struct sockaddr_in   stDestAddr     = { 0 };
   char                 * pszHostName  = NULL;

   if ( lpHostEntry )
      {
      memcpy ( &stDestAddr.sin_addr, lpHostEntry->h_addr_list [ 0 ], min ( sizeof stDestAddr.sin_addr, lpHostEntry->h_length ) );
      stDestAddr.sin_family = lpHostEntry->h_addrtype;
      }
   else
      {
      unsigned long lnAddr = 0LU;

      if ( ( lnAddr = inet_addr ( strComputerNameOrAddress ) ) == INADDR_NONE )
         {
         strncpy ( szAddress, "???.???.???.???", cbAddress );
         return FALSE;
         }
      }

/*
 * Convert the Destination Address Into a Printable String
 */
   pszHostName = inet_ntoa ( stDestAddr.sin_addr );

   strncpy ( szAddress, pszHostName, cbAddress );

   return TRUE;

   }  /* BOOL GetUDPAddress ( LPCSTR strComputerNameOrAddress, char * szAddress, size_t cbAddress ) */

int main ( int argc, char * argv[], char * envp [] )

   {
   SOCKET         uUDPSocket           = INVALID_SOCKET;                   /* The UDP Communications Socket             */

   SOCKADDR_IN    sinUDP               = { AF_INET, 0U };                  /* The Socket Intput Address                 */

   DWORD          dwSndSequenceNumber  = 0LU;                              /* The Sent Packet Sequence Number           */
   DWORD          dwRcvSequenceNumber  = 0LU;                              /* The Received Packet Sequence Number       */

   int            nTimeout             = 500;                              /* Desired Timeout Value in Milliseconds     */
   int            nResult              = 0;                                /* Error Return                              */

   WSADATA        stWSAData            = { 0U };                           /* The Windows Sockets Implementation Data   */

   char           * szDefaultHost      = "localhost";                      /* The UDP Server's Default UDP Address      */
   char           * szHost             = NULL;                             /* The Host Name Parameter                   */

   char           szUDPAddress [ 16 ]  = "";                               /* The UDP Address of the Specified Host     */
   unsigned short usPortNumber         = 50001U;                           /* The UDP Socket Port Number                */

   BOOL           fRedirected          = ! _isatty ( _fileno ( stdin ) );  /* Are Commands Comming from a Piped File?   */

/*
 * Account for Unreferenced Parameters
 */
   UNREFERENCED_PARAMETER ( envp );

/*
 * Start Up a Windows Socket Application
 */
   if ( WSAStartup ( MAKEWORD ( 2, 1 ), &stWSAData ) != 0 )
      {
      int nErrorCode = WSAGetLastError();
      fprintf ( stderr, "main():  WSAStartup() returned %d!\n", nErrorCode );
      return 1;
      }

/*
 * Determine the UDP Address and Socket Number to Use
 */
   szHost = argc > 1 ? argv [ 1 ] : szDefaultHost;

   if ( ! GetUDPAddress ( szHost, szUDPAddress, sizeof szUDPAddress ) )
      {
      fprintf ( stderr, "Host %s not found!\n\a", szHost );
      WSACleanup();
      return 2;
      }

   if ( argc > 2 )
      usPortNumber = ( unsigned short ) atoi ( argv [ 2 ] );

   sinUDP.sin_port = htons ( usPortNumber );

/*
 * Open the UDP Socket
 */
   if ( ( uUDPSocket = socket ( AF_INET, SOCK_DGRAM, 0 ) ) == INVALID_SOCKET )
      {
      int nErrorCode = WSAGetLastError();
      fprintf ( stderr, "main():  socket() returned %d!\n", nErrorCode );
      WSACleanup();
      return 3;
      }

/*
 * Set the Send and Receive Timeouts
 */
   nResult = setsockopt ( uUDPSocket, SOL_SOCKET, SO_SNDTIMEO, ( char * ) &nTimeout, sizeof ( nTimeout ) );
   nResult = setsockopt ( uUDPSocket, SOL_SOCKET, SO_RCVTIMEO, ( char * ) &nTimeout, sizeof ( nTimeout ) );

/*
 * Get the Socket Address
 */
   sinUDP.sin_addr.S_un.S_addr = inet_addr ( szUDPAddress );

/*
 * Connect it to the Remote Socket
 */
   if ( connect ( uUDPSocket, ( PSOCKADDR ) &sinUDP, sizeof ( sinUDP ) ) == SOCKET_ERROR )
      {
      int nErrorCode = WSAGetLastError(); /* i.e. WSAECONNREFUSED or WSAEADDRNOTAVAIL */
      closesocket ( uUDPSocket );
      uUDPSocket = INVALID_SOCKET;
      WSACleanup();
      fprintf ( stderr, "main():  connect() returned %d <%s>!\n", nErrorCode, nErrorCode == WSAECONNREFUSED ? "Connection Refused" : "<unknown>" );
      return 4;
      }

/*
 * Initialize the AES Encryption and Decryption Contexts
 */
   InitCrypto();

/*
 * Do Normal Processing Here
 */
   SetConsoleCtrlHandler ( ControlHandler, TRUE );

/*************************************
* Process the Request/Response Pairs *
*************************************/

   while ( ! g_fShutDownRequested )
      {
      char  szRequest   [ 1024 ] = { '\0' };
      char  szResponse  [ 1024 ] = { '\0' };

      int   i                    = 0;

   /*
    * Get and Trim the Command String
    */
      fprintf ( stdout, "==>  " );

      if ( ! fgets ( szRequest, sizeof szRequest, stdin ) )
         {
         if ( ferror ( stdin ) )
            {
            perror ( strerror ( errno ) );
            clearerr ( stdin );
            }

         break;
         }

   /*
    * Find the Terminating '\0'
    */
      for ( i = 0; szRequest [ i ]; i++ );

   /*
    * Delete Trailing Newlines and Carriage Returns
    */
      while ( i && ( szRequest [ i - 1 ] == '\r' || szRequest [ i - 1 ] == '\n' ) )
         szRequest [ --i ] = '\0';

      if ( fRedirected )
         fprintf ( stdout, "%s\n", szRequest );

   /*
    * Send the Request
    */
      if ( ! CntPutAESEncryptedUDPPacket ( uUDPSocket, ++dwSndSequenceNumber, szRequest, strlen ( szRequest ) ) )
         continue;

   /*
    * Get the Response
    */
      for ( i = 0; i < 5; i++ )
         {
         if ( ! CntGetAESEncryptedUDPPacket ( uUDPSocket, &dwRcvSequenceNumber, &szResponse, sizeof szResponse ) )
            continue;
      // else           // !!! Fix !!!
      //    break;      // !!! Fix !!!

      /*
       * Check for Packets Out of Sequence
       */
         if ( dwRcvSequenceNumber == dwSndSequenceNumber ) break;

         fprintf ( stdout, "Sequence Number Error!  Sent %lu but got %lu\n", dwSndSequenceNumber, dwRcvSequenceNumber );

         }  /* End - for ( i = 0; i < 5; i++ ) */

   /*
    * Print the Results
    */
      if ( i < 5 )
         fprintf ( stdout, "%s\n", szResponse );

      }  /* End - while ( ! g_fShutDownRequested ) */

/*
 * Close the Socket
 */
   closesocket ( uUDPSocket );
   uUDPSocket = INVALID_SOCKET;

/*
 * Cleanup and Terminate Windows Sockets
 */
   WSACleanup();

/*
 * Return Success!
 */
   fprintf ( stdout, "\n\nBye!\n" );

   return 0;

   }  /* int main ( int argc, char * argv [], char * envp [] ) */

Try.cpp

/************************************************************************************************************
*                                                                                                           *
*  Copyright (c) 2009 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342                      *
*                                                                                                           *
*  This application allows us to gather timing information about this AES Encrypted UDP protocol.           *
*  Running Server and Try on the same computer, I have seen up to 14,000 request/response pairs per         *
*  second.  Obviously, this depends on both the hardware that we are using and the software that is         *
*  running at the same time.  I have also seen in excess of 3,000 request/response pairs between PCs on     *
*  a T10/T100 Ethernet through a switch.                                                                    *
*                                                                                                           *
*  To compile the application from the command line:                                                        *
*                                                                                                           *
*     "CL Try.cpp aescrypt.c aeskey.c aestab.c CRC.c Crypto.c DateTime.c ErrorTxt.c HiRes.cpp WriteCon.c"   *
*                                                                                                           *
************************************************************************************************************/

#pragma warning ( disable : 4514 )     // unreferenced inline function has been removed

#pragma warning ( push, 3 )            // Suppress Warnings from WINDOWS.H and WINSOCK2.H
#include <WINSOCK2.H>                  // Windows Sockets Version 2.0
#pragma warning ( pop )                // Return to Normal Processing

#include <STDIO.H>                     // Standard I/O Function Prototypes and Defines

#include "HiRes.h"                     // The High Resolution Timer Prototypes and Defines
#include "Crypto.h"                    // The AES Encryption Wrapper

#pragma comment ( lib, "ws2_32.lib" )  // Functions Defined in WINSOCK2.H

// Detect and Honor all of the Normal Shutdown Events, Including Ctrl+C and Ctrl+Break

extern "C" BOOL g_fShutDownRequested = FALSE;

static BOOL WINAPI ControlHandler ( DWORD dwCtrlType )

   {

   switch ( dwCtrlType )
      {
      case CTRL_C_EVENT:               // Ctrl+C from Keyboard
      case CTRL_BREAK_EVENT:           // Ctrl+Break from Keyboard
      case CTRL_CLOSE_EVENT:           // Close from System Menu or Button
      case CTRL_SHUTDOWN_EVENT:        // System Shutdown Event
      case CTRL_LOGOFF_EVENT:          // User Logoff Event

         g_fShutDownRequested = TRUE;  // Set Shutdown Requested

         return TRUE;

      default:
         fprintf ( stdout, "\rControlHandler() Received %lu\n", dwCtrlType );
         return FALSE;
      }

   }  // static BOOL WINAPI ControlHandler ( DWORD dwCtrlType )

BOOL GetUDPAddress ( LPCSTR strComputerNameOrAddress, char * szAddress, size_t cbAddress )

   {
   struct hostent       * lpHostEntry  = gethostbyname ( strComputerNameOrAddress );
   struct sockaddr_in   stDestAddr     = { 0 };
   char                 * pszHostName  = NULL;

   if ( lpHostEntry )
      {
      memcpy ( &stDestAddr.sin_addr, lpHostEntry->h_addr_list [ 0 ], min ( sizeof stDestAddr.sin_addr, lpHostEntry->h_length ) );
      stDestAddr.sin_family = lpHostEntry->h_addrtype;
      }
   else
      {
      unsigned long lnAddr = 0LU;

      if ( ( lnAddr = inet_addr ( strComputerNameOrAddress ) ) == INADDR_NONE )
         {
         strncpy ( szAddress, "???.???.???.???", cbAddress );
         return FALSE;
         }
      }

   // Convert the Destination Address Into a Printable String

   pszHostName = inet_ntoa ( stDestAddr.sin_addr );

   strncpy ( szAddress, pszHostName, cbAddress );

   return TRUE;

   }  // BOOL GetUDPAddress ( LPCSTR strComputerNameOrAddress, char * szAddress, size_t cbAddress )

int main ( int argc, char * argv[], char * envp [] )

   {
   SOCKET         uUDPSocket           = INVALID_SOCKET;    // The UDP Communications Socket

   SOCKADDR_IN    sinUDP               = { AF_INET, 0U };   // The Socket Intput Address

   DWORD          dwSndSequenceNumber  = 0LU;               // The Sent Packet Sequence Number
   DWORD          dwRcvSequenceNumber  = 0LU;               // The Received Packet Sequence Number

   int            nTimeout             = 100;               // Desired Timeout Value in Milliseconds
   int            nResult              = 0;                 // Error Return

   WSADATA        stWSAData            = { 0U };            // The Windows Sockets Implementation Data

   char           * szDefaultHost      = "localhost";       // The UDP Server's Default UDP Address
   char           * szHost             = NULL;              // The Host Name Parameter

   char           szUDPAddress [ 16 ]  = "";                // The UDP Address of the Specified Host
   unsigned short usPortNumber         = 50001U;            // The UDP Socket Port Number

   unsigned long  ulPass               = 0LU;               // The Current Pass Number

   CHiResTimer    HiRes;                                    // The High Resolution Timer

   // Account for Unreferenced Parameters

   UNREFERENCED_PARAMETER ( envp );

   // Start Up a Windows Socket Application

   if ( WSAStartup ( MAKEWORD ( 2, 1 ), &stWSAData ) != 0 )
      {
      int nErrorCode = WSAGetLastError();
      fprintf ( stderr, "main():  WSAStartup() returned %d!\n", nErrorCode );
      return 1;
      }

   // Determine the UDP Address and Socket Number to Use

   szHost = argc > 1 ? argv [ 1 ] : szDefaultHost;

   if ( ! GetUDPAddress ( szHost, szUDPAddress, sizeof szUDPAddress ) )
      {
      fprintf ( stderr, "Host %s not found!\n\a", szHost );
      WSACleanup();
      return 2;
      }

   if ( argc > 2 )
      usPortNumber = ( unsigned short ) atoi ( argv [ 2 ] );

   sinUDP.sin_port = htons ( usPortNumber );

   // Open the UDP Socket

   if ( ( uUDPSocket = socket ( AF_INET, SOCK_DGRAM, 0 ) ) == INVALID_SOCKET )
      {
      int nErrorCode = WSAGetLastError();
      fprintf ( stderr, "main():  socket() returned %d!\n", nErrorCode );
      WSACleanup();
      return 3;
      }

   // Set the Send and Receive Timeouts

   nResult = setsockopt ( uUDPSocket, SOL_SOCKET, SO_SNDTIMEO, ( char * ) &nTimeout, sizeof ( nTimeout ) );
   nResult = setsockopt ( uUDPSocket, SOL_SOCKET, SO_RCVTIMEO, ( char * ) &nTimeout, sizeof ( nTimeout ) );

   // Get the Socket Address

   sinUDP.sin_addr.S_un.S_addr = inet_addr ( szUDPAddress );

   // Connect it to the Remote Socket

   if ( connect ( uUDPSocket, ( PSOCKADDR ) &sinUDP, sizeof ( sinUDP ) ) == SOCKET_ERROR )
      {
      int nErrorCode = WSAGetLastError(); // i.e. WSAECONNREFUSED or WSAEADDRNOTAVAIL
      closesocket ( uUDPSocket );
      uUDPSocket = INVALID_SOCKET;
      WSACleanup();
      fprintf ( stderr, "main():  connect() returned %d <%s>!\n", nErrorCode, nErrorCode == WSAECONNREFUSED ? "Connection Refused" : "<unknown>" );
      return 4;
      }

   // Initialize the AES Encryption and Decryption Contexts

   InitCrypto();

   // Bump to the Maximum Process and Thread Priority for the Timings Below

   if ( ! SetPriorityClass ( GetCurrentProcess(), REALTIME_PRIORITY_CLASS ) )
      {
      fprintf ( stderr, "main():  SetPriorityClass() returned %d!\n", GetLastError() );
      return 5;
      }

   if ( ! SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL ) )
      {
      fprintf ( stderr, "main():  SetThreadPriority() returned %d!\n", GetLastError() );
      return 6;
      }

   // Do Normal Processing Here

   SetConsoleCtrlHandler ( ControlHandler, TRUE );

   // Process the Request/Response Pairs

   HiRes.Start();

   for ( ulPass = 0; ! g_fShutDownRequested; ulPass++ )
      {
      char szResponse [ 128 ] = { 0 };

      // Print the Current Error Statistics

      if ( ulPass && ulPass % 10LU == 0 )
         {
         HiRes.Stop();
         Sleep ( 10LU );
         fprintf ( stdout, "\r%lu %4.1f - %lu\t\t\r\n", ulPass, 10.0f / HiRes.ElapsedTimeInSeconds(), g_ulErrors );
         HiRes.Start();
         }

      // Send the Request

      if ( ! CntPutAESEncryptedUDPPacket ( uUDPSocket, ++dwSndSequenceNumber, "REV", 3 ) )
         continue;

      // Get the Response

      int i = 0;

      for ( i = 0; i < 5; i++ )
         {
         if ( ! CntGetAESEncryptedUDPPacket ( uUDPSocket, &dwRcvSequenceNumber, &szResponse, sizeof szResponse ) )   // GetLastError() - 10060 == WSAETIMEDOUT, 10054 == WSAECONNRESET
            continue;

         // Check for Packets Out of Sequence

         if ( dwRcvSequenceNumber == dwSndSequenceNumber ) break;

         fprintf ( stdout, "Sequence Number Error!  Sent %lu but got %lu\n", dwSndSequenceNumber, dwRcvSequenceNumber );

         }  // End - for ( i = 0; i < 5; i++ )

      }  // End - while ( ! g_fShutDownRequested )

   // Close the Socket

   closesocket ( uUDPSocket );
   uUDPSocket = INVALID_SOCKET;

   // Cleanup and Terminate Windows Sockets

   WSACleanup();

   // Return Success!

   fprintf ( stdout, "\n\nBye!\n" );

   return 0;

   }  // int main ( int argc, char * argv [], char * envp [] )