-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathClient.java
More file actions
370 lines (302 loc) · 8.24 KB
/
Client.java
File metadata and controls
370 lines (302 loc) · 8.24 KB
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
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
import java.io.*;
import java.net.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.math.*;
import java.util.*;
/**
* This class is a secure file transfer client. Connects to the server and sends a
* file across.
*
* @author Mike Jacobson
* @version 1.0, October 23, 2013
*/
public class Client
{
private boolean debug;
private Socket sock; //Socket to communicate with
private BufferedReader stdIn; // for user input
private DataOutputStream out;
private DataInputStream in;
private SecretKeySpec key; // AES encryption key
/**
* Utility for printing protocol messages
* @param s protocol message to be printed
*/
private void debug(String s) {
if(debug)
System.out.println("Debug Client: " + s);
}
/**
* Constructor, in this case does everything.
* @param ipaddress The hostname to connect to.
* @param port The port to connect to.
*/
public Client (String ipaddress, int port, boolean setDebug)
{
// set the debug flag
debug = setDebug;
// open reader for usesr input
stdIn = new BufferedReader(new InputStreamReader(System.in));
// Try to connect to the specified host on the specified port.
try {
sock = new Socket (InetAddress.getByName(ipaddress), port);
}
catch (UnknownHostException e) {
System.out.println ("Usage: java Client hostname port#");
System.out.println ("First argument is not a valid hostname");
return;
}
catch (IOException e) {
System.out.println ("Could not connect to " + ipaddress + ".");
return;
}
// Status info
System.out.println ("Connected to " + sock.getInetAddress().getHostAddress() + " on port " + port);
// open input and output streams for file transfer
in = null;
out = null;
try {
in = new DataInputStream(sock.getInputStream());
out = new DataOutputStream(sock.getOutputStream());
}
catch (UnknownHostException e) {
System.out.println ("Unknown host error.");
close();
}
catch (IOException e) {
System.out.println ("Could not create output stream.");
close();
}
}
/**
* Generates a random AES-128 key and sends to the server using the server's public
* RSA key.
*/
public void getKey() {
debug("Starting getKey");
//key setup - generate random 128 bit AES key
debug("Generating random AES-128 key");
SecretKey sec_key = null;
try {
KeyGenerator key_gen = KeyGenerator.getInstance("AES");
key_gen.init(128);
sec_key = key_gen.generateKey();
}
catch (NoSuchAlgorithmException ex) {
System.out.println("Problem initializing AES key generator.");
close();
}
//get key material in raw form
byte[] raw = sec_key.getEncoded();
key = new SecretKeySpec(raw, "AES");
debug("AES key = " + CryptoUtilities.toHexString(raw));
// get n from the server
debug("Receiving RSA modulus n from the server.");
byte[] encodedn;
try {
encodedn = CryptoUtilities.receive(in);
}
catch (IOException ex) {
System.out.println("Error receiving n from server.");
close();
return;
}
BigInteger n = new BigInteger(encodedn);
debug("Received n = " + n);
// get e from the server
debug("Receiving RSA exponent e from the server.");
byte[] encodede;
try {
encodede = CryptoUtilities.receive(in);
}
catch (IOException ex) {
System.out.println("Error receiving e from server.");
close();
return;
}
BigInteger e = new BigInteger(encodede);
debug("Received e = " + e);
// encrypt the key and send to the server
debug("Encrypting the AES key with the server's RSA public key");
RSATool RSA = new RSATool(n,e,debug);
byte[] encryptedKey = null;
try {
encryptedKey = RSA.encrypt(raw);
}
catch (IllegalArgumentException ex) {
System.out.println(ex);
}
debug("Sending encrypted key to server");
try {
CryptoUtilities.send(encryptedKey,out);
}
catch (IOException ex) {
System.out.println("Error sending key to server.");
close();
return;
}
debug("Sent C = " + CryptoUtilities.toHexString(encryptedKey));
}
/**
* Encrypted file transfer
* @return true if file transfer was successful
*/
public boolean sendFile() {
debug("Starting File Transfer");
// get input file name
String infilename;
FileInputStream infile;
try {
System.out.print("Please enter the source filename: ");
infilename = stdIn.readLine();
infile = new FileInputStream(infilename);
}
catch (IOException e) {
System.out.println ("Could not open source file");
close();
return false;
}
// get output file name
String outfilename;
try {
System.out.print("Please enter the destination filename: ");
outfilename = stdIn.readLine();
}
catch (IOException e) {
System.out.println("Error getting destination filename.");
close();
return false;
}
// send the output file name
try {
debug("Sending output file name = " + outfilename);
CryptoUtilities.encryptAndSend(outfilename.getBytes(),key,out);
}
catch (IOException e) {
System.out.println("Error sending the output file name");
close();
return false;
}
// send the file size
try {
debug("Sending file size = " + infile.available());
CryptoUtilities.encryptAndSend(String.valueOf(infile.available()).getBytes(), key,out);
}
catch (IOException e) {
System.out.println("Error sending the file length");
close();
return false;
}
// append message digest, encrypt, send file
try {
debug("Encrypting and sending file with MAC appended");
// read input file into a byte array
byte[] msg = new byte[infile.available()];
int read_bytes = infile.read(msg);
// append HMAC-SHA-1 message digest
byte[] hashed_msg = CryptoUtilities.append_hash(msg,key);
// encrypt anad send
CryptoUtilities.encryptAndSend(hashed_msg,key,out);
}
catch (IOException e) {
System.out.println("Error sending encrypted file");
close();
return false;
}
// get acknowledgement from server
boolean transferOK = false;
try {
debug("Waiting for server acknowledgement");
String ack = new String(CryptoUtilities.receiveAndDecrypt(key,in));
debug("Got acknowledgement = " + ack);
if (ack.compareTo("Passed") == 0) {
System.out.println("File received and verified");
transferOK = true;
}
else {
System.out.println("Error verifying file");
}
}
catch (IOException e) {
System.out.println("Error getting server acknowledgement");
close();
return transferOK;
}
return transferOK;
}
/**
* Shuts down the socket connection
*/
public void close() {
// shutdown socket and input reader
System.out.println("Shutting down client.");
try {
stdIn.close();
sock.close();
if (in != null)
in.close();
if (out != null)
out.close();
}
catch (IOException e) {
return;
}
}
/**
* Outputs usage instructions
*/
public static void printUsage() {
System.out.println ("Usage: java Client hostname port#");
System.out.println(" or java Client debug hostname port#");
System.out.println (" - hostname is a string identifying your server");
System.out.println (" - port is a positive integer identifying the port to connect to the server");
}
/**
* Main method, starts the client.
* @param args args[0] needs to be a hostname, args[1] a port number.
*/
public static void main (String [] args)
{
boolean setDebug = false;
if (args.length < 2 || args.length > 3) {
printUsage();
return;
}
// check if debug flag is being set
String ipaddress;
int port;
if (args.length == 3) {
if (args[2].compareTo("debug") == 0) {
setDebug = true;
ipaddress = args[0];
port = Integer.parseInt(args[1]);
}
else {
printUsage();
return;
}
}
else {
ipaddress = args[0];
port = Integer.parseInt(args[1]);
}
// initialize client and socket connections
Client c;
try {
c = new Client (ipaddress, port, setDebug);
}
catch (NumberFormatException e) {
printUsage();
System.out.println ("ERROR: second argument was not a port number");
return;
}
// get the encryption key
c.getKey();
// do file transfer
c.sendFile();
// shut down the client
c.close();
}
}