source: trunk/src/org/expeditee/auth/Mail.java@ 1283

Last change on this file since 1283 was 1283, checked in by bln4, 5 years ago

When loading in messages from the mail databases now uses the timestamp last-accessed companion file to only load in new ones.

File size: 9.1 KB
Line 
1package org.expeditee.auth;
2
3import java.io.File;
4import java.io.FileNotFoundException;
5import java.io.IOException;
6import java.nio.file.Path;
7import java.nio.file.Paths;
8import java.security.InvalidKeyException;
9import java.security.KeyStoreException;
10import java.security.NoSuchAlgorithmException;
11import java.security.PrivateKey;
12import java.security.PublicKey;
13import java.security.cert.CertificateException;
14import java.security.spec.InvalidKeySpecException;
15import java.sql.Connection;
16import java.sql.DriverManager;
17import java.sql.PreparedStatement;
18import java.sql.SQLException;
19import java.sql.Statement;
20import java.text.ParseException;
21import java.text.SimpleDateFormat;
22import java.util.ArrayList;
23import java.util.Arrays;
24import java.util.Base64;
25import java.util.Date;
26import java.util.HashMap;
27import java.util.List;
28import java.util.Map;
29import java.util.Scanner;
30
31import javax.crypto.BadPaddingException;
32import javax.crypto.Cipher;
33import javax.crypto.IllegalBlockSizeException;
34import javax.crypto.NoSuchPaddingException;
35
36import org.expeditee.gui.FrameIO;
37import org.ngikm.cryptography.CryptographyConstants;
38
39public class Mail implements CryptographyConstants {
40
41 private static List<MailEntry> messages = new ArrayList<MailEntry>();
42
43 /**
44 * Add a piece of mail, used during initialisation.
45 */
46 public static void addEntry(MailEntry mail) {
47 messages.add(mail);
48 }
49
50 public static void clear() {
51 messages.clear();
52 }
53
54 public static void sendMail(MailEntry mail, String colleagueName) {
55 // Ensure dead drop area is set up.
56 Path databaseFileDirPath = Paths.get(FrameIO.DEAD_DROPS_PATH).resolve(colleagueName);
57 Path databaseFilePath = databaseFileDirPath.resolve(colleagueName + ".db");
58 File databaseFile = databaseFilePath.toFile();
59 if (!databaseFile.exists()) {
60 databaseFileDirPath.toFile().mkdirs();
61 String sql =
62 "CREATE TABLE EXPMAIL (" +
63 "TIME TEXT NOT NULL, " +
64 "SND TEXT NOT NULL, " +
65 "REC TEXT NOT NULL, " +
66 "MSG TEXT NOT NULL, " +
67 "MSG2 TEXT NOT NULL, " +
68 "OPTS ARRAY NOT NULL, " +
69 "OPTSVAL ARRAY NOT NULL)";
70 try {
71 Connection c = DriverManager.getConnection("jdbc:sqlite:" + databaseFile.getAbsolutePath());
72 Statement createTable = c.createStatement();
73 createTable.executeUpdate(sql);
74 createTable.close();
75 c.close();
76 } catch (SQLException e) {
77 System.err.println("Error while creating database file.");
78 e.printStackTrace();
79 }
80 }
81
82 // Obtain public key
83 PublicKey publicKey = null;
84 try {
85 publicKey = AuthenticatorBrowser.getInstance().getPublicKey(colleagueName);
86 } catch (InvalidKeySpecException | NoSuchAlgorithmException | KeyStoreException | CertificateException
87 | ClassNotFoundException | IOException | SQLException e) {
88 System.err.println("Error while sending message. Unable to obtain public key for colleague " +
89 colleagueName + ". Exception message: " + e.getMessage());
90 return;
91 }
92
93 // Check we got public key
94 if (publicKey == null) {
95 System.err.println("Error while sending message. Unable to obtain public key for colleague. Have you exchanged contact details?");
96 return;
97 }
98
99 // Send message
100 sendMail(mail, publicKey, databaseFilePath);
101 }
102
103 private static void sendMail(MailEntry mail, PublicKey key, Path databaseFile) {
104 try {
105 Cipher cipher = Cipher.getInstance(AsymmetricAlgorithm + AsymmetricAlgorithmParameters);
106
107 // encrypt the necessary parts of the message
108 //cipher.init(Cipher.ENCRYPT_MODE, key);
109 //String time = Base64.getEncoder().encodeToString(cipher.doFinal(mail.timestamp.getBytes()));
110 cipher.init(Cipher.ENCRYPT_MODE, key);
111 String sender = Base64.getEncoder().encodeToString(cipher.doFinal(mail.sender.getBytes()));
112 cipher.init(Cipher.ENCRYPT_MODE, key);
113 String rec = Base64.getEncoder().encodeToString(cipher.doFinal(mail.receiver.getBytes()));
114 cipher.init(Cipher.ENCRYPT_MODE, key);
115 String message = Base64.getEncoder().encodeToString(cipher.doFinal(mail.message.getBytes()));
116 cipher.init(Cipher.ENCRYPT_MODE, key);
117 String message2 = Base64.getEncoder().encodeToString(cipher.doFinal(mail.message2.getBytes()));
118
119 Map<String, String> options = new HashMap<String, String>();
120 for (String label: mail.options.keySet()) {
121 cipher.init(Cipher.ENCRYPT_MODE, key);
122 String labelEncrypted = Base64.getEncoder().encodeToString(cipher.doFinal(label.getBytes()));
123 cipher.init(Cipher.ENCRYPT_MODE, key);
124 String actionNameEncrypted = Base64.getEncoder().encodeToString(cipher.doFinal(mail.options.get(label).getBytes()));
125 options.put(labelEncrypted, actionNameEncrypted);
126 }
127
128 // write to mail database
129 Connection c = DriverManager.getConnection("jdbc:sqlite:" + databaseFile);
130 String sql = "INSERT INTO EXPMAIL (TIME,SND,REC,MSG,MSG2,OPTS,OPTSVAL) VALUES (?, ?, ?, ?, ?, ?, ?);";
131 PreparedStatement statement = c.prepareStatement(sql);
132 statement.setString(1, mail.timestamp);
133 statement.setString(2, sender);
134 statement.setString(3, rec);
135 statement.setString(4, message);
136 statement.setString(5, message2);
137 String opts = Arrays.toString(options.keySet().toArray());
138 statement.setString(6, opts);
139 String optsval = Arrays.toString(options.values().toArray());
140 statement.setString(7, optsval);
141 statement.execute();
142 statement.close();
143 c.close();
144 } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | SQLException e) {
145 e.printStackTrace();
146 }
147 }
148
149 /**
150 * Gets the mail messages that the specified user is able to read.
151 * The caller supplies their username and private key.
152 * If the private key can decrypt a message, then it was encrypted using the users public key, and is therefore for them.
153 */
154 public static List<MailEntry> getEntries(String name, PrivateKey key) throws NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
155 List<MailEntry> filtered = new ArrayList<MailEntry>();
156
157 for (MailEntry mail: messages) {
158 // confirm this is a message for the requester of entries
159 String receiver = mail.receiver;
160 byte[] receiverBytes = Base64.getDecoder().decode(receiver);
161 String receiverDecrypted = null;
162 Cipher c = Cipher.getInstance(AsymmetricAlgorithm + AsymmetricAlgorithmParameters);
163 try {
164 c.init(Cipher.DECRYPT_MODE, key);
165 receiverDecrypted = new String(c.doFinal(receiverBytes));
166 } catch (InvalidKeyException | BadPaddingException e) {
167 // this is not a message for 'us'
168 continue;
169 }
170
171 // add an unencrypted version of the message to the return list
172 if (receiverDecrypted.compareToIgnoreCase(name) == 0) {
173 c.init(Cipher.DECRYPT_MODE, key);
174 String sender = new String(c.doFinal(Base64.getDecoder().decode(mail.sender)));
175 c.init(Cipher.DECRYPT_MODE, key);
176 String message = new String(c.doFinal(Base64.getDecoder().decode(mail.message)));
177 c.init(Cipher.DECRYPT_MODE, key);
178 String message2 = new String(c.doFinal(Base64.getDecoder().decode(mail.message2)));
179
180 Map<String, String> options = new HashMap<String, String>(); //mail.options;
181 for (String label: mail.options.keySet()) {
182 c.init(Cipher.DECRYPT_MODE, key);
183 String labelDecrypted = new String(c.doFinal(Base64.getDecoder().decode(label)));
184 c.init(Cipher.DECRYPT_MODE, key);
185 String actionNameDecrypted = new String(c.doFinal(Base64.getDecoder().decode(mail.options.get(label))));
186 options.put(labelDecrypted, actionNameDecrypted);
187 }
188
189 Path lastAccessedFile = Paths.get(FrameIO.DEAD_DROPS_PATH).resolve(sender).resolve(name + ".last-accessed");
190 SimpleDateFormat format = new SimpleDateFormat("ddMMMyyyy[HH:mm]");
191 MailEntry mailEntry = new MailEntry(mail.timestamp, sender, receiverDecrypted, message, message2, options);
192 try (Scanner in = new Scanner(lastAccessedFile.toFile())) {
193 Date lastAccessedTimestamp = format.parse(in.nextLine());
194 Date mailTimestamp = format.parse(mail.timestamp);
195 if (mailTimestamp.after(lastAccessedTimestamp)) {
196 filtered.add(mailEntry);
197 }
198 } catch (FileNotFoundException e) {
199 // It may not have been created yet, then err on the safe side and add it in.
200 filtered.add(mailEntry);
201 } catch (ParseException e) {
202 // If we fail to parse, then err on the safe side and add it in.
203 filtered.add(mailEntry);
204 }
205
206 }
207 }
208
209 return filtered;
210 }
211
212 /**
213 * Describes a piece of mail, either encrypted or decrypted.
214 */
215 public static class MailEntry {
216 public String timestamp;
217 public String sender;
218 public String receiver;
219 public String message;
220 public String message2;
221 public Map<String, String> options;
222
223 public MailEntry(String timestamp, String sender, String rec, String message, String message2, Map<String, String> options) {
224 this.timestamp = timestamp;
225 this.sender = sender;
226 this.receiver = rec;
227 this.message = message;
228 this.message2 = message2;
229 this.options = options;
230 }
231 }
232}
Note: See TracBrowser for help on using the repository browser.