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

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

Changed surrogates to work the way discussed with David. EncryptedExpReader/Writer updated to work with this.

File size: 9.9 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.items.surrogates.EncryptionDetail;
27import org.expeditee.encryption.items.surrogates.Label;
28import org.expeditee.encryption.items.surrogates.Label.LabelResult;
29import org.expeditee.gui.Frame;
30import org.expeditee.gui.FrameIO;
31import org.expeditee.io.Conversion;
32import org.expeditee.io.ExpReader;
33import org.expeditee.items.Item;
34import org.expeditee.items.Text;
35import org.expeditee.settings.identity.secrets.KeyList;
36
37public class EncryptedExpReader extends ExpReader implements CryptographyConstants {
38
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 static boolean isEncryptedExpediteeFile(final String path) throws IOException {
46 final BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(path), "UTF-8"));
47 final String firstLine = in.readLine();
48 in.close();
49 return firstLine.startsWith(ENCRYPTED_EXP_FLAG);
50 }
51
52 public EncryptedExpReader(String frameName) {
53 super(frameName);
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
135 String tag = getTagEnc(next);
136 if (next.startsWith("S ")) {
137 currentItem = newItem(next);
138 _linePoints.put(currentItem.getID(), currentItem);
139 newFrame.addItem(currentItem);
140 currentItem.setEncryptionDetailForTag(tag + "", EncryptionDetail.UnencryptedOnSave);
141 } else if (next.startsWith("SurrogateFor")) {
142 int parentID = Integer.parseInt(next.split(" ")[1]);
143 newFrame.getItemWithID(parentID).addToSurrogates(currentItem);
144 } else if (currentItem != null && actionShouldBeDelayed(tag.charAt(0))) {
145 delayedActions.add(new DelayedAction(currentItem, next));
146 } else if (currentItem != null) {
147 processBodyLine(currentItem, next);
148 } else {
149 System.err.println("Error while reading in frame (ExpReader): Found body line but no current item to apply it to.");
150 }
151 }
152
153 if (next.equals(EncryptedExpWriter.SURROGATE_TERMINATOR)) {
154 next = readTheItems(newFrame, delayedActions);
155 }
156
157 return next;
158 }
159
160 @Override
161 protected void processBodyLine(Item item, String line) {
162 // separate the tag from the value
163 String tag = getTagEnc(line);
164 String value = getValue(line);
165
166 if (item.isSurrogate() && item.isTagInherited(tag)) {
167 return;
168 }
169
170 // Attempt to decrypt the line if necessary.
171 if (isEncryptedLine(line)) {
172 LabelResult res = Label.resolveKey(item.getEncryptionLabel());
173 if (res == LabelResult.SuccessResolveLabelToKey) {
174 item.setEncryptionDetailForTag(tag, EncryptionDetail.ReencryptOnSave);
175 SecretKey key = new SecretKeySpec(res.key, SymmetricAlgorithm);
176 byte[] decryptedBytes = DecryptSymmetric(Base64.getDecoder().decode(value), key);
177 value = new String(decryptedBytes);
178 } else {
179 EncryptionDetail encryptionDetail = EncryptionDetail.UseUndecipheredValueOnSave.setUndecipheredValue(getValue(line));
180 item.setEncryptionDetailForTag(tag, encryptionDetail);
181 return;
182 }
183 } else {
184 item.setEncryptionDetailForTag(tag, EncryptionDetail.UnencryptedOnSave);
185 }
186
187 // Process the line
188 Method toRun = tag.startsWith("_") ? _ItemTagsExt.get(tag) : _ItemTags.get(tag.charAt(0));
189 if (toRun == null) {
190 System.out.println("Error accessing tag method: " + tag);
191 }
192 Object[] vals = Conversion.Convert(toRun, value);
193 try {
194 if (vals != null) {
195 toRun.invoke(item, vals);
196 }
197 } catch (Exception e) {
198 System.out.println("Error running tag method: " + tag);
199 e.printStackTrace();
200 }
201 }
202
203 protected static String getValue(String line) {
204 String[] split = line.split(" ");
205 if (split.length >= 2) {
206 return line.substring(split[0].length()).trim();
207 } else {
208 return null;
209 }
210 }
211
212 private static String getTagEnc(String line) {
213 char charAtZero = line.charAt(0);
214 if (charAtZero == '_') {
215 return line.split(" ")[0];
216 } else {
217 return charAtZero + "";
218 }
219 }
220
221 private static boolean isEncryptedLine(String line) {
222 if (line.startsWith("S") || line.startsWith("_el")) {
223 return false;
224 }
225 if (line.length() > 2) {
226 return line.charAt(1) == 'E';
227 } else {
228 return false;
229 }
230 }
231
232 private static byte[] DecryptSymmetric(final byte[] toDecrypt, final SecretKey key) {
233 try {
234 final Cipher cipher = Cipher.getInstance(SymmetricAlgorithm + SymmetricAlgorithmParameters);
235 cipher.init(Cipher.DECRYPT_MODE, key);
236 final byte[] decryptedBytes = cipher.doFinal(toDecrypt);
237 int indexOfZero = decryptedBytes.length - 1;
238 for (int i = decryptedBytes.length - 1; i >= 0; i--) {
239 if (decryptedBytes[i] != (byte) 0) {
240 indexOfZero = i + 1;
241 break;
242 }
243 }
244 if (indexOfZero < 0) { return decryptedBytes; }
245 else { return Arrays.copyOf(decryptedBytes, indexOfZero); }
246 } catch (final NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
247 | IllegalBlockSizeException | BadPaddingException e) {
248 e.printStackTrace();
249 return null;
250 }
251 }
252
253 private class EncryptedLineReader extends BufferedReader {
254 private boolean noneMode = false;
255
256 public EncryptedLineReader(Reader in) {
257 super(in);
258 }
259
260 @Override
261 /**
262 * Reads a line from an encrypted exp file that uses an encryption specified by the first line of the file.
263 * Returns that line to process, null if the currently logged in users doesn't own the appropriate key (access denied).
264 */
265 public String readLine() throws IOException {
266 String line = super.readLine();
267
268 if (line.isEmpty()) {
269 return "";
270 }
271
272 if (noneMode) {
273 return line;
274 }
275
276 if (line.startsWith(ENCRYPTED_EXP_FLAG)) {
277 String label = line.replace(ENCRYPTED_EXP_FLAG, "");
278 // if using Profile label, use personal key
279 if (label.equals(labelProfile)) {
280 Text text = KeyList.PersonalKey.get();
281 byte[] keyBytes = Base64.getDecoder().decode(text.getData().get(0));
282 personalKey = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
283 return readLine();
284 } else if (label.equals(labelNone)) {
285 noneMode = true;
286 return readLine();
287 } else {
288 personalKey = resolveLabel(label);
289 if (personalKey == null) {
290 return null;
291 } else {
292 return readLine();
293 }
294 }
295 }
296
297 // decrypt line and return result
298 byte[] toDecrypt = Base64.getDecoder().decode(line);
299 byte[] decrypted = DecryptSymmetric(toDecrypt, personalKey);
300 if (decrypted == null) {
301 accessDenied = true;
302 return null; // access denied
303 } else {
304 String decryptedLine = new String(decrypted);
305 if (decryptedLine.startsWith("Z")) {
306 return decryptedLine.trim();
307 } else {
308 return decryptedLine;
309 }
310 }
311 }
312
313 private SecretKeySpec resolveLabel(String label) {
314 LabelResult res = Label.resolveKey(label);
315 if (res == LabelResult.SuccessResolveLabelToKey) {
316 byte[] keyBytes = res.key;
317 return new SecretKeySpec(keyBytes, SymmetricAlgorithm);
318 }
319 return null;
320 }
321 }
322}
Note: See TracBrowser for help on using the repository browser.