-
Notifications
You must be signed in to change notification settings - Fork 0
/
enc_client.c
341 lines (285 loc) · 9.46 KB
/
enc_client.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
// include all the header files for commands used
#define _GNU_SOURCE
#include <dirent.h>
// header file for input/output system calls
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
// header file for file/directory statistics
#include <sys/stat.h>
// header file for wait system calls for clearing child processes
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
// header file for signal-related system calls & modifcations
#include <signal.h>
#include <fcntl.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
// gethostbyname()
#include <netdb.h>
// Set up the address struct used to store the server's address where the client will connect to
void setupAddressStruct(struct sockaddr_in* address,
int portNumber,
char* hostname){
// Clear out the address struct
memset((char*) address, '\0', sizeof(*address));
// The address should be network capable
address->sin_family = AF_INET;
// Store the port number
address->sin_port = htons(portNumber);
// Get the DNS entry for this host name
struct hostent* hostInfo = gethostbyname(hostname);
if (hostInfo == NULL) {
fprintf(stderr, "CLIENT: ERROR, no such host\n");
exit(0);
}
// Copy the first IP address from the DNS entry to sin_addr.s_addr
memcpy((char*) &address->sin_addr.s_addr,
hostInfo->h_addr_list[0],
hostInfo->h_length);
}
/*
- validate that there are no bad characters in a file
*/
int validateFile(char *file) {
char character;
FILE* file_pointer = fopen(file, "r");
// iterate through every character in the file
for (character = fgetc(file_pointer); character != 10; character = fgetc(file_pointer)) {
if (!((character > 64 && character < 91) || character == 32)) {
// return 0 if a bad character is detected
return 0;
}
}
// Close the file
fclose(file_pointer);
// return 1 if the file doesn't contain bad characters
return 1;
}
/*
- return the word count of a file
*/
int charCount(char *file) {
FILE* file_pointer;
int count = 0;
char character;
// Open the file
file_pointer = fopen(file, "r");
// iterate through each character of the file
for (character = fgetc(file_pointer); character != 10; character = fgetc(file_pointer)) {
// Increment count for this character
count = count + 1;
}
// Close the file
fclose(file_pointer);
// return the word count
return count;
}
/*
- checks to see a file is in the current directory
*/
int fileExists(char *file) {
FILE* file_pointer;
// attempt to open the file
file_pointer = fopen(file, "r");
if (file_pointer == NULL) {
// file doesn't exist
return 0;
}
// file exists
return 1;
}
/*
- validate that:
- both files exist
- neither file contains bad characrters
- key is at least as long as the plaintext
*/
int validate(char *plaintext, char *key) {
// check to see if both files exist
if (fileExists(plaintext) != 1 || fileExists(key) != 1) {
fprintf(stderr, "enc_client error: cannot open input file(s)\n");
// return 0 if not
return 0;
}
// check to see if both files are free of bad chars
int p_validated = validateFile(plaintext);
int k_validated = validateFile(key);
if (p_validated != 1 || k_validated != 1) {
fprintf(stderr, "enc_client error: input contains bad characters\n");
// return 0 if not
return 0;
}
// check if key is at least as long as plaintext
if (charCount(key) < charCount(plaintext)) {
fprintf(stderr, "Error: key \'%s\' is too short\n", key);
// return 0 if not
return 0;
}
// return 1 if all criterias are satisfied
return 1;
}
/*
- put the contents of a "\n" trailed file into a buffer
*/
void putBuffer(char *buffer, char *file) {
FILE* file_pointer;
size_t buffer_size = charCount(file) + 2;
// open file
file_pointer = fopen(file, "r");
// get the one line consisting of the entire content of the file & store it in buffer
getline(&buffer, &buffer_size, file_pointer);
buffer[charCount(file)] = '\0';
}
/*
- send a message from a buffer to a socket
*/
void sendMessage(int socket, char *message) {
// number of chars sent
int sent = 0;
// total of chars in the buffer to be sent
int total = strlen(message);
// number of chars sent by current message packet
int charsWritten;
while(1) {
// if remaining characters < 200
if ((total - sent) < 200) {
// send all of them & terminate the function
charsWritten = send(socket, message + sent, total - sent, 0);
break;
}
// if remaining characters > 200
else {
// send the next 200 characters in the buffer
charsWritten = send(socket, message + sent, 200, 0);
sent = sent + 200;
}
// if there's a problem with the send request
if (charsWritten < 0){
// print error to stderr & exit with value 1
fprintf(stderr,"ENC_CLIENT: ERROR writing to socket\n");
close(socket);
exit(1);
}
// if number of chars sent is less than specified, display warning message
if (charsWritten < 1){
printf("ENC_CLIENT: WARNING: Not all data written to socket!\n");
}
}
}
/*
- receive characters from a socket & store it into a buffer
*/
int receiveMessage(int socket, char *buffer) {
// number of characters read by current receive request
int charsRead;
// indicator for whether client has connected to the wrong server
int wrong_server = 0;
// buffer to store the characters received by the current receive request
char tempBuffer[201];
// continue creating receive requests until then termination character "@" is detected in the buffer
while (strstr(tempBuffer, "@") == NULL) {
memset(tempBuffer, '\0', 201);
// receive a maximum number of 200 characters
charsRead = recv(socket, tempBuffer, sizeof(tempBuffer) - 1, 0);
if (charsRead < 0){
// if there is an error, report to stderr & exit with value 1
perror("ENC_CLIENT");
close(socket);
exit(1);
}
// if "d" is detected in current message received, set wrong server indicator
if (strstr(tempBuffer, "d") != NULL) {
wrong_server = 1;
}
// concactenate current message to the target buffer
strcat(buffer, tempBuffer);
}
// slice off the termination character "@"
char *terminal_char = strstr(buffer, "@");
memset(terminal_char, '\0', 1);
if (wrong_server == 1) {
// return 0 if client connected to the wrong server
return 0;
}
else {
// return 1 if client connected to the correct server
return 1;
}
}
/*
- verify that input files are valid, exit program otherwise
- establishes a connection socket with enc_server
- sends plaintext & key to enc_server
- receives ciphertext from enc_server
- prints ciphertext to stdout
*/
int main(int argc, char *argv[]) {
// initialize variables for the socket file & specified port number
int socketFD, portNumber, charsWritten, charsRead;
struct sockaddr_in serverAddress;
// Check usage & args
if (argc < 4) {
fprintf(stderr,"USAGE: %s plaintext key port\n", argv[0]);
exit(0);
}
// if either of the input files are invalid, prints appropriate error msg to stderr & exit with value 1
if (validate(argv[1], argv[2]) == 0) {
exit(1);
}
// Create a socket
socketFD = socket(AF_INET, SOCK_STREAM, 0);
if (socketFD < 0){
fprintf(stderr,"ENC_CLIENT: ERROR opening socket\n");
}
// Set up the server address struct
setupAddressStruct(&serverAddress, atoi(argv[3]), "localhost");
// Connect to server with address specified with localhost as the target host & input port as the target port
if (connect(socketFD, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) < 0){
fprintf(stderr,"Error: could not contact enc_server on port %s\n", argv[3]);
exit(2);
}
// initialize buffer for the input plaintext
char buffer_plaintext[charCount(argv[1]) + 2];
// initialize buffer for the input key
char buffer_key[charCount(argv[2]) + 2];
memset(buffer_plaintext, '\0', charCount(argv[1]) + 2);
memset(buffer_key, '\0', charCount(argv[2]) + 2);
// put the input plaintext into its initialized buffer
putBuffer(buffer_plaintext, argv[1]);
// put the input key into its initialized buffer
putBuffer(buffer_key, argv[2]);
// send "e" to indicate that this message is sent from the enc_client
sendMessage(socketFD, "e");
// send the plaintext
sendMessage(socketFD, buffer_plaintext);
// send "#" to indicate the end of the plaintext
sendMessage(socketFD, "#");
// send the key
sendMessage(socketFD, buffer_key);
// send "@" to indicate the end of the key and the entire message transaction
sendMessage(socketFD, "@");
// initialize buffer for the ciphertext
char buffer_cypher[charCount(argv[1]) + 2];
memset(buffer_cypher, '\0', charCount(argv[1]) + 2);
// receive message from the server
int wrong_server = receiveMessage(socketFD, buffer_cypher);
// close the connection socket
close(socketFD);
// if message contains wrong server indicator "d", implying that enc_client connected to dec_server
if (wrong_server == 0) {
// print error to stderr & exit with value 2
fprintf(stderr,"Error: enc_client could not contact dec_server on port %s\n", argv[3]);
exit(2);
}
// or else, print ciphertext to stdout
else {
printf("%s\n", buffer_cypher);
// exit program with value 0
return 0;
}
}