· 8 years ago · Jan 11, 2018, 01:54 PM
1package dslab.client;
2
3import java.io.*;
4import java.net.Socket;
5import java.security.*;
6import java.util.ArrayList;
7
8
9import org.bouncycastle.util.encoders.Base64;
10import java.util.Scanner;
11import java.util.regex.Matcher;
12import java.util.regex.Pattern;
13
14import dslab.ComponentFactory;
15import dslab.mailbox.Message;
16import dslab.util.Config;
17import dslab.util.Keys;
18
19import javax.crypto.*;
20
21public class MessageClient implements IMessageClient, Runnable {
22
23 private String componentId;
24 private Config config;
25 private InputStream in;
26
27 private PrintStream output;
28 private BufferedReader input;
29
30 private PrintStream out;
31
32 private Socket socket;
33 private SecretKey sharedSecretKey;
34
35 /**
36 * Creates a new client instance.
37 *
38 * @param componentId the id of the component that corresponds to the Config resource
39 * @param config the component config
40 * @param in the input stream to read console input from
41 * @param out the output stream to write console output to
42 */
43 public MessageClient(String componentId, Config config, InputStream in, PrintStream out) {
44 this.componentId = componentId;
45 this.config = config;
46 this.in = in;
47 this.out = out;
48
49 try {
50 this.sharedSecretKey = Keys.readSecretKey(new File("keys/hmac.key"));
51 } catch (IOException e) {
52 e.printStackTrace();
53 }
54 }
55
56 @Override
57 public void run() {
58 Scanner sc = new Scanner(in);
59
60 /*
61 The connection to the DMAP server should be established as soon as the client starts,
62 using the server and login details stored in the client’s properties file
63 */
64
65 try {
66
67 socket = new Socket(config.getString("mailbox.host"), config.getInt("mailbox.port"));
68
69 output = new PrintStream(socket.getOutputStream());
70 input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
71
72 /* Check if connection is acquired and server is ready */
73 if(!input.readLine().equals("ok DMAP2.0")) {
74 System.out.println("Error");
75 }
76
77 /* Start secure connection */
78 output.println("startsecure");
79 String response = input.readLine();
80 out.println(response);
81 String componentId = response.split(" ")[1];
82 PublicKey publicKey = Keys.readPublicKey(new File("keys/client/" + componentId + ".pub"));
83
84 byte[] challenge = new SecureRandom().generateSeed(32);
85 byte[] iv = new SecureRandom().generateSeed(16);
86
87 try {
88
89 Cipher rsa = Cipher.getInstance("RSA/NONE/OAEPWithSHA256AndMGF1Padding");
90 rsa.init(Cipher.ENCRYPT_MODE, publicKey);
91 KeyGenerator keyGen = KeyGenerator.getInstance("AES");
92 keyGen.init(256);
93 String msg = "ok " + Base64.encode(challenge) + " " + keyGen.generateKey().getEncoded() + " " + Base64.encode(iv);
94 byte[] encodedMsg = rsa.doFinal(msg.getBytes("UTF-8"));
95 output.println(Base64.encode(encodedMsg));
96
97 System.out.println(Base64.encode(encodedMsg));
98
99
100 } catch (NoSuchAlgorithmException e) {
101 e.printStackTrace();
102 } catch (NoSuchPaddingException e) {
103 e.printStackTrace();
104 } catch (BadPaddingException e) {
105 e.printStackTrace();
106 } catch (IllegalBlockSizeException e) {
107 e.printStackTrace();
108 } catch (InvalidKeyException e) {
109 e.printStackTrace();
110 }
111
112
113
114
115
116
117 /* Log in into mailbox server */
118 output.println("login " + config.getString("mailbox.user") + " " + config.getString("mailbox.password"));
119 if(!input.readLine().equals("ok")) {
120 System.out.println("Not logged in.");
121 }else System.out.println("Logged in.");
122
123 while(!socket.isClosed()) {
124
125 String cmd = sc.nextLine();
126 String[] splitted = cmd.split(" ");
127 //TODO Validierung
128 switch(splitted[0]) {
129 case "inbox" :
130 inbox();
131 break;
132 case "delete" :
133 delete(splitted[1]);
134 break;
135 case "verify" :
136 verify(splitted[1]);
137 break;
138 case "msg" :
139 /* establish DMEP connection */
140 Pattern p = Pattern.compile("\"([^\"]*)\"");
141 Matcher m = p.matcher(cmd);
142
143 m.find();
144 String subject = m.group(1);
145 m.find();
146 String data = m.group(1);
147 msg(splitted[1], subject, data);
148 break;
149 case "shutdown" :
150 shutdown();
151 break;
152 default:
153 shutdown();
154 break;
155 }
156 }
157 } catch (IOException e) {
158 e.printStackTrace();
159 }
160 sc.close();
161 shutdown();
162 }
163
164 @Override
165 public void inbox() {
166 try {
167 output.println("list");
168 ArrayList<Integer> messageIds = new ArrayList<>();
169 for (String line = input.readLine(); line != null; line = input.readLine()) {
170 if(line.equals("ok")) break;
171 messageIds.add(Integer.parseInt(line.split(" ")[0]));
172 }
173
174 for(Integer messageId : messageIds) {
175 System.out.println("msg id : " + messageId);
176 output.println("show " + messageId);
177 String line;
178 int i;
179 for (i = 0, line = input.readLine(); line != null ; line = input.readLine(), i++) {
180 if(!line.split(" ")[0].equals("hash") && !line.equals("ok")){
181 out.println(line);
182 }
183 if (line.equals("ok")){
184 break;
185 }
186 }
187 }
188 } catch (IOException e) {
189 e.printStackTrace();
190 }
191 }
192
193 @Override
194 public void delete(String id) {
195 output.println("delete " + id);
196 try {
197 if(input.readLine().equals("ok")) System.out.println("ok");
198 else System.out.println("error");
199 } catch (IOException e) {
200 e.printStackTrace();
201 }
202 }
203
204 @Override
205 public void verify(String id) {
206
207 int messageId = Integer.parseInt(id);
208 Message message = loadMessage(messageId);
209 String hash = signMessage(message);
210
211 if(hash.equals(message.getHash()))
212 System.out.println("ok");
213 else
214 System.out.println("error");
215 }
216
217 private String signMessage(Message message) {
218 byte[] hash = new byte[0];
219 try {
220 Mac macInstance = Mac.getInstance("HmacSHA256");
221 macInstance.init(sharedSecretKey);
222
223 String msg = String.join("\n", message.getFrom(), message.getToClients(), message.getSubject(), message.getData());
224 hash = macInstance.doFinal(msg.getBytes());
225 } catch (NoSuchAlgorithmException e) {
226 //TODO macInstace Algo not found
227 } catch (InvalidKeyException e) {
228 e.printStackTrace();
229 }
230 return Base64.encode(hash).toString();
231 }
232
233 @Override
234 public void msg(String to, String subject, String data) {
235 /*
236 The connection to the DMEP server should be established every time the msg command is invoked.
237 */
238
239 Message mess = new Message(config.getString("transfer.email"), to, subject, data, null);
240 mess.setHash(signMessage(mess));
241
242 try {
243 Socket transferSocket = new Socket(config.getString("transfer.host"), config.getInt("transfer.port"));
244 PrintStream out = new PrintStream(transferSocket.getOutputStream());
245 BufferedReader in = new BufferedReader(new InputStreamReader(transferSocket.getInputStream()));
246
247 if(!in.readLine().equals("ok DMEP2.0")){
248 System.out.println("error 0");
249 }
250 out.println("begin");
251
252 if (!in.readLine().equals("ok")) {
253 System.out.println("error 1");
254 return;
255 }
256 out.println("to " + to);
257 if (!in.readLine().startsWith("ok")){
258 System.out.println("error 2");
259 return;
260 }
261 out.println("subject " + subject);
262 if (!in.readLine().equals("ok")){
263 System.out.println("error 3");
264 return;
265 }
266 out.println("data " + data);
267 if (!in.readLine().equals("ok")){
268 System.out.println("error 4");
269 return;
270 }
271 out.println("from " + config.getString("transfer.email"));
272 if (!in.readLine().equals("ok")) {
273 System.out.println("error 5");
274 return;
275 }
276 out.println("hash " + mess.getHash());
277 if (!in.readLine().equals("ok")) {
278 System.out.println("error 6");
279 return;
280 }
281 out.println("send");
282 if (!in.readLine().equals("ok")){
283 System.out.println("error 7");
284 return;
285 }
286 out.println("quit");
287 if (!in.readLine().startsWith("ok")){
288 System.out.println("error 8");
289 return;
290 }
291 System.out.println("ok");
292 out.close();
293 in.close();
294 transferSocket.close();
295 } catch (IOException e) {
296 e.printStackTrace();
297 }
298
299 }
300
301 private Message loadMessage(int messageId){
302 Message m = new Message(null, null, null, null, null);
303
304 try {
305
306 output.println("show " + messageId);
307
308 String line = input.readLine();
309 m.setFrom(line.split(" ")[1]);
310 line = input.readLine();
311 m.setTo(line.split(" ")[1]);
312
313 String[] newLine = input.readLine().split(" ");
314 String tmp = "";
315 for(int x = 1; x < newLine.length; x++) {
316 tmp += newLine[x] + " ";
317 }
318 tmp = tmp.substring(0, tmp.length() - 1);
319 m.setSubject(tmp);
320
321 newLine = input.readLine().split(" ");
322 tmp = "";
323 for(int x = 1; x < newLine.length; x++) {
324 tmp += newLine[x] + " ";
325 }
326 tmp = tmp.substring(0, tmp.length() - 1);
327 m.setData(tmp);
328
329 line = input.readLine();
330 if (line.contains(" ")) m.setHash(input.readLine().split(" ")[1]);
331 else m.setHash("");
332
333 if(input.readLine().equals("ok")) {
334 System.out.println("Sve je okej");
335 return m;
336 }
337
338 } catch (IOException e) {
339 e.printStackTrace();
340 }
341 return null;
342 }
343
344 @Override
345 public void shutdown() {
346 System.out.println("U shutdown sam.");
347 output.close();
348 out.close();
349 try {
350 socket.close();
351 } catch (IOException e) {
352 e.printStackTrace();
353 }
354 try {
355 input.close();
356 } catch (IOException e) {
357 e.printStackTrace();
358 }
359 }
360
361 public static void main(String[] args) throws Exception {
362 IMessageClient client = ComponentFactory.createMessageClient(args[0], System.in, System.out);
363 client.run();
364 }
365}