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

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

Renamed Frame.getItems() to Frame.getSortedItems() to better represent its functionality.

-> org.apollo.ApolloGestureActions
-> org.apollo.ApolloSystem
-> org.expeditee.actions.Actions
-> org.expeditee.actions.Debug
-> org.expeditee.actions.ExploratorySearchActions
-> org.expeditee.actions.JfxBrowserActions
-> org.expeditee.actions.Misc
-> org.expeditee.actions.Navigation
-> org.expeditee.actions.ScriptBase
-> org.expeditee.actions.Simple
-> org.expeditee.agents.ComputeTree
-> org.expeditee.agents.CopyTree
-> org.expeditee.agents.DisplayComet
-> org.expeditee.agents.DisplayTree
-> org.expeditee.agents.DisplayTreeLeaves
-> org.expeditee.agents.GraphFramesetLinks
-> org.expeditee.agents.TreeProcessor
-> org.expeditee.gio.gesture.StandardGestureActions
-> org.expeditee.gui.DisplayController
-> org.expeditee.gui.FrameCreator
-> org.expeditee.gui.FrameIO
-> org.expeditee.io.DefaultTreeWriter
-> org.expeditee.io.JavaWriter
-> org.expeditee.io.PDF2Writer
-> org.expeditee.io.TXTWriter
-> org.expeditee.io.WebParser
-> org.expeditee.io.flowlayout.XGroupItem
-> org.expeditee.items.Dot
-> org.expeditee.items.Item
-> org.expeditee.items.ItemUtils
-> org.expeditee.network.FrameShare
-> org.expeditee.stats.TreeStats


Created ItemsList class to wrap ArrayList<Item>. Frames now use this new class to store its body list (used for display) as well as its primaryBody and surrogateBody.

-> org.expeditee.agents.Format
-> org.expeditee.agents.HFormat
-> org.expeditee.gio.gesture.StandardGestureActions
-> org.expeditee.gui.Frame
-> org.expeditee.gui.FrameUtils


Refactorted Frame.setResort(bool) to Frame.invalidateSorted() to better function how it is intended to with a more accurate name.

-> org.expeditee.agents.Sort


When writing out .exp files and getting attributes to respond to LEFT + RIGHT click, boolean items are by default true. This has always been the case. An ammendment to this is that defaults can now be established.
Also added 'EnterClick' functionality. If cursored over a item with this property and you press enter, it acts as if you have clicked on it instead.

-> org.expeditee.assets.resources-public.framesets.authentication.1.exp to 6.exp
-> org.expeditee.gio.gesture.StandardGestureActions
-> org.expeditee.gio.input.KBMInputEvent
-> org.expeditee.gio.javafx.JavaFXConversions
-> org.expeditee.gio.swing.SwingConversions
-> org.expeditee.gui.AttributeUtils
-> org.expeditee.io.Conversion
-> org.expeditee.io.DefaultFrameWriter
-> org.expeditee.items.Item


Fixed a bug caused by calling Math.abs on Integer.MIN_VALUE returning unexpected result. Due to zero being a thing, you cannot represent Math.abs(Integer.MIN_VALUE) in a Integer object. The solution is to use Integer.MIN_VALUE + 1 instead of Integer.MIN_VALUE.

-> org.expeditee.core.bounds.CombinationBounds
-> org.expeditee.io.flowlayout.DimensionExtent


Recoded the contains function in EllipticalBounds so that intersection tests containing circles work correctly.

-> org.expeditee.core.bounds.EllipticalBounds


Added toString() to PolygonBounds to allow for useful printing during debugging.

-> org.expeditee.core.bounds.PolygonBounds

Implemented Surrogate Mode!

-> org.expeditee.encryption.io.EncryptedExpReader
-> org.expeditee.encryption.io.EncryptedExpWriter
-> org.expeditee.encryption.items.surrogates.EncryptionDetail
-> org.expeditee.encryption.items.surrogates.Label
-> org.expeditee.gui.FrameUtils
-> org.expeditee.gui.ItemsList
-> org.expeditee.items.Item
-> org.expeditee.items.Text


???? Use Integer.MAX_VALUE cast to a float instead of Float.MAX_VALUE. This fixed some bug which I cannot remember.

-> org.expeditee.gio.TextLayoutManager
-> org.expeditee.gio.swing.SwingTextLayoutManager


Improved solution for dealing with the F10 key taking focus away from Expeditee due to it being a assessibility key.

-> org.expeditee.gio.swing.SwingInputManager


Renamed variable visibleItems in FrameGraphics.paintFrame to itemsToPaintCanditates to better represent functional intent.

-> org.expeditee.gui.FrameGraphics


Improved checking for if personal resources exist before recreating them

-> org.expeditee.gui.FrameIO


Repeated messages to message bay now have a visual feedback instead of just a beep. This visual feedback is in the form of a count of the amount of times it has repeated.

-> org.expeditee.gui.MessageBay


Updated comment on the Vector class to explain what vectors are.

-> org.expeditee.gui.Vector


Added constants to represent all of the property keys in DefaultFrameReader and DefaultFrameWriter.

-> org.expeditee.io.DefaultFrameReader
-> org.expeditee.io.DefaultFrameWriter


Updated the KeyList setting to be more heirarcial with how users will store their Secrets.

-> org.expeditee.settings.identity.secrets.KeyList

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