-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathClient.java
482 lines (413 loc) · 18 KB
/
Client.java
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
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
import java.net.*;
import java.io.*;
import java.util.*;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.nio.file.*;
/* The Client that can be run both as a console or a GUI */
public class Client {
// for I/O
private ObjectInputStream sInput; // to read from the socket
private ObjectOutputStream sOutput; // to write on the socket
private Socket socket;
private static SecretKey claveAES; //Clave para encriptar los mensajes
//private SecretKey claveAESprueba;
private static PublicKey clavePublica;
private static PrivateKey clavePrivada;
private String claveAESEncriptada;
// if I use a GUI or not
private ClientGUI cg;
// the server, the port and the username
private String server, username;
private int port;
/*
* Constructor called by console mode
* server: the server address
* port: the port number
* username: the username
*/
Client(String server, int port, String username) {
// which calls the common constructor with the GUI set to null
this(server, port, username, null);
}
/*
* Constructor call when used from a GUI
* in console mode the ClienGUI parameter is null
*/
Client(String server, int port, String username, ClientGUI cg) {
this.server = server;
this.port = port;
this.username = username;
// save if we are in GUI mode or not
cg = null;
this.cg = cg;
}
/*
* To start the dialog
*/
public boolean start() {
// try to connect to the server
try {
socket = new Socket(server, port);
}
// if it failed not much I can so
catch (Exception ec) {
display("Error connectiong to server:" + ec);
return false;
}
String msg = "Connection accepted " + socket.getInetAddress() + ":" + socket.getPort();
display(msg);
/* Creating both Data Stream */
try {
sInput = new ObjectInputStream(socket.getInputStream());
sOutput = new ObjectOutputStream(socket.getOutputStream());
} catch (IOException eIO) {
display("Exception creating new Input/output Streams: " + eIO);
return false;
}
// creates the Thread to listen from the server
new ListenFromServer().start();
// Send our username to the server this is the only message that we
// will send as a String. All other messages will be ChatMessage objects
try {
sOutput.writeObject(username);
} catch (IOException eIO) {
display("Exception doing login : " + eIO);
disconnect();
return false;
}
// success we inform the caller that it worked
return true;
}
/*
* To send a message to the console or the GUI
*/
private void display(String msg) {
if (cg == null)
System.out.println(msg); // println in console mode
else
cg.append(msg + "\n"); // append to the ClientGUI JTextArea (or whatever)
}
/*
* To send a message to the server //importante
*/
void sendMessage(ChatMessage msg) {
try {
sOutput.writeObject(msg);
} catch (IOException e) {
display("Exception writing to server: " + e);
}
}
/*
* When something goes wrong
* Close the Input/Output streams and disconnect not much to do in the catch clause
*/
private void disconnect() {
try {
if (sInput != null) sInput.close();
} catch (Exception e) {
} // not much else I can do
try {
if (sOutput != null) sOutput.close();
} catch (Exception e) {
} // not much else I can do
try {
if (socket != null) socket.close();
} catch (Exception e) {
} // not much else I can do
// inform the GUI
if (cg != null)
cg.connectionFailed();
}
/*
* To start the Client in console mode use one of the following command
* > java Client
* > java Client username
* > java Client username portNumber
* > java Client username portNumber serverAddress
* at the console prompt
* If the portNumber is not specified 1500 is used
* If the serverAddress is not specified "localHost" is used
* If the username is not specified "Anonymous" is used
* > java Client
* is equivalent to
* > java Client Anonymous 1500 localhost
* are eqquivalent
*
* In console mode, if an error occurs the program simply stops
* when a GUI id used, the GUI is informed of the disconnection
*/
public static void main(String[] args) {
// default values
int portNumber = 1500;
String serverAddress = "localhost";
String userName = "Anonymous";
// depending of the number of arguments provided we fall through
switch (args.length) {
// > javac Client username portNumber serverAddr
case 3:
serverAddress = args[2];
// > javac Client username portNumber
case 2:
try {
portNumber = Integer.parseInt(args[1]);
} catch (Exception e) {
System.out.println("Invalid port number.");
System.out.println("Usage is: > java Client [username] [portNumber] [serverAddress]");
return;
}
// > javac Client username
case 1:
userName = args[0];
// > java Client
case 0:
break;
// invalid number of arguments
default:
System.out.println("Usage is: > java Client [username] [portNumber] {serverAddress]");
return;
}
// create the Client object
Client client = new Client(serverAddress, portNumber, userName);
// test if we can start the connection to the Server
// if it failed nothing we can do
if (!client.start())
return;
// wait for messages from user
Scanner scan = new Scanner(System.in);
// loop forever for message from the user
while (true) {
System.out.print("> ");
// read message from user
String msg = scan.nextLine();
// logout if message is LOGOUT
if (msg.equalsIgnoreCase("LOGOUT")) {
client.sendMessage(new ChatMessage(ChatMessage.LOGOUT, ""));
// break to do the disconnect
break;
}
// message WhoIsIn
else if (msg.equalsIgnoreCase("WHOISIN")) {
client.sendMessage(new ChatMessage(ChatMessage.WHOISIN, ""));
}
else if (msg.contains("FILE")) {
String msg2=msg.substring(6,msg.length());
msg2=msg2.substring(msg2.lastIndexOf("\\"));
msg2=encriptarMensaje(msg2);
ChatMessage cosa=new ChatMessage(ChatMessage.FILE, msg2);
String archivo=msg.substring(6,msg.length());
File f = new File(archivo);
byte[] content=null;
try{
content = Files.readAllBytes(f.toPath());
}
catch (IOException ex) {
System.out.println("Problema con el archivo");
}
if(claveAES!=null){
content=encriptarMensajeBytes(content);
}
cosa.setContenido(content);
client.sendMessage(cosa);
}
else { // default to ordinary message
if(claveAES!=null){
msg = encriptarMensaje(userName+": "+msg);}
client.sendMessage(new ChatMessage(ChatMessage.CIPHERMESSAGE, msg));
}
}
// done disconnect
client.disconnect();
}
/*
* a class that waits for the message from the server and append them to the JTextArea
* if we have a GUI or simply System.out.println() it in console mode
*/
class ListenFromServer extends Thread {
public void run() {
generarRSA();
System.out.println("Como nuevo usuario he generado mis claves RSA");
while (true) {
try {
ChatMessage aux = (ChatMessage) sInput.readObject();
if(aux.getType()==5){
if(claveAES!=null){
String msg=aux.getMessage();
msg=desencriptarMensaje(msg);
System.out.println(msg);
display(msg);
}
}
if(aux.getType()==1 || aux.getType()==4){
String msg=aux.getMessage();
// if console mode print the message and add back the prompt
if (cg == null) {
if(!msg.contains("~0~") && !msg.contains("~1~")){
System.out.println(msg);
}
if(aux.getType()!=4){
msg = msg.substring(9, msg.length() - 1);
}
if (msg.equalsIgnoreCase("Eres el primero que chupi")) {
System.out.println("Soy el primero viva");
generarAES();
}
if (msg.equalsIgnoreCase("Vas a mandarme tu clave publica")){
sOutput.writeObject(new ChatMessage(ChatMessage.KEY,clavePublica));
}
if (msg.contains("~0~")){
System.out.println("Tengo la clave publica de otro usuario");
System.out.println("Encripto la clave AES con ella y la mando");
//Recibo la clavepublica de B desde el servidor, y con ella encripto mi AES, devolviendo un String
String enviar=encriptarK(aux.getKey());
sOutput.writeObject(new ChatMessage(ChatMessage.MESSAGE, "~1~"+enviar));
}
if (msg.contains("~1~")){
System.out.println("Tengo la clave AES encriptada");
System.out.println("La desencripto con mi clave privada");
String hecho=msg.substring(3);
System.out.println(hecho);
claveAES=desencriptarK(hecho);
System.out.println("Ya tengo la clave AES");
}
if(!msg.equalsIgnoreCase("Eres el primero que chupi")){
System.out.print("> ");
}
} else {
cg.append(msg);
}
}
if(aux.getType()==3){
byte[] otro = aux.getContenido();
otro=desencriptarMensajeBytes(otro);
System.out.println("Tengo el archivo");
String nombre=desencriptarMensaje(aux.getMessage());
File f = new File("C:\\Users\\Irene\\Downloads\\LorikeetFiles"+nombre);
Files.write(f.toPath(), otro);
}
} catch (IOException e) {
display("Server has close the connection: " + e);
if (cg != null)
cg.connectionFailed();
break;
}
// can't happen with a String object but need the catch anyhow
catch (ClassNotFoundException e2) {
}
}
}
}
public static void generarRSA() {
try {
//Establecemos las características de la clave (RSA 2048)
KeyPairGenerator generadorDosClaves = KeyPairGenerator.getInstance("RSA"); //Tipo de algoritmo
generadorDosClaves.initialize(2048); //Tamaño de la clave
KeyPair pareja = generadorDosClaves.generateKeyPair();
clavePrivada = pareja.getPrivate();
clavePublica = pareja.getPublic();
} catch (Exception ex) {
System.out.println(ex);
}
}
public static void generarAES() {
try {
//Establecemos las características de la clave (AES 128)
KeyGenerator generadorClave = KeyGenerator.getInstance("AES"); //Tipo de algoritmo
generadorClave.init(128); //Tamaño de la clave
claveAES = generadorClave.generateKey(); //Genera la clave AES
} catch (Exception ex) {
System.out.println(ex);
}
}
public static String encriptarK(PublicKey clavep) {
String aesCifrado = null;
try {
Cipher cifrado = Cipher.getInstance("RSA");
cifrado.init(Cipher.ENCRYPT_MODE, clavep); //Le decimos explícitamente que queremos encriptar
aesCifrado = Base64.getEncoder().encodeToString(cifrado.doFinal(claveAES.getEncoded()));
//Mostramos por pantalla los resultados
System.out.println("Clave original: " + claveAES);
System.out.println("Clave encriptada: " + aesCifrado);
System.out.println();
} catch (Exception ex) {
System.out.println(ex);
}
return aesCifrado;
}
public SecretKey desencriptarK(String aesCifrado) {
SecretKey claveAESprueba=null;
try {
byte[] aesCifradoBytes = Base64.getDecoder().decode(aesCifrado); //La clave en bytes
Cipher cifrado = Cipher.getInstance("RSA");
cifrado.init(Cipher.DECRYPT_MODE, clavePrivada); //Le decimos explícitamente que queremos encriptar
byte[] descifradaBytes = cifrado.doFinal(aesCifradoBytes);
claveAESprueba = new SecretKeySpec(descifradaBytes, 0, descifradaBytes.length, "AES");
//Mostramos por pantalla los resultados
System.out.println("Clave maestra encriptada: " + aesCifrado);
System.out.println("Clave maestra desencriptada: " + claveAESprueba);
System.out.println();
} catch (Exception ex) {
System.out.println(ex);
}
return claveAESprueba;
}
public static String encriptarMensaje(String textoPlano) {
String textoCifrado = null;
try {
//Ahora que tenemos la clave, pasamos a cifrar el mensaje
Cipher cifrado = Cipher.getInstance("AES");
cifrado.init(Cipher.ENCRYPT_MODE, claveAES); //Le decimos explícitamente que queremos encriptar
textoCifrado = Base64.getEncoder().encodeToString(cifrado.doFinal(textoPlano.getBytes("UTF-8")));
//Mostramos por pantalla los resultados
System.out.println("Mensaje original: " + textoPlano);
System.out.println("Mensaje encriptado: " + textoCifrado);
System.out.println();
} catch (Exception ex) {
System.out.println(ex);
}
return textoCifrado;
}
public static String desencriptarMensaje(String textoCifrado) {
String textoPlano = null;
try {
//Ahora que tenemos la clave, pasamos a descifrar el mensaje
Cipher cifrado = Cipher.getInstance("AES");
cifrado.init(Cipher.DECRYPT_MODE, claveAES); //Le decimos explícitamente que queremos desencriptar
byte[] base64desencriptar = Base64.getDecoder().decode(textoCifrado);
textoPlano = new String(cifrado.doFinal(base64desencriptar));
//Mostramos por pantalla los resultados
System.out.println("Mensaje cifrado: " + textoCifrado);
System.out.println("Mensaje en claro: " + textoPlano);
System.out.println();
} catch (Exception ex) {
System.out.println(ex);
}
return textoPlano;
}
public static byte[] encriptarMensajeBytes(byte[] textoPlano) {
byte[] textoCifrado = null;
try {
//Ahora que tenemos la clave, pasamos a cifrar el mensaje
Cipher cifrado = Cipher.getInstance("AES");
cifrado.init(Cipher.ENCRYPT_MODE, claveAES); //Le decimos explícitamente que queremos encriptar
textoCifrado = Base64.getEncoder().encode(cifrado.doFinal(textoPlano));
} catch (Exception ex) {
System.out.println(ex);
}
return textoCifrado;
}
public static byte[] desencriptarMensajeBytes(byte[] textoCifrado) {
byte[] textoPlano = null;
try {
//Ahora que tenemos la clave, pasamos a descifrar el mensaje
Cipher cifrado = Cipher.getInstance("AES");
cifrado.init(Cipher.DECRYPT_MODE, claveAES); //Le decimos explícitamente que queremos desencriptar
byte[] base64desencriptar = Base64.getDecoder().decode(textoCifrado);
textoPlano = cifrado.doFinal(base64desencriptar);
} catch (Exception ex) {
System.out.println(ex);
}
return textoPlano;
}
}