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

Last change on this file was 1508, checked in by bnemhaus, 4 years ago

The HetrogeneousEncryptionLabels frame property is now set automatically when the owner of the frame is saving out an encrypted frame.
Also fixed some issues setting frame properties on load. For example, when loading a frame, the FrameEncryptionLabel should be set regardless of if you have permission to set the label.

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