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

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

More amendments to the way surrogates are handled. Including renaming classic to primary.

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