· 5 years ago · Jan 09, 2020, 04:42 PM
1package dslab.client;
2
3import java.io.*;
4import java.net.Socket;
5import java.net.SocketException;
6import java.net.UnknownHostException;
7import java.security.*;
8import java.util.Arrays;
9import java.util.Base64;
10import at.ac.tuwien.dsg.orvell.Shell;
11import at.ac.tuwien.dsg.orvell.StopShellException;
12import at.ac.tuwien.dsg.orvell.annotation.Command;
13import dslab.ComponentFactory;
14import dslab.util.Communicator;
15import dslab.util.Config;
16import dslab.util.Keys;
17import dslab.util.Message;
18
19
20import javax.crypto.*;
21import javax.crypto.spec.IvParameterSpec;
22
23public class MessageClient implements IMessageClient, Runnable {
24
25 /**
26 * Creates a new client instance.
27 *
28 * @param componentId the id of the component that corresponds to the Config resource
29 * @param config the component config
30 * @param in the input stream to read console input from
31 * @param out the output stream to write console output to
32 */
33
34 private String componentId;
35 private Config config;
36 private InputStream in;
37 private PrintStream out;
38
39 private Socket socket_DMAP;
40 private Socket socket_DMTP;
41
42 private String serverMsg_DMAP;
43
44
45 private final Base64.Encoder encoder;
46 private final Base64.Decoder decoder;
47
48 private Communicator clientCommunicatorDMAP;
49 private Communicator clientCommunicatorDMTP;
50
51 private Key publicKey;
52 private SecretKey secretKey;
53 private SecretKey hmacKey;
54 private IvParameterSpec initialVector;
55 private Cipher rsa;
56
57 private Cipher aesDecryptor;
58 private Cipher aesEncryptor;
59
60 private Mac hMac;
61
62 private Shell shell;
63
64 private BufferedReader transferReader;
65 private PrintWriter transferWriter;
66
67
68
69
70 public MessageClient(String componentId, Config config, InputStream in, PrintStream out) {
71
72 this.config = config;
73 try {
74 this.socket_DMAP = new Socket(config.getString("mailbox.host"), config.getInt("mailbox.port"));
75 this.clientCommunicatorDMAP = new Communicator(socket_DMAP.getInputStream(), socket_DMAP.getOutputStream());
76
77 this.socket_DMTP = new Socket(config.getString("transfer.host"),config.getInt("transfer.port"));
78 this.clientCommunicatorDMTP = new Communicator(socket_DMTP.getInputStream(), socket_DMTP.getOutputStream());
79
80 } catch (IOException e) {
81 e.printStackTrace();
82 }
83
84 KeyGenerator keyGenerator = null;
85 try {
86 keyGenerator = KeyGenerator.getInstance("AES");
87 keyGenerator.init(256);
88 this.secretKey = keyGenerator.generateKey();
89 } catch (NoSuchAlgorithmException e) {
90 e.printStackTrace();
91 }
92
93 try {
94 hmacKey = Keys.readSecretKey(new File("keys/hmac.key"));
95 hMac = Mac.getInstance("HmacSHA256");
96 hMac.init(hmacKey);
97 } catch (IOException | NoSuchAlgorithmException | InvalidKeyException e) {
98 e.printStackTrace();
99 }
100
101 this.encoder = Base64.getEncoder();
102 this.decoder = Base64.getDecoder();
103
104
105 this.componentId = componentId;
106 this.in = in;
107 this.out = out;
108 this.shell = new Shell(in, out);
109 shell.register(this);
110 shell.setPrompt(componentId + "> ");
111
112 }
113
114 @Override
115 public void run() {
116
117 try {
118
119 System.out.println("Setting the secure handshake");
120 serverMsg_DMAP = clientCommunicatorDMAP.read();
121 if (("ok DMAP2.0").equals(serverMsg_DMAP)) {
122 byte[] challenge = new byte[32];
123 byte[] initialVectorBytes = new byte[16];
124
125 clientCommunicatorDMAP.write("startsecure");
126
127 serverMsg_DMAP = clientCommunicatorDMAP.read();
128
129 String[] parts = serverMsg_DMAP.split("\\s");
130
131 String pathToKeys = "keys/client/" + parts[1] + "_pub" + ".der";
132
133 publicKey = Keys.readPublicKey(new File(pathToKeys));
134
135 SecureRandom secureRandom = new SecureRandom();
136
137 secureRandom.nextBytes(challenge);
138
139 challenge = encoder.encode(challenge);
140
141 initialVector = new IvParameterSpec(initialVectorBytes);
142
143 System.out.println("send the challene to server");
144
145 rsa = Cipher.getInstance("RSA/ECB/PKCS1Padding");
146 rsa.init(Cipher.ENCRYPT_MODE, publicKey);
147
148 String prepereResponse = new String(challenge) + " " + new String(encoder.encode(secretKey.getEncoded())) + " " + new String(encoder.encode(initialVectorBytes));
149 String msg = "ok " + prepereResponse;
150
151 String encryptedMsg = new String(encoder.encode(rsa.doFinal(msg.getBytes())));
152
153 clientCommunicatorDMAP.write(encryptedMsg);
154
155 aesDecryptor = Cipher.getInstance("AES/CTR/NoPadding");
156 aesDecryptor.init(Cipher.DECRYPT_MODE, secretKey, initialVector);
157
158 aesEncryptor = Cipher.getInstance("AES/CTR/NoPadding");
159 aesEncryptor.init(Cipher.ENCRYPT_MODE, secretKey, initialVector);
160
161 serverMsg_DMAP = clientCommunicatorDMAP.read();
162 serverMsg_DMAP = aesDecryptor(serverMsg_DMAP);
163
164 String[] checking = serverMsg_DMAP.split("\\s");
165
166 if (checking.length == 2 && ("ok").equals(checking[0])) {
167 System.out.println(checking.length);
168 if (Arrays.equals(checking[1].getBytes(), challenge)) {
169 System.out.println("hier");
170 clientCommunicatorDMAP.write(aesEncryptor("ok"));
171 System.out.println("Secure handshake done.");
172 } else {
173 shutdown();
174 }
175 } else {
176 shutdown();
177 }
178 }
179
180 //LOGIN
181 shell.run();
182
183 } catch (Exception ex) {
184 System.out.println(ex.getMessage());
185 }
186 }
187
188
189 @Command
190 @Override
191 public void inbox() {
192
193 }
194
195 @Command
196 @Override
197 public void delete(String id) {
198
199 clientCommunicatorDMAP.write(aesEncryptor("delete " + id));
200 serverMsg_DMAP = aesDecryptor(clientCommunicatorDMAP.read());
201 out.println(serverMsg_DMAP);
202
203 }
204
205 @Command
206 @Override
207 public void verify(String id) {
208 System.out.println("VERIFY");
209 }
210
211 @Command
212 @Override
213 public void msg(String to, String subject, String data) {
214 String host = this.config.getString("transfer.host");
215 int port = this.config.getInt("transfer.port");
216 String emailAdresse = this.config.getString("transfer.email");
217 Message message = new Message();
218 message.setFrom(emailAdresse);
219 message.setSubject(subject);
220 message.addTo(to);
221 message.setData(data);
222 String hash = null;
223 String response = "";
224
225 Socket socketTransferServer = null;
226 try {
227 socketTransferServer = new Socket(host,port);
228 this.transferReader = new BufferedReader(new InputStreamReader(socketTransferServer.getInputStream()));
229 this.transferWriter = new PrintWriter(socketTransferServer.getOutputStream(), true);
230
231 hash = this.hashValueGenerator(String.join("\n", config.getString("transfer.email"), to, subject, data));
232 message.setHash(hash);
233 if (!"ok DMTP2.0".equals(this.transferReader.readLine())){
234 this.shell.out().println("Connection refused");
235 return;
236 }
237 System.out.println("client connecting");
238
239 this.transferWriter.println("begin");
240 this.transferWriter.flush();
241 response = this.transferReader.readLine();
242 if (!response.equals("ok")){
243 System.out.println("begin failed");
244
245 }
246
247 this.transferWriter.println("from " + message.getFrom());
248 this.transferWriter.flush();
249 response = this.transferReader.readLine();
250 if (!"ok".equals(response)){
251 System.out.println("from failed");
252 return;
253 }
254
255 this.transferWriter.println("to " + to);
256 this.transferWriter.flush();
257 response = this.transferReader.readLine();
258 if (!response.equals("ok " + message.getTo().size())){
259 System.out.println("to failed");
260 return;
261 }
262
263 this.transferWriter.println("subject " + subject);
264 this.transferWriter.flush();
265 response = this.transferReader.readLine();
266 if (!"ok".equals(response)){
267 System.out.println("subject failed");
268 return;
269 }
270
271 this.transferWriter.println("data " + message.getData());
272 this.transferWriter.flush();
273 response = this.transferReader.readLine();
274 if (response.equals("ok")){
275 String getRes = "";
276 this.transferWriter.println("hash " + message.getHash());
277 this.transferWriter.flush();
278 getRes = this.transferReader.readLine();
279 if (!"ok".equals(getRes)){
280 System.out.println("hash failed");
281 return;
282 }
283
284 this.transferWriter.println("send");
285 this.transferWriter.flush();
286 getRes = this.transferReader.readLine();
287 if ("ok".equals(getRes)){
288 System.out.println("Sending completed");
289 return;
290 }
291
292 this.transferWriter.println("quit");
293 this.transferWriter.flush();
294 getRes = this.transferReader.readLine();
295 if (getRes.equals("ok bye")){
296 System.out.println("bye");
297 return;
298 }
299
300 System.out.println("quit failed");
301 return;
302 }
303 System.out.println("Data failed");
304
305 } catch (UnknownHostException var43) {
306 System.out.println("host nicht erkannt");
307 } catch (SocketException var44) {
308 System.out.println("Verbindung zum Transfer Server abgerißen!");
309 return;
310 } catch (IOException var45) {
311 System.out.println("Verbindung zum Ein- oder Ausgabegerät abreißt");
312 return;
313 } catch (NoSuchAlgorithmException var46) {
314
315 System.out.println("cryptographic algorithm is requested but is not available in the environment!");
316 return;
317 } catch (InvalidKeyException var47) {
318 var47.printStackTrace();
319 System.out.println("Key ist Invalide!");
320 return;
321 } finally {
322 if (socketTransferServer != null || !socketTransferServer.isClosed()) {
323 try {
324 socketTransferServer.close();
325 } catch (IOException var42) {
326 }
327 }
328
329 }
330
331 }
332
333
334
335 @Command
336 @Override
337 public void shutdown() {
338
339 System.out.println("shutdown");
340
341 if (socket_DMAP != null && !socket_DMAP.isClosed()) {
342 try {
343 socket_DMAP.close();
344 } catch (IOException e) {
345 e.printStackTrace();
346 }
347 }
348
349 if (socket_DMTP != null && !socket_DMTP.isClosed()) {
350 try {
351 socket_DMTP.close();
352 } catch (IOException e) {
353 e.printStackTrace();
354 }
355 }
356
357 throw new StopShellException();
358 }
359
360 //Verschlüsselt einen String mit dem geshareten Secret Key.
361 //Diese Methode nimmt an, dass das Handshake schon erfolgt hat und das Cipher aesEncryptor (Klassenvariable) schon gesetzt ist.
362 public String aesEncryptor(String res) {
363 try {
364 return new String(encoder.encode(aesEncryptor.doFinal(res.getBytes())));
365 } catch (IllegalBlockSizeException e) {
366 e.printStackTrace();
367 } catch (BadPaddingException e) {
368 e.printStackTrace();
369 }
370 return null;
371 }
372
373 //Entschlüsselt eine Server-Antwort mit dem geshareten Secret Key.
374 //Diese Methode nimmt an, dass das Handshake schon erfolgt hat und das Cipher aesDecryptor (Klassenvariable) schon gesetzt ist.
375 public String aesDecryptor(String res) {
376 try {
377 return new String(aesDecryptor.doFinal(decoder.decode(res)));
378 } catch (IllegalBlockSizeException e) {
379 e.printStackTrace();
380 } catch (BadPaddingException e) {
381 e.printStackTrace();
382 }
383 return null;
384 }
385
386 public String hashValueGenerator(String hashing) throws NoSuchAlgorithmException,InvalidKeyException,IOException{
387
388 hMac.update(hashing.getBytes());
389 byte[] hash = hMac.doFinal();
390 return new String(encoder.encode(hash));
391 }
392 //
393
394
395 public static void main(String[] args) throws Exception {
396 IMessageClient client = ComponentFactory.createMessageClient(args[0], System.in, System.out);
397 client.run();
398 }
399}