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

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

Permissions for encrypting frames are now respected. (Group level permissions still need testing and maybe implementation)

The current implementation of Hetrogeneous Owner requires that the owner of the frame specify the available labels. Injecting the property "HetrogeneousEncryptionLabels: <label name>" into the frame name item adds the specified label to the list of labels that those with 'Hetrogeneous (Owner)' permission are able to use.

File size: 9.9 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(getLabelNone())) {
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(getLabelNone())) {
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
279 /**
280 * @return the labelnone
281 */
282 public static String getLabelNone() {
283 return labelNone;
284 }
285}
Note: See TracBrowser for help on using the repository browser.