source: trunk/src/org/expeditee/encryption/io/EncryptedExpWriter.java@ 1431

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

Recoding of the Labels class to improve surrogate mode functionality. Surrogate mode is now maintained when you navigate from one frame to another, even if that frame has a different set of labels. Completely different sets of labels cause Expeditee to exit surrogate mode with a message to the user.

File size: 9.8 KB
Line 
1package org.expeditee.encryption.io;
2
3import java.io.IOException;
4import java.lang.reflect.InvocationTargetException;
5import java.lang.reflect.Method;
6import java.security.InvalidKeyException;
7import java.security.NoSuchAlgorithmException;
8import java.util.Arrays;
9import java.util.Base64;
10import java.util.LinkedHashMap;
11import java.util.List;
12import java.util.function.BinaryOperator;
13import java.util.function.Function;
14import java.util.stream.Collectors;
15
16import javax.crypto.BadPaddingException;
17import javax.crypto.Cipher;
18import javax.crypto.IllegalBlockSizeException;
19import javax.crypto.NoSuchPaddingException;
20import javax.crypto.SecretKey;
21import javax.crypto.spec.SecretKeySpec;
22
23import org.expeditee.encryption.CryptographyConstants;
24import org.expeditee.encryption.items.surrogates.EncryptionDetail;
25import org.expeditee.encryption.items.surrogates.EncryptionDetail.Type;
26import org.expeditee.encryption.items.surrogates.Label.LabelResult;
27import org.expeditee.encryption.items.surrogates.Label;
28import org.expeditee.encryption.items.surrogates.Label.LabelInfo;
29import org.expeditee.gui.Frame;
30import org.expeditee.gui.Frame.BodyType;
31import org.expeditee.gui.MessageBay;
32import org.expeditee.io.Conversion;
33import org.expeditee.io.ExpWriter;
34import org.expeditee.items.Item;
35import org.expeditee.items.Line;
36import org.expeditee.items.Text;
37import org.expeditee.settings.identity.secrets.KeyList;
38import org.expeditee.stats.SessionStats;
39
40public class EncryptedExpWriter extends ExpWriter implements CryptographyConstants {
41 private SecretKey key;
42
43 private final String label;
44
45 private static final String ENCRYPTED_EXP_FLAG = "EncryptedExp";
46 private static final String nl = "\n";
47 private static final String labelProfile = "Profile";
48 private static final String labelNone = "None";
49 protected static final char TERMINATOR = 'Z';
50 protected static final String TERMINATOR_WITH_CONTINUATION = TERMINATOR + "...";
51
52 public EncryptedExpWriter(String encryptionLabel) {
53 label = encryptionLabel;
54 if (label.equals(labelNone)) {
55 return;
56 }
57
58 if (label.equals(labelProfile)) {
59 // obtain personal key
60 Text text = KeyList.PersonalKey.get();
61 List<String> data = text.getData();
62 if (data != null && !data.isEmpty()) {
63 byte[] keyBytes = Base64.getDecoder().decode(data.get(0));
64 key = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
65 }
66 } else {
67 LabelInfo res = Label.getLabel(label);
68 if (res.is(LabelResult.SuccessResolveLabelToKey)) {
69 byte[] keyBytes = res.key;
70 key = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
71 } else if (res.is(LabelResult.ErrorUnableToFindLabel)) {
72 MessageBay.errorMessage(res.toString() + encryptionLabel);
73 key = null;
74 } else {
75 MessageBay.errorMessage(res.toString());
76 }
77 }
78 }
79
80 @Override
81 protected void preOutputFrame() {
82 try {
83 String line = ENCRYPTED_EXP_FLAG + label + nl;
84 _writer.write(line);
85 _stringWriter.append(line);
86 } catch (final IOException e) {
87 e.printStackTrace();
88 }
89 }
90
91 @Override
92 public void outputFrame(Frame frame) throws IOException {
93 if (_writer == null) { return; }
94
95 preOutputFrame();
96 writeHeader(frame);
97
98 // write item
99 writeItemData(frame, true);
100 writeTerminator();
101 // write lines and constraints
102 writeLineData();
103 writeTerminator();
104 writeConstraintData();
105
106 // write surrogate items
107 if (frame.hasSurrogates()) {
108 writeSurrogateTerminator();
109 writeItemData(frame, false);
110 writeTerminator();
111 } else {
112 writeTerminator();
113 }
114
115 writeLine(SessionStats.getFrameEventList(frame));
116 }
117
118 @Override
119 protected void writeLine(String line) throws IOException {
120 // do not write empty lines
121 if (line == null) { return; }
122
123 String toWrite;
124 if (key == null && label.equals(labelNone)) {
125 toWrite = line + nl;
126 } else {
127 // prepare line to write out
128 byte[] encrypted = EncryptSymmetric(line.getBytes(), key);
129 toWrite = Base64.getEncoder().encodeToString(encrypted) + nl;
130 }
131
132 // output
133 _writer.write(toWrite);
134 _stringWriter.append(toWrite);
135 }
136
137 protected void writeClass(Item toWrite) throws IOException {
138 LinkedHashMap<Character,Method> itemTags = new LinkedHashMap<Character, Method>(getItemCharTags());
139 LinkedHashMap<String,Method> itemTagsExt = new LinkedHashMap<String, Method>(getItemStrTags());
140
141 writeTag(toWrite, new Object[] {}, itemTags, 'S');
142 writeTag(toWrite, new Object[] {}, itemTagsExt, "_el");
143
144 if (toWrite.isSurrogate()) {
145 writeLine("SurrogateFor " + toWrite.getPrimary().getID());
146 }
147
148 itemTags.remove('S');
149 itemTagsExt.remove("_el");
150
151 writeTags(toWrite, new Object[] {}, itemTags);
152 writeTags(toWrite, new Object[] {}, itemTagsExt);
153 }
154
155 @Override
156 protected <T> void writeTag(Item toWrite, Object[] param, LinkedHashMap<T, Method> tags, T tag) {
157 if (toWrite.isSurrogate() && toWrite.isTagInherited(tag + "")) {
158 return;
159 }
160 EncryptionDetail encryptionDetail = toWrite.getEncryptionDetailForTag(tag + "");
161 Type encryptionDetailType = encryptionDetail.getEncryptionDetailType();
162
163 switch(encryptionDetailType) {
164 case UnencryptedOnSave:
165 writeTagUnencryptedOnSave(toWrite, param, tags, tag);
166 break;
167 case InheritanceCheckOnSave:
168 writeTagInheritanceCheckOnSave(toWrite, tags, tag);
169 break;
170 case ReencryptOnSave:
171 writeTagReencryptOnSave(toWrite, tags, tag);
172 break;
173 case UseUndecipheredValueOnSave:
174 writeTagUseUndecipheredValueOnSave(toWrite, tags, tag);
175 break;
176 }
177 }
178
179 private void writeItemData(Frame frame, boolean primaryItems) throws IOException {
180 // write each item in the frame
181 BodyType bodyType = primaryItems ? BodyType.PrimaryBody : BodyType.SurrogateBody;
182 for (Item i : frame.getItemsToSave(bodyType)) {
183 assert (!(i instanceof Line));
184 writeItem(i);
185 }
186
187 for (Item i: frame.getBodyItemsWithInsufficientPermissions()) {
188 assert (!(i instanceof Line));
189 writeItem(i);
190 }
191 }
192
193 private <T> void writeTagInheritanceCheckOnSave(Item toWrite, LinkedHashMap<T, Method> tags, T tag) {
194 List<Item> surrogateItems = toWrite.getSurrogates().stream().collect(Collectors.toList());
195 Function<Item, Boolean> isTagInherited = surrogate -> surrogate.isTagInherited(tag + "");
196 BinaryOperator<Boolean> trueExists = (a, b) -> a || b;
197 boolean surrogatesInherit = surrogateItems.stream().map(isTagInherited).collect(Collectors.reducing(trueExists)).orElseGet(() -> false);
198 boolean userHasKey = Label.getLabel(toWrite.getEncryptionLabel()).is(LabelResult.SuccessResolveLabelToKey);
199
200 // If we have no surrogates that inherit this property from us, and we have the label required to encrypt it, then we should encrypt it.
201 if (!surrogatesInherit && userHasKey) {
202 EncryptionDetail reencryptOnSave = new EncryptionDetail(EncryptionDetail.Type.ReencryptOnSave);
203 toWrite.setEncryptionDetailForTag(tag + "", reencryptOnSave);
204 writeTagReencryptOnSave(toWrite, tags, tag);
205 } else {
206 // If one or more surrogates still inherit from us, or we do not have the label, then we write it out unencrypted.
207 EncryptionDetail unencryptedOnSave = new EncryptionDetail(EncryptionDetail.Type.UnencryptedOnSave);
208 toWrite.setEncryptionDetailForTag(tag + "", unencryptedOnSave);
209 writeTagUnencryptedOnSave(toWrite, new Object[] {}, tags, tag);
210 }
211 }
212
213 private <T> void writeTagReencryptOnSave(Item toWrite, LinkedHashMap<T, Method> tags, T tag) {
214 Method toRun = tags.get(tag);
215 Class<?> declarer = toRun.getDeclaringClass();
216 LabelInfo res = Label.getLabel(toWrite.getEncryptionLabel());
217 if (declarer.isAssignableFrom(toWrite.getClass()) && res.is(LabelResult.SuccessResolveLabelToKey)) {
218 try {
219 Object o = toRun.invoke(toWrite, new Object[] {});
220 o = Conversion.ConvertToExpeditee(toRun, o);
221 if (o == null) {
222 return;
223 }
224 if (o instanceof List) {
225 for (Object line: (List<?>) o) {
226 writeLineEnc(tag, line, res.key);
227 }
228 } else {
229 writeLineEnc(tag, o, res.key);
230 }
231 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
232 e.printStackTrace();
233 } catch (IOException e) {
234 e.printStackTrace();
235 }
236 }
237 }
238
239 private <T> void writeTagUseUndecipheredValueOnSave(Item toWrite, LinkedHashMap<T, Method> tags, T tag) {
240 EncryptionDetail encryptionDetail = toWrite.getEncryptionDetailForTag(tag + "");
241 try {
242 writeLine(tag + "E", encryptionDetail.getUndecipheredValue());
243 } catch (IOException e) {
244 e.printStackTrace();
245 }
246 }
247
248 private <T> void writeTagUnencryptedOnSave(Item toWrite, Object[] param, LinkedHashMap<T, Method> tags, T tag) {
249 super.writeTag(toWrite, param, tags, tag);
250 }
251
252 private void writeSurrogateTerminator() throws IOException {
253 writeLine(TERMINATOR_WITH_CONTINUATION + nl);
254 }
255
256 private <T> void writeLineEnc(T tag, Object line, byte[] keyBytes) throws IOException {
257 SecretKey key = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
258 byte[] lineEncryptedBytes = EncryptSymmetric(line.toString().getBytes(), key);
259 line = Base64.getEncoder().encodeToString(lineEncryptedBytes);
260 writeLine(tag + "E", line.toString());
261 }
262
263 private static byte[] EncryptSymmetric(byte[] toEncrypt, SecretKey key) {
264 try {
265 Cipher cipher = Cipher.getInstance(SymmetricAlgorithm + SymmetricAlgorithmParameters);
266 cipher.init(Cipher.ENCRYPT_MODE, key);
267 //could use modulus
268 int length = (int) ((Math.ceil(toEncrypt.length / 16f)) * 16);
269 byte[] toEncryptSizeAdjusted = Arrays.copyOf(toEncrypt, length);
270 byte[] result = cipher.doFinal(toEncryptSizeAdjusted);
271 return result;
272 } catch (final NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
273 | IllegalBlockSizeException | BadPaddingException e) {
274 e.printStackTrace();
275 return null;
276 }
277 }
278}
Note: See TracBrowser for help on using the repository browser.