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

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

Injecting an encryption label into an XRayable Item now injects that encryption label into the source item as well.

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