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

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

Changes have been made to how mail is stored. Each user now has a location in their deaddrops folder (found inside their resources folder) that acts as an exchange location for each of their partnerships. Mail databases now belong in there.

Initial functionality to support the culling of already processed messages from the mail database has been implemented with more to follow.

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