You are on page 1of 11

/******************************************************************************\

* simplec.c - Simple TCP/UDP client using Winsock 1.1


*
* This is a part of the Microsoft Source Code Samples.
* Copyright 1996 - 2000 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/
#ifdef _IA64_
#pragma warning(disable:4127)
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/////////////////////
#include <windows.h>
#include <wincrypt.h>
/////////////////////
#define DEFAULT_PORT "5001" // Default server port
#define DEFAULT_PROTO SOCK_STREAM // Default protocol (TCP)
#define DEFAULT_BUFFER_LEN 8 // Default send/recv buffer length
#define DEFAULT_BUFFER_LEN_C 9
#define SIZE 16

////////////////////////////////////////////////////////////////////////////////
/////////////////////
// Function prototype
//DWORD WINAPI ServerThread(LPVOID lpParam);
//////////////////////////////////////////////////////////////////////////////
#define HASH_CREATE_ALGORITHM CALG_MD2 // MD2
// #define HASH_CREATE_ALGORITHM CALG_SHA // SHA
// #define HASH_CREATE_ALGORITHM CALG_MD5 // MD5
#define HASH_DERIVE_ALGORITHM CALG_RC2 //RC2
//#define HASH_DERIVE_ALGORITHM CALG_DES //DES
// Defined in lots of samples but rarely used
//#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define HASH_DERIVE_KEY_LENGHT 0x00280000 // 40 bits for RC_2
//#define HASH_DERIVE_KEY_LENGHT 0x00380000 // 56 bits for DES
/* Comment out next line if you want to use stream cipher */
#define USE_BLOCK_CIPHER
#ifdef USE_BLOCK_CIPHER
// defines for RC2 block cipher
#define ENCRYPT_ALGORITHM CALG_RC2
//#define DECRYPT_ALGORITHM CALG_DES
//#define ENCRYPT_ALGORITHM CALG_DES
//#define ENCRYPT_ALGORITHM CALG_RC4
//#define ENCRYPT_BLOCK_SIZE 8
#define ENCRYPT_BLOCK_SIZE 3
#else
// defines for RC4 stream cipher
#define DECRYPT_ALGORITHM CALG_RC4
#define DECRYPT_BLOCK_SIZE 1
#endif

static BOOL CAPIEncryptFile(PCHAR szSource, PCHAR szDestination, PCHAR szPasswor


d);

/****************************************************************************/
LPSTR glueEncr(LPSTR key, LPSTR PlainText, LPSTR buffer, DWORD & dataLen, DWORD
buffLen);
LPSTR glueDecr(LPSTR key, LPSTR CipherText, LPSTR buffer, DWORD& dataLen);
int initCrypt(HCRYPTPROV &hCryptProv, HCRYPTHASH &hHash,
HCRYPTKEY &hKey, LPSTR key);
void cleanUp(HCRYPTPROV &hCryptProv, HCRYPTHASH &hHash, HCRYPTKEY &hKey);
void checkErr();
// build up crypto objects
// on error cleanup and return negative
// 1 if ok
int initCrypt(HCRYPTPROV &hCryptProv, HCRYPTHASH &hHash,
HCRYPTKEY &hKey, LPSTR key)
{
hCryptProv = 0;
hHash = 0;
hKey = 0;
// Get handle to the default provider.
// try MS_DEF_PROV, MS_STRONG_PROV, MS_ENHANCED_PROV
// try NULL instead of "altoth" (my username)
// try CRYPT_NEWKEYSET instead of 0
if (!CryptAcquireContext(&hCryptProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
CRYPT_NEWKEYSET))
{
if (!CryptAcquireContext(&hCryptProv, NULL, MS_DEF_PROV, PROV_RS
A_FULL, 0))
{
checkErr();
cleanUp(hCryptProv, hHash, hKey);
return -1;
}
}
checkErr();
// Create a hash object, hHash
if (!CryptCreateHash(hCryptProv, HASH_CREATE_ALGORITHM, 0, 0, &hHash))
{
checkErr();
cleanUp(hCryptProv, hHash, hKey);
return -2;
}
checkErr();
// Use the hash object, hHash, to hash the password.
if (!CryptHashData(hHash, (PBYTE)key, strlen(key)+1, 0))
{
checkErr();
cleanUp(hCryptProv, hHash, hKey);
return -3;
}
checkErr();
// Derive a session key, hKey, from the hash object, hHash.
// try CRYPT_NO_SALT and explicit HASH_DERIVE_KEY_LENGHT
if (!CryptDeriveKey(hCryptProv, HASH_DERIVE_ALGORITHM, hHash,
HASH_DERIVE_KEY_LENGHT | CRYPT_EXPORTABLE | CRYPT_NO_SALT, &hKey
))
{
checkErr();
cleanUp(hCryptProv, hHash, hKey);
return -4;
}
checkErr();
return 1;
}

// clean up crypto objects


void cleanUp(HCRYPTPROV &hCryptProv, HCRYPTHASH &hHash, HCRYPTKEY &hKey)
{
if (hKey) {
CryptDestroyKey(hKey);
hKey = 0;
}
if (hHash) {
CryptDestroyHash(hHash);
hHash = 0;
}
if (hCryptProv) {
CryptReleaseContext(hCryptProv, 0);
hCryptProv = 0;
}
//checkErr();
}
void checkErr()
{
DWORD err;
switch ((err = GetLastError()))
{
case 0:
break;
case NTE_BAD_KEY_STATE:
// cout << "NTE_BAD_KEY_STATE" << endl;
printf("NTE_BAD_KEY_STATE\n");
break;
case NTE_BAD_PUBLIC_KEY:
// cout << "NTE_BAD_PUBLIC_KEY" << endl;
printf("NTE_BAD_PUBLIC_KEY\n");
break;
case NTE_BAD_KEY:
// cout << "NTE_BAD_KEY" << endl;
printf("NTE_BAD_KEY\n");
break;
case NTE_NO_KEY:
// cout << "NTE_NO_KEY" << endl;
printf("NTE_NO_KEY\n");
break;
case NTE_BAD_TYPE:
// cout << "NTE_BAD_TYPE" << endl;
printf("NTE_BAD_TYPE\n");
break;
case NTE_PROV_TYPE_NO_MATCH:
// cout << "NTE_PROV_TYPE_NO_MATCH" << endl;
printf("NTE_PROV_TYPE_NO_MATCH\n");
break;
case NTE_BAD_KEYSET:
// cout << "NTE_BAD_KEYSET" << endl;
printf("NTE_BAD_KEYSET\n");
break;
default:
// cout << "Other:" << err << endl;
printf("Other: %s\n", err);
}
}
// Decryption
// if error return " " or errcode if available
// [in/out] datalen : len of input data, len of result data
LPSTR glueDecr(LPSTR key, LPSTR CipherText, LPSTR buffer, DWORD&dataLen)
{
HCRYPTPROV hCryptProv = 0;
HCRYPTHASH hHash = 0;
HCRYPTKEY hKey = 0;
int result;
if ((result = initCrypt(hCryptProv, hHash, hKey, key)) <= 0) {
checkErr();
_ltoa(result, buffer, 10);
return buffer;
}
checkErr();
memcpy((char*)buffer, CipherText, dataLen);
//printf("hCryptProv is %s\n", hCryptProv);
//printf("hHash is %s\n", hHash);
//printf("hKey is %s\n", hKey);
//printf("dataLen is %d\n", dataLen);
//printf("DECRYPT IS %s\n", CryptDecrypt(hKey, NULL, 1, 0, (BYTE*)buffer
, &dataLen));
// Decrypt
if (CryptDecrypt(hKey, NULL, 1, 0, (BYTE*)buffer, &dataLen))
{
// make it string !
buffer[dataLen] = 0;
}
else {
//checkErr();
_ltoa(GetLastError(), buffer, 10);
strcat(buffer, " calling CryptDecrypt");
dataLen = 0;
//printf("\n CryptDecrypt failed, Error=0x%.8x\n", __FUNCTION__
, GetLastError());
}
//checkErr();
cleanUp(hCryptProv, hHash, hKey);
return buffer;
}
////////////////////////////////////////////////////////////////////////////////
/////////////////////
//
// Function: Usage
//
// Description:
// Print the parameters and exit.
//
void Usage(char *progname)
{
fprintf(stderr, "Usage\n%s -p [protocol] -n [server] -e [endpoint] -l [itera
tions] [-4] [-6]\n"
"Where:\n"
"\t-p protocol - is one of TCP or UDP\n"
"\t-n server - is the string address or name of server\n"
"\t-e endpoint - is the port to listen on\n"
"\t-l iterations - is the number of loops to execute\n"
"\t -l by itself makes client run in an infinite loop,"
"\t Hit Ctrl-C to terminate it)\n"
"\t-4 - force IPv4\n"
"\t-6 - force IPv6\n"
"\n"
"Defaults are TCP, localhost and 5001\n",
progname
);
WSACleanup();
exit(1);
}
/////////////////////Random number generation def/////////////////////
static HCRYPTPROV hProvider;
void spc_rand_init(void) {
if (!CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
ExitProcess((UINT)-1); /* Feel free to properly signal
* an error instead. *
/
}
unsigned char *spc_rand(unsigned char *pbBuffer, size_t cbBuffer) {
if (!hProvider) spc_rand_init();
if (!CryptGenRandom(hProvider, cbBuffer, pbBuffer))
ExitProcess((UINT)-1); /* Feel free to properly signal an
* error instead. */
return pbBuffer;
}
////////////////////////////////////////////////////////////////////////

//
// Function: main
//
// Description:
// Parse the command line and attempt to connect to the given server.
// The client will attempt to connect to each address returned by the
// getaddrinfo call until one succeeds afterwhich it will initiate
// echoing the data. Once the requested number of sends are issued,
// the connection is closed. For UDP, this is simply connecting the
// UDP socket to and endpoint and issuing the requested number of
// datagram sends and receives.
//
int __cdecl main(int argc, char *argv[])
{
WSADATA wsaData;
SOCKET conn_socket = INVALID_SOCKET;
struct addrinfo *results = NULL,
*addrptr = NULL,
hints;
char *server_name = "localhost",
*port = DEFAULT_PORT,
Buffer[DEFAULT_BUFFER_LEN],
cipher_text[DEFAULT_BUFFER_LEN],
hoststr[NI_MAXHOST],
servstr[NI_MAXSERV];
int address_family = AF_UNSPEC,
socket_type = DEFAULT_PROTO;
int retval,
loopflag = 0,
loopcount,
maxloop = -1,
i;
///////////////////////////////////////////////////////
SetLastError(0);
char *passwd = "1"; // Password is used as a key
//char plain_text[SIZE];
//char cipher_text[SIZE];
char new_plain_text[SIZE];
char new_plain_text1[SIZE];
char Buffer_P[DEFAULT_BUFFER_LEN];
char Buffer_C[SIZE];
char Buffer_T[10]="123";
//memset(plain_text, 0, SIZE);
memset(new_plain_text, 0, DEFAULT_BUFFER_LEN);
memset(Buffer_C, 0, DEFAULT_BUFFER_LEN);
//memset(Buffer_T, 0, DEFAULT_BUFFER_LEN);
///////////////////////////////////////////////////////
// Parse the command line
if (argc >1)
{
for (i=1; i < argc; i++)
{
if ( (strlen(argv[i]) == 2) && ((argv[i][0] == '-') || (argv[i][0] =
= '/') ) )
{
switch (tolower(argv[i][1]))
{
case '4': // Force IPv4
address_family = AF_INET;
break;
case '6': // Force IPv6
address_family = AF_INET6;
break;
case 'p': // Protocol (UDP or TCP)
if (!_strnicmp(argv[i+1], "TCP", 3) )
socket_type = SOCK_STREAM;
else if (!_strnicmp(argv[i+1], "UDP", 3) )
socket_type = SOCK_DGRAM;
else
Usage(argv[0]);
i++;
break;
case 'n': // Server name to connect to
server_name = argv[++i];
break;
case 'e': // Port number to connect to
port = argv[++i];
break;
case 'l': // Number of iterations
loopflag = 1;
if (i+1 >= argc)
Usage(argv[0]);
if (argv[i+1][0] != '-')
maxloop = atoi(argv[i+1]);
else
maxloop = -1;
i++;
break;
default:
Usage(argv[0]);
break;
}
}
else
Usage(argv[0]);
}
}
// Load Winsock
if ((retval = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
{
fprintf(stderr,"WSAStartup failed with error %d\n",retval);
WSACleanup();
return -1;
}
// Make sure the wildcard port wasn't specified
if (_strnicmp(port, "0", 1) == 0)
Usage(argv[0]);
//
// Resolve the server name
//
memset(&hints, 0, sizeof(hints));
hints.ai_family = address_family;
hints.ai_socktype = socket_type;
hints.ai_protocol = ((socket_type == SOCK_STREAM) ? IPPROTO_TCP : IPPROTO_UD
P);
retval = getaddrinfo(
server_name,
port,
&hints,
&results
);
if (retval != 0)
{
fprintf(stderr, "getaddrinfo failed: %d\n", retval);
goto cleanup;
}
// Make sure we got at least one address
if (results == NULL)
{
fprintf(stderr, "Server (%s) name could not be resolved!\n", server_name
);
goto cleanup;
}
//
// Walk through the list of addresses returned and connect to each one.
// Take the first successful connection.
//
addrptr = results;
while (addrptr)
{
conn_socket = socket(addrptr->ai_family, addrptr->ai_socktype, addrptr->
ai_protocol);
if (conn_socket == INVALID_SOCKET)
{
fprintf(stderr, "socket failed: %d\n", WSAGetLastError());
goto cleanup;
}
//
// Notice that nothing in this code is specific to whether we
// are using UDP or TCP.
// We achieve this by using a simple trick.
// When connect() is called on a datagram socket, it does not
// actually establish the connection as a stream (TCP) socket
// would. Instead, TCP/IP establishes the remote half of the
// ( LocalIPAddress, LocalPort, RemoteIP, RemotePort) mapping.
// This enables us to use send() and recv() on datagram sockets,
// instead of recvfrom() and sendto()
retval = getnameinfo(
addrptr->ai_addr,
(socklen_t)addrptr->ai_addrlen,
hoststr,
NI_MAXHOST,
servstr,
NI_MAXSERV,
NI_NUMERICHOST | NI_NUMERICSERV
);
if (retval != 0)
{
fprintf(stderr, "getnameinfo failed: %d\n", retval);
goto cleanup;
}
printf("Client attempting connection to: %s port: %s\n", hoststr, servst
r);
retval = connect(conn_socket, addrptr->ai_addr, (int)addrptr->ai_addrlen
);
if (retval == SOCKET_ERROR)
{
closesocket(conn_socket);
conn_socket = INVALID_SOCKET;
addrptr = addrptr->ai_next;
}
else
{
break;
}
}
freeaddrinfo(results);
results = NULL;
// Make sure we got a connection established
if (conn_socket == INVALID_SOCKET)
{
printf("Unable to establish connection...\n");
goto cleanup;
}
else
{
printf("Connection established...\n");
}
////////////EXTRE IMPORTANT//////////////////////////////////
memset(Buffer, 0, DEFAULT_BUFFER_LEN);
////Clear Buffer before using, otherwise, null will occur////
spc_rand((unsigned char *)Buffer, 7);
//printf("Buffer is %s\n", Buffer);

loopcount = 0;
for(;;)
{
//printf("Plaintext is %s\n", Buffer);
//_snprintf(Buffer, SIZE-1,
// "This is a small test message [number %d]",
//loopcount++
//);
// Send the data
retval = send(conn_socket, Buffer, DEFAULT_BUFFER_LEN, 0);
if (retval == SOCKET_ERROR)
{
fprintf(stderr,"send failed: error %d\n", WSAGetLastError());
goto cleanup;
}
printf("wrote %d bytes, Plaintext = [%s]\n",retval,Buffer);
strcpy(Buffer_P, Buffer);

// Receive the data back


retval = recv(conn_socket,Buffer_C, SIZE, 0);
printf("read %d bytes, Ciphertext = [%s]\n",retval,Buffer_C);
//strcpy(Buffer_E,Buffer_C);
if (retval == SOCKET_ERROR)
{
fprintf(stderr, "recv failed: error %d\n", WSAGetLastError());
goto cleanup;
}
//
// We are not likely to see this with UDP, since there is no
// 'connection' established.
//
else if (retval == 0)
{
printf("Server closed connection\n");
break;
}
else
{
/////////////////////////////////////////////////////////////
//////////
DWORD len2 = strlen(Buffer_C)+1;
//printf("Decrypted \"%s\" ==> \"%s\"\n", Buffer_C
//, glueDecr(passwd, Buffer_C, new_plain_text, l
en2));
printf("Decrypted [%s] ==> [%s]\n", Buffer_C
, glueDecr(passwd, Buffer_C, new_plain_text, len
2));
//printf("Client: Plaintext is [%s]\n", Buffer_P);
//if (strcmp(Buffer_P, new_plain_text) == 0)
if (strcmp(Buffer_P, new_plain_text) == 0)
printf("The test is successful !!\n");
else
printf("The test is failed !!\n");
break;
/////////////////////////////////////////////////////////////
/////////
//printf("read %d bytes, data [%s] from server\n", retval, ci
pher_text);
}

// See if we need to break out of the loop


if (loopflag)
{
if ( (loopcount >= maxloop) && (maxloop > 0) )
break;
}
else
{
break;
}
}
cleanup:
//
// clean up the client connection
//
if (conn_socket != INVALID_SOCKET)
{
// Indicate no more data to send
retval = shutdown(conn_socket, SD_SEND);
if (retval == SOCKET_ERROR)
{
fprintf(stderr, "shutdown failed: %d\n", WSAGetLastError());
}
// Close the socket
retval = closesocket(conn_socket);
if (retval == SOCKET_ERROR)
{
fprintf(stderr, "closesocket failed: %d\n", WSAGetLastError());
}
conn_socket = INVALID_SOCKET;
}
if (results != NULL)
{
freeaddrinfo(results);
results = NULL;
}
WSACleanup();
getchar();
return 0;
}

You might also like