source: trunk/src/org/expeditee/encryption/io/EncryptedExpReader.java@ 1408

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

Implementation of the surrogate system.
When you set an item to have a encryption label, a surrogate for that item is generated.
The newly updated EncryptedExpReader/Writer has been updated to maintain the connection between the item and its surrogate.

Coming up next:
Surrogate mode. The ability to simulate viewing and editing an encrypted frame with a limited set of labels.

File size: 11.1 KB
Line 
1package org.expeditee.encryption.io;
2
3import java.io.BufferedReader;
4import java.io.FileInputStream;
5import java.io.FileReader;
6import java.io.IOException;
7import java.io.InputStreamReader;
8import java.io.Reader;
9import java.lang.reflect.Method;
10import java.security.InvalidKeyException;
11import java.security.NoSuchAlgorithmException;
12import java.util.ArrayList;
13import java.util.Arrays;
14import java.util.Base64;
15import java.util.List;
16import java.util.function.Predicate;
17
18import javax.crypto.BadPaddingException;
19import javax.crypto.Cipher;
20import javax.crypto.IllegalBlockSizeException;
21import javax.crypto.NoSuchPaddingException;
22import javax.crypto.SecretKey;
23import javax.crypto.spec.SecretKeySpec;
24
25import org.expeditee.encryption.CryptographyConstants;
26import org.expeditee.encryption.Label;
27import org.expeditee.encryption.Label.LabelResult;
28import org.expeditee.encryption.items.surrogates.EncryptionDetail;
29import org.expeditee.encryption.items.surrogates.Surrogate;
30import org.expeditee.gui.Frame;
31import org.expeditee.gui.FrameIO;
32import org.expeditee.io.Conversion;
33import org.expeditee.io.ExpReader;
34import org.expeditee.items.Item;
35import org.expeditee.items.Text;
36import org.expeditee.settings.identity.secrets.KeyList;
37
38public class EncryptedExpReader extends ExpReader implements CryptographyConstants {
39 private static final String ENCRYPTED_EXP_FLAG = "EncryptedExp";
40 private static final String labelProfile = "Profile";
41 private static final String labelNone = "None";
42 private SecretKey personalKey;
43 private boolean accessDenied = false;
44
45 public EncryptedExpReader(String frameName) {
46 super(frameName);
47 }
48
49 public static boolean isEncryptedExpediteeFile(final String path) throws IOException {
50 final BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(path), "UTF-8"));
51 final String firstLine = in.readLine();
52 in.close();
53 return firstLine.startsWith(ENCRYPTED_EXP_FLAG);
54 }
55
56 public int getVersionEnc(String fullpath) {
57 try {
58 BufferedReader reader = new EncryptedLineReader(new BufferedReader(new FileReader(fullpath)));
59 String next = "";
60 // First read the header lines until we get the version number
61 while (reader.ready() && !(next = reader.readLine()).equals("Z")) {
62 if (isValidLine(next)) {
63 Character tag = getTag(next);
64 String value = getValue(next);
65 if (tag.equals('V')) {
66 reader.close();
67 return Integer.parseInt(value);
68 }
69 }
70 }
71 reader.close();
72 } catch (Exception e) {
73 }
74 return -1;
75 }
76
77 @Override
78 public Frame readFrame(final String fullPath) throws IOException {
79 Reader in = new InputStreamReader(new FileInputStream(fullPath), "UTF-8");
80 return readFrame(new EncryptedLineReader(in));
81 }
82
83 @Override
84 public Frame readFrame(BufferedReader reader) throws IOException {
85 if (accessDenied) { return null; }
86
87 _reader = reader;
88 String next = "";
89 Frame newFrame = new Frame();
90 List<DelayedAction> delayedActions = new ArrayList<DelayedAction>();
91 newFrame.setName(_frameName);
92
93 try {
94 // First read all the header lines
95 next = readTheHeader(newFrame);
96
97 // Now read all the items
98 next = readTheItems(newFrame, delayedActions);
99
100 // Read the lines
101 next = readTheLines(newFrame);
102
103 // Read the constraints
104 next = readTheConstraints();
105
106 for(DelayedAction action: delayedActions) {
107 action.exec();
108 }
109
110 // Read the stats
111 next = readTheStats(newFrame);
112 } catch (Exception e) {
113 e.printStackTrace();
114 System.out.println("Error reading frame file line: " + next + " " + e.getMessage());
115 }
116
117 _reader.close();
118 FrameIO.setSavedProperties(newFrame);
119 newFrame.setChanged(false);
120
121 return newFrame;
122 }
123
124 @Override
125 protected String readTheItems(Frame newFrame, List<DelayedAction> delayedActions) throws IOException {
126 String next = null;
127 Item currentItem = null;
128
129 Predicate<String> endOfSection = s -> s.equals("Z") || s.equals("Z...");
130 while (_reader.ready() && !endOfSection.test(next = _reader.readLine())) {
131 if (!isValidLine(next)) {
132 continue;
133 }
134 String tag = getTagEnc(next);
135 if (tag.equals("S")) {
136 currentItem = newItem(next);
137 _linePoints.put(currentItem.getID(), currentItem);
138 newFrame.addItem(currentItem);
139 currentItem.setEncryptionDetailForTag(tag + "", EncryptionDetail.UnencryptedOnSave);
140 } else if (currentItem != null && actionShouldBeDelayed(tag.charAt(0))) {
141 delayedActions.add(new DelayedAction(currentItem, next));
142 } else if (currentItem != null) {
143 processBodyLine(currentItem, next);
144 } else {
145 System.err.println("Error while reading in frame (ExpReader): Found body line but no current item to apply it to.");
146 }
147 }
148
149 if (next.equals("Z...")) {
150 next = readTheSurrogateItems(newFrame, delayedActions);
151 }
152
153 return next;
154 }
155
156 @Override
157 protected void processBodyLine(Item item, String line) {
158 // separate the tag from the value
159 String tag = getTagEnc(line);
160 String value = getValue(line);
161
162 // Attempt to decrypt the line if necessary.
163 if (isEncryptedLine(line)) {
164 LabelResult res = Label.resolveKey(item.getEncryptionLabel());
165 if (res == LabelResult.SuccessResolveLabelToKey) {
166 item.setEncryptionDetailForTag(tag, EncryptionDetail.ReencryptOnSave);
167 SecretKey key = new SecretKeySpec(res.key, SymmetricAlgorithm);
168 byte[] decryptedBytes = DecryptSymmetric(Base64.getDecoder().decode(value), key);
169 value = new String(decryptedBytes);
170 } else {
171 EncryptionDetail encryptionDetail = EncryptionDetail.UseUndecipheredValueOnSave.setUndecipheredValue(getValue(line));
172 item.setEncryptionDetailForTag(tag, encryptionDetail);
173 return;
174 }
175 } else {
176 item.setEncryptionDetailForTag(tag, EncryptionDetail.UnencryptedOnSave);
177 }
178
179 // Process the line
180 Method toRun = tag.startsWith("_") ? _ItemTagsExt.get(tag) : _ItemTags.get(tag.charAt(0));
181 if (toRun == null) {
182 System.out.println("Error accessing tag method: " + tag);
183 }
184 Object[] vals = Conversion.Convert(toRun, value);
185 try {
186 if (vals != null) {
187 toRun.invoke(item, vals);
188 }
189 } catch (Exception e) {
190 System.out.println("Error running tag method: " + tag);
191 e.printStackTrace();
192 }
193 }
194
195 private String readTheSurrogateItems(Frame newFrame, List<DelayedAction> delayedActions) throws IOException {
196 String next = null;
197 Item currentItem = null;
198
199 Predicate<String> endOfSection = s -> s.equals("Z") || s.equals("Z...");
200 while (_reader.ready() && !endOfSection.test(next = _reader.readLine())) {
201 if (!isValidLine(next)) {
202 continue;
203 }
204
205 String tag = getTagEnc(next);
206 if (tag.equals("S") && !next.startsWith("SurrogateFor")) {
207 currentItem = newItem(next);
208 currentItem.setEncryptionDetailForTag(tag + "", EncryptionDetail.UnencryptedOnSave);
209 } else if (next.startsWith("SurrogateFor")) {
210 String id = next.split(" ")[1];
211 Item classic = newFrame.getItemWithID(Integer.parseInt(id));
212 if (id == null) {
213 System.err.println("WARNING: Attempted to create surrogate for classic ID " +
214 id + " but was no item on frame " + newFrame.getName() + " exists.");
215 continue;
216 }
217 currentItem.setAsSurrogateFor(classic);
218 classic.addToSurrogates(new Surrogate(currentItem));
219 } else if (currentItem != null && actionShouldBeDelayed(getTag(next))) {
220 delayedActions.add(new DelayedAction(currentItem, next));
221 } else if (currentItem != null) {
222 processBodyLine(currentItem, next);
223 } else {
224 System.err.println("Error while reading in frame (ExpReader): Found body line but no current item to apply it to.");
225 }
226 }
227
228 return next;
229 }
230
231 protected static String getTagEnc(String line) {
232 char charAtZero = line.charAt(0);
233 if (charAtZero == '_') {
234 return line.split(" ")[0];
235 } else {
236 return charAtZero + "";
237 }
238 }
239
240 protected static String getValue(String line) {
241 String[] split = line.split(" ");
242 if (split.length >= 2) {
243 return line.substring(split[0].length()).trim();
244 } else {
245 return null;
246 }
247 }
248
249 protected static boolean isEncryptedLine(String line) {
250 if (line.startsWith("S") || line.startsWith("_el")) {
251 return false;
252 }
253 if (line.length() > 2) {
254 return line.charAt(1) == 'E';
255 } else {
256 return false;
257 }
258 }
259
260 private static byte[] DecryptSymmetric(final byte[] toDecrypt, final SecretKey key) {
261 try {
262 final Cipher cipher = Cipher.getInstance(SymmetricAlgorithm + SymmetricAlgorithmParameters);
263 cipher.init(Cipher.DECRYPT_MODE, key);
264 final byte[] decryptedBytes = cipher.doFinal(toDecrypt);
265 int indexOfZero = decryptedBytes.length - 1;
266 for (int i = decryptedBytes.length - 1; i >= 0; i--) {
267 if (decryptedBytes[i] != (byte) 0) {
268 indexOfZero = i + 1;
269 break;
270 }
271 }
272 if (indexOfZero < 0) { return decryptedBytes; }
273 else { return Arrays.copyOf(decryptedBytes, indexOfZero); }
274 } catch (final NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
275 | IllegalBlockSizeException | BadPaddingException e) {
276 e.printStackTrace();
277 return null;
278 }
279 }
280
281 private class EncryptedLineReader extends BufferedReader {
282 private boolean noneMode = false;
283
284 public EncryptedLineReader(Reader in) {
285 super(in);
286 }
287
288 @Override
289 /**
290 * Reads a line from an encrypted exp file that uses an encryption specified by the first line of the file.
291 * Returns that line to process, null if the currently logged in users doesn't own the appropriate key (access denied).
292 */
293 public String readLine() throws IOException {
294 String line = super.readLine();
295
296 if (line.isEmpty()) {
297 return "";
298 }
299
300 if (noneMode) {
301 return line;
302 }
303
304 if (line.startsWith(ENCRYPTED_EXP_FLAG)) {
305 String label = line.replace(ENCRYPTED_EXP_FLAG, "");
306 // if using Profile label, use personal key
307 if (label.equals(labelProfile)) {
308 Text text = KeyList.PersonalKey.get();
309 byte[] keyBytes = Base64.getDecoder().decode(text.getData().get(0));
310 personalKey = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
311 return readLine();
312 } else if (label.equals(labelNone)) {
313 noneMode = true;
314 return readLine();
315 } else {
316 personalKey = resolveLabel(label);
317 if (personalKey == null) {
318 return null;
319 } else {
320 return readLine();
321 }
322 }
323 }
324
325 // decrypt line and return result
326 byte[] toDecrypt = Base64.getDecoder().decode(line);
327 byte[] decrypted = DecryptSymmetric(toDecrypt, personalKey);
328 if (decrypted == null) {
329 accessDenied = true;
330 return null; // access denied
331 } else {
332 String decryptedLine = new String(decrypted);
333 if (decryptedLine.startsWith("Z")) {
334 return decryptedLine.trim();
335 } else {
336 return decryptedLine;
337 }
338 }
339 }
340
341 private SecretKeySpec resolveLabel(String label) {
342 LabelResult res = Label.resolveKey(label);
343 if (res == LabelResult.SuccessResolveLabelToKey) {
344 byte[] keyBytes = res.key;
345 return new SecretKeySpec(keyBytes, SymmetricAlgorithm);
346 }
347 return null;
348 }
349 }
350}
Note: See TracBrowser for help on using the repository browser.