Ignore:
Timestamp:
06/21/19 12:12:55 (5 years ago)
Author:
bln4
Message:

Implementation of the surrogate system.
When you set an item to have a encryption label, a surrogate for that item is generated.
The newly updated EncryptedExpReader/Writer has been updated to maintain the connection between the item and its surrogate.

Coming up next:
Surrogate mode. The ability to simulate viewing and editing an encrypted frame with a limited set of labels.

Location:
trunk/src/org/expeditee/encryption
Files:
3 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/expeditee/encryption/Actions.java

    r1389 r1408  
    2323import org.expeditee.gui.Frame;
    2424import org.expeditee.gui.FrameIO;
     25import org.expeditee.items.Item;
    2526import org.expeditee.items.Text;
    2627import org.expeditee.settings.UserSettings;
     
    2930
    3031public class Actions implements CryptographyConstants {
     32       
     33        public static void TestSurrogate(Item classic) {
     34                System.out.println("Test surrogates: ");
     35        }
    3136       
    3237        public static Text GenerateSecret(String label) {
  • trunk/src/org/expeditee/encryption/io/EncryptedExpReader.java

    r1401 r1408  
    77import java.io.InputStreamReader;
    88import java.io.Reader;
    9 import java.io.UnsupportedEncodingException;
     9import java.lang.reflect.Method;
    1010import java.security.InvalidKeyException;
    1111import java.security.NoSuchAlgorithmException;
     12import java.util.ArrayList;
    1213import java.util.Arrays;
    1314import java.util.Base64;
    14 import java.util.Collection;
     15import java.util.List;
     16import java.util.function.Predicate;
    1517
    1618import javax.crypto.BadPaddingException;
     
    2426import org.expeditee.encryption.Label;
    2527import org.expeditee.encryption.Label.LabelResult;
     28import org.expeditee.encryption.items.surrogates.EncryptionDetail;
     29import org.expeditee.encryption.items.surrogates.Surrogate;
    2630import org.expeditee.gui.Frame;
     31import org.expeditee.gui.FrameIO;
     32import org.expeditee.io.Conversion;
    2733import org.expeditee.io.ExpReader;
    2834import org.expeditee.items.Item;
     
    3137
    3238public class EncryptedExpReader extends ExpReader implements CryptographyConstants {
    33         static final String ENCRYPTED_EXP_FLAG = "EncryptedExp";
     39        private static final String ENCRYPTED_EXP_FLAG = "EncryptedExp";
     40        private static final String labelProfile = "Profile";
     41        private static final String labelNone = "None";
    3442        private SecretKey personalKey;
    3543        private boolean accessDenied = false;
    3644
    37         public EncryptedExpReader(final String frameName) throws UnsupportedEncodingException {
     45        public EncryptedExpReader(String frameName) {
    3846                super(frameName);
    3947        }
    40        
     48
    4149        public static boolean isEncryptedExpediteeFile(final String path) throws IOException {
    4250                final BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(path), "UTF-8"));
     
    7482       
    7583        @Override
    76         public Frame readFrame(final BufferedReader reader) throws IOException {
     84        public Frame readFrame(BufferedReader reader) throws IOException {
    7785                if (accessDenied) { return null; }
    78                 else {
    79                         Frame unencryptedFrame = super.readFrame(reader);
    80                         individualItemDecryption(unencryptedFrame);
    81                         return unencryptedFrame;
    82                 }
    83         }
    84        
    85         private void individualItemDecryption(Frame frame) {
    86                 // Find items with their own encryption label.
    87                 Collection<Item> itemsWithEncryptionLabel = frame.getAllItems();
    88                 itemsWithEncryptionLabel.removeIf(i -> i.getEncryptionLabel() == null || i.getEncryptionLabel().isEmpty());
    89                
    90                 for (Item i: itemsWithEncryptionLabel) {
    91                         // Decrypt the Text Items
    92                         if (i instanceof Text) {
    93                                 LabelResult res = Label.resolveKey(i.getEncryptionLabel());
    94                                 if (res == LabelResult.SuccessResolveLabelToKey) {
    95                                         byte[] keyBytes = res.key;
    96                                         if (keyBytes == null) { continue; }
    97                                         SecretKeySpec key = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
    98                                         byte[] decryptedBytes = DecryptSymmetric(Base64.getDecoder().decode(i.getText()), key);
    99                                         i.setText(new String(decryptedBytes));
    100                                 }
    101                         }
     86               
     87                _reader = reader;
     88                String next = "";
     89                Frame newFrame = new Frame();
     90                List<DelayedAction> delayedActions = new ArrayList<DelayedAction>();
     91                newFrame.setName(_frameName);
     92               
     93                try {
     94                        // First read all the header lines
     95                        next = readTheHeader(newFrame);
     96                       
     97                        // Now read all the items
     98                        next = readTheItems(newFrame, delayedActions);
     99                       
     100                        // Read the lines
     101                        next = readTheLines(newFrame);
     102
     103                        // Read the constraints
     104                        next = readTheConstraints();
     105                       
     106                        for(DelayedAction action: delayedActions) {
     107                                action.exec();
     108                        }
     109
     110                        // Read the stats
     111                        next = readTheStats(newFrame);
     112                } catch (Exception e) {
     113                        e.printStackTrace();
     114                        System.out.println("Error reading frame file line: " + next + " " + e.getMessage());
     115                }
     116               
     117                _reader.close();
     118                FrameIO.setSavedProperties(newFrame);
     119                newFrame.setChanged(false);
     120
     121                return newFrame;
     122        }
     123       
     124        @Override
     125        protected String readTheItems(Frame newFrame, List<DelayedAction> delayedActions) throws IOException {
     126                String next = null;
     127                Item currentItem = null;
     128               
     129                Predicate<String> endOfSection = s -> s.equals("Z") || s.equals("Z...");
     130                while (_reader.ready() && !endOfSection.test(next = _reader.readLine())) {
     131                        if (!isValidLine(next)) {
     132                                continue;
     133                        }
     134                        String tag = getTagEnc(next);
     135                        if (tag.equals("S")) {
     136                                currentItem = newItem(next);
     137                                _linePoints.put(currentItem.getID(), currentItem);
     138                                newFrame.addItem(currentItem);
     139                                currentItem.setEncryptionDetailForTag(tag + "", EncryptionDetail.UnencryptedOnSave);
     140                        } else if (currentItem != null && actionShouldBeDelayed(tag.charAt(0))) {
     141                                delayedActions.add(new DelayedAction(currentItem, next));
     142                        } else if (currentItem != null) {
     143                                processBodyLine(currentItem, next);
     144                        } else {
     145                                System.err.println("Error while reading in frame (ExpReader): Found body line but no current item to apply it to.");
     146                        }
     147                }
     148               
     149                if (next.equals("Z...")) {
     150                        next = readTheSurrogateItems(newFrame, delayedActions);
     151                }
     152               
     153                return next;
     154        }
     155       
     156        @Override
     157        protected void processBodyLine(Item item, String line) {
     158                // separate the tag from the value
     159                String tag = getTagEnc(line);
     160                String value = getValue(line);
     161               
     162                // Attempt to decrypt the line if necessary.
     163                if (isEncryptedLine(line)) {
     164                        LabelResult res = Label.resolveKey(item.getEncryptionLabel());
     165                        if (res == LabelResult.SuccessResolveLabelToKey) {
     166                                item.setEncryptionDetailForTag(tag, EncryptionDetail.ReencryptOnSave);
     167                                SecretKey key = new SecretKeySpec(res.key, SymmetricAlgorithm);
     168                                byte[] decryptedBytes = DecryptSymmetric(Base64.getDecoder().decode(value), key);
     169                                value = new String(decryptedBytes);                             
     170                        } else {
     171                                EncryptionDetail encryptionDetail = EncryptionDetail.UseUndecipheredValueOnSave.setUndecipheredValue(getValue(line));
     172                                item.setEncryptionDetailForTag(tag, encryptionDetail);
     173                                return;
     174                        }
     175                } else {
     176                        item.setEncryptionDetailForTag(tag, EncryptionDetail.UnencryptedOnSave);
     177                }
     178               
     179                // Process the line
     180                Method toRun = tag.startsWith("_") ? _ItemTagsExt.get(tag) : _ItemTags.get(tag.charAt(0));
     181                if (toRun == null) {
     182                        System.out.println("Error accessing tag method: " + tag);
     183                }
     184                Object[] vals = Conversion.Convert(toRun, value);
     185                try {
     186                        if (vals != null) {
     187                                toRun.invoke(item, vals);
     188                        }
     189                } catch (Exception e) {
     190                        System.out.println("Error running tag method: " + tag);
     191                        e.printStackTrace();
     192                }
     193        }
     194               
     195        private String readTheSurrogateItems(Frame newFrame, List<DelayedAction> delayedActions) throws IOException {
     196                String next = null;
     197                Item currentItem = null;
     198               
     199                Predicate<String> endOfSection = s -> s.equals("Z") || s.equals("Z...");
     200                while (_reader.ready() && !endOfSection.test(next = _reader.readLine())) {
     201                        if (!isValidLine(next)) {
     202                                continue;
     203                        }
     204                       
     205                        String tag = getTagEnc(next);
     206                        if (tag.equals("S") && !next.startsWith("SurrogateFor")) {
     207                                currentItem = newItem(next);
     208                                currentItem.setEncryptionDetailForTag(tag + "", EncryptionDetail.UnencryptedOnSave);
     209                        } else if (next.startsWith("SurrogateFor")) {
     210                                String id = next.split(" ")[1];
     211                                Item classic = newFrame.getItemWithID(Integer.parseInt(id));
     212                                if (id == null) {
     213                                        System.err.println("WARNING: Attempted to create surrogate for classic ID " +
     214                                                        id + " but was no item on frame " + newFrame.getName() + " exists.");
     215                                        continue;
     216                                }
     217                                currentItem.setAsSurrogateFor(classic);
     218                                classic.addToSurrogates(new Surrogate(currentItem));
     219                        } else if (currentItem != null && actionShouldBeDelayed(getTag(next))) {
     220                                delayedActions.add(new DelayedAction(currentItem, next));
     221                        } else if (currentItem != null) {
     222                                processBodyLine(currentItem, next);
     223                        } else {
     224                                System.err.println("Error while reading in frame (ExpReader): Found body line but no current item to apply it to.");
     225                        }
     226                }
     227
     228                return next;
     229        }
     230       
     231        protected static String getTagEnc(String line) {
     232                char charAtZero = line.charAt(0);
     233                if (charAtZero == '_') {
     234                        return line.split(" ")[0];
     235                } else {
     236                        return charAtZero + "";
     237                }
     238        }
     239       
     240        protected static String getValue(String line) {
     241                String[] split = line.split(" ");
     242                if (split.length >= 2) {
     243                        return line.substring(split[0].length()).trim();
     244                } else {
     245                        return null;
     246                }
     247        }
     248       
     249        protected static boolean isEncryptedLine(String line) {
     250                if (line.startsWith("S") || line.startsWith("_el")) {
     251                        return false;
     252                }               
     253                if (line.length() > 2) {
     254                        return line.charAt(1) == 'E';
     255                } else {
     256                        return false;
    102257                }
    103258        }
     
    125280       
    126281        private class EncryptedLineReader extends BufferedReader {
     282                private boolean noneMode = false;
     283               
    127284                public EncryptedLineReader(Reader in) {
    128285                        super(in);
     
    140297                                return "";
    141298                        }
     299                       
     300                        if (noneMode) {
     301                                return line;
     302                        }
     303                       
    142304                        if (line.startsWith(ENCRYPTED_EXP_FLAG)) {
    143305                                String label = line.replace(ENCRYPTED_EXP_FLAG, "");
    144306                                // if using Profile label, use personal key
    145                                 if (label.startsWith("Profile")) {
     307                                if (label.equals(labelProfile)) {
    146308                                        Text text = KeyList.PersonalKey.get();
    147309                                        byte[] keyBytes = Base64.getDecoder().decode(text.getData().get(0));
    148310                                        personalKey = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
     311                                        return readLine();
     312                                } else if (label.equals(labelNone)) {
     313                                        noneMode = true;
    149314                                        return readLine();
    150315                                } else {
  • trunk/src/org/expeditee/encryption/io/EncryptedExpWriter.java

    r1401 r1408  
    22
    33import java.io.IOException;
     4import java.lang.reflect.InvocationTargetException;
     5import java.lang.reflect.Method;
    46import java.security.InvalidKeyException;
    57import java.security.NoSuchAlgorithmException;
     8import java.util.ArrayList;
    69import java.util.Arrays;
    710import java.util.Base64;
    8 import java.util.Collection;
     11import java.util.LinkedHashMap;
    912import java.util.List;
     13import java.util.function.Consumer;
    1014
    1115import javax.crypto.BadPaddingException;
     
    1923import org.expeditee.encryption.Label;
    2024import org.expeditee.encryption.Label.LabelResult;
     25import org.expeditee.encryption.items.surrogates.EncryptionDetail;
     26import org.expeditee.encryption.items.surrogates.Surrogate;
    2127import org.expeditee.gui.Frame;
    2228import org.expeditee.gui.MessageBay;
     29import org.expeditee.io.Conversion;
    2330import org.expeditee.io.ExpWriter;
    2431import org.expeditee.items.Item;
     32import org.expeditee.items.Line;
    2533import org.expeditee.items.Text;
    2634import org.expeditee.settings.identity.secrets.KeyList;
     35import org.expeditee.stats.SessionStats;
    2736
    2837public class EncryptedExpWriter extends ExpWriter implements CryptographyConstants {
    2938        private SecretKey key;
    30         private String label;
     39       
     40        private final String label;
     41       
     42        private static final String ENCRYPTED_EXP_FLAG = "EncryptedExp";
    3143        private static final String nl = "\n";
    32        
    33         public EncryptedExpWriter(String encryptionLabel) throws IOException {
    34                 if (encryptionLabel.compareTo("Profile") == 0) {
     44        private static final String labelProfile = "Profile";
     45        private static final String labelNone = "None";
     46        protected static final String SURROGATE_TERMINATOR = TERMINATOR + "...";
     47
     48        public EncryptedExpWriter(String encryptionLabel) {
     49                label = encryptionLabel;
     50                if (label.equals(labelNone)) {
     51                        return;
     52                }
     53               
     54                if (label.equals(labelProfile)) {
    3555                        // obtain personal key
    3656                        Text text = KeyList.PersonalKey.get();
     
    4060                                key = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
    4161                        }
    42                         label = "Profile";
    4362                } else {
    44                         LabelResult res = Label.resolveKey(encryptionLabel);
     63                        LabelResult res = Label.resolveKey(label);
    4564                        if (res == LabelResult.SuccessResolveLabelToKey) {
    4665                                byte[] keyBytes = res.key;
    4766                                key = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
    48                                 label = encryptionLabel;
    4967                        } else if (res == LabelResult.ErrorUnableToFindLabel) {
    5068                                MessageBay.errorMessage(res.toString() + encryptionLabel);
     69                                key = null;
    5170                        } else {
    5271                                MessageBay.errorMessage(res.toString());
     
    5473                }
    5574        }
    56 
     75       
     76        @Override
     77        public void outputFrame(Frame frame) throws IOException {
     78                if (_writer == null) { return; }
     79               
     80                preOutputFrame();
     81                writeHeader(frame);
     82               
     83                // write item
     84                writeItemData(frame);
     85                writeTerminator();
     86               
     87                // write lines and constraints
     88                writeLineData();
     89                writeTerminator();
     90                writeConstraintData();
     91                writeTerminator();
     92               
     93                writeLine(SessionStats.getFrameEventList(frame));
     94        }
     95       
    5796        @Override
    5897        protected void preOutputFrame() {
    5998                try {
    60                         String line = EncryptedExpReader.ENCRYPTED_EXP_FLAG + label + nl;
     99                        String line = ENCRYPTED_EXP_FLAG + label + nl;
    61100                        _writer.write(line);
    62101                        _stringWriter.append(line);
     
    67106       
    68107        @Override
    69         public void outputFrame(Frame frame) throws IOException {
    70                 individualItemEncryption(frame);
    71                 super.outputFrame(frame);
    72         }
    73        
    74         @Override
    75108        protected void writeLine(String line) throws IOException {
    76109                // do not write empty lines
    77110                if (line == null) { return; }
    78111               
    79                 // prepare line to write out
    80                 byte[] encrypted = EncryptSymmetric(line.getBytes(), key);
    81                 String toWrite = Base64.getEncoder().encodeToString(encrypted) + nl;
    82                
     112                String toWrite;
     113                if (key == null && label.equals(labelNone)) {
     114                        toWrite = line + nl;
     115                } else {
     116                        // prepare line to write out
     117                        byte[] encrypted = EncryptSymmetric(line.getBytes(), key);
     118                        toWrite = Base64.getEncoder().encodeToString(encrypted) + nl;
     119                }
     120                               
    83121                // output
    84122                _writer.write(toWrite);
     
    86124        }
    87125       
    88         private void individualItemEncryption(Frame frame) {
    89                 // Find items with their own encryption label.
    90                 Collection<Item> itemsWithEncryptionLabel = frame.getAllItems();
    91                 itemsWithEncryptionLabel.removeIf(i -> i.getEncryptionLabel() == null || i.getEncryptionLabel().isEmpty());
    92                
    93                 for (Item i: itemsWithEncryptionLabel) {
    94                         // Encrypt the Text Items
    95                         if (i instanceof Text) {
    96                                 LabelResult res = Label.resolveKey(i.getEncryptionLabel());
    97                                 if (res == LabelResult.SuccessResolveLabelToKey) {
    98                                         byte[] keyBytes = res.key;
    99                                         if (keyBytes == null) { continue; }
    100                                         SecretKeySpec key = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
    101                                         byte[] encryptedBytes = EncryptSymmetric(i.getText().getBytes(), key);
    102                                         i.setText(Base64.getEncoder().encodeToString(encryptedBytes));
     126        @Override
     127        protected void writeLineData() throws IOException {
     128                super.writeLineData();
     129               
     130                writeSurrogateLineData();
     131        }
     132       
     133        @Override
     134        protected void writeClass(Item toWrite) throws IOException {
     135                LinkedHashMap<Character,Method> itemTags = new LinkedHashMap<Character, Method>(getItemTags());
     136                LinkedHashMap<String,Method> itemTagsExt = new LinkedHashMap<String, Method>(getItemTagsExt());
     137               
     138                writeTag(toWrite, new Object[] {}, itemTags, 'S');
     139                writeTag(toWrite, new Object[] {}, itemTagsExt, "_el");
     140               
     141                itemTags.remove('S');
     142                itemTagsExt.remove("_el");
     143               
     144                writeTags(toWrite, new Object[] {}, itemTags);
     145                writeTags(toWrite, new Object[] {}, itemTagsExt);
     146        }
     147       
     148        @Override
     149        protected <T> void writeTag(Item toWrite, Object[] param, LinkedHashMap<T, Method> tags, T tag) {
     150                EncryptionDetail encryptionDetail = toWrite.getEncryptionDetailForTag(tag + "");
     151                switch (encryptionDetail) {
     152                case UnencryptedOnSave:
     153                        super.writeTag(toWrite, param, tags, tag);
     154                        break;
     155                case ReencryptOnSave:
     156                        Method toRun = tags.get(tag);
     157                        Class<?> declarer = toRun.getDeclaringClass();
     158                        LabelResult res = Label.resolveKey(toWrite.getEncryptionLabel());
     159                        if (declarer.isAssignableFrom(toWrite.getClass()) && res == LabelResult.SuccessResolveLabelToKey) {
     160                                SecretKey key = new SecretKeySpec(res.key, SymmetricAlgorithm);
     161                                try {
     162                                        Object o = toRun.invoke(toWrite, new Object[] {});
     163                                        o = Conversion.ConvertToExpeditee(toRun, o);
     164                                        if (o != null) {
     165                                                if (o instanceof List) {
     166                                                        for (Object line: (List<?>)o) {
     167                                                                byte[] encryptedBytes = EncryptSymmetric(line.toString().getBytes(), key);
     168                                                                writeLine(tag + "E", Base64.getEncoder().encodeToString(encryptedBytes));
     169                                                        }
     170                                                } else {
     171                                                        byte[] encryptedBytes = EncryptSymmetric(o.toString().getBytes(), key);
     172                                                        writeLine(tag + "E", Base64.getEncoder().encodeToString(encryptedBytes));
     173                                                }
     174                                        }
     175                                } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
     176                                        e.printStackTrace();
     177                                } catch (IOException e) {
     178                                        e.printStackTrace();
    103179                                }
    104180                        }
    105                 }
    106         }
    107        
    108 //      protected static byte[] resolveKeyFromLabel(String label, String framename) {
    109 //              String credentialsFrameName = UserSettings.ProfileName.get() + AuthenticatorBrowser.CREDENTIALS_FRAME;
    110 //              Frame credentialsFrame = FrameIO.LoadFrame(credentialsFrameName);
    111 //              Collection<Text> textItems = credentialsFrame.getTextItems();
    112 //              textItems.removeIf(t -> !t.getText().equals("Secrets"));
    113 //              textItems.removeIf(t -> !t.hasLink());
    114 //              if (textItems.isEmpty()) {
    115 //                      MessageBay.errorMessage("Unable to find label " + label + " to encrypt frame " + framename + ".");
    116 //                      return null;
    117 //              } else {
    118 //                      Text linkToSecretsFrame = textItems.iterator().next();
    119 //                      Frame secretsFrame = FrameIO.LoadFrame(linkToSecretsFrame.getParent().getFramesetName() + linkToSecretsFrame.getLink());
    120 //                      Collection<Text> labels = secretsFrame.getTextItems();
    121 //                      labels.removeIf(lbl -> !lbl.getText().equals(label));
    122 //                      labels.removeIf(lbl -> lbl.getData() == null || lbl.getData().size() == 0);
    123 //                      if (labels.isEmpty()) {
    124 //                              MessageBay.errorMessage("Unable to find label " + label + " to encrypt frame " + framename + ".");
    125 //                              return null;
    126 //                      }
    127 //                     
    128 //                      Text labelItem = labels.iterator().next();
    129 //                      String data = labelItem.getData().get(0);
    130 //                      if (data.contains("{")) {
    131 //                              MessageBay.errorMessage("You only have a fraction of the required key to access " + framename + ".");
    132 //                              return null;
    133 //                      } else {
    134 //                              try {
    135 //                                      return Base64.getDecoder().decode(data);
    136 //                              } catch (IllegalArgumentException e) {
    137 //                                      MessageBay.errorMessage("Unable to create key out of data stored in label " + label + ".");
    138 //                                      return null;
    139 //                              }
    140 //                      }
    141 //              }
    142 //      }
     181                        break;
     182                case UseUndecipheredValueOnSave:
     183                        try {
     184                                writeLine(tag + "E", encryptionDetail.getUndecipheredValue());
     185                        } catch (IOException e) {
     186                                e.printStackTrace();
     187                        }
     188                        break;
     189                }
     190        }
     191       
     192        private void writeItemData(Frame frame) throws IOException {
     193                // write each item in the frame
     194                for (Item i : frame.getItemsToSave()) {
     195                        assert (!(i instanceof Line));
     196                        writeItem(i);
     197                }
     198               
     199                for (final Item i: frame.getBodyItemsWithInsufficientPermissions()) {
     200                        assert (!(i instanceof Line));
     201                        writeItem(i);
     202                }
     203               
     204                writeSurrogateItemsData(frame);
     205        }
     206       
     207        private void writeSurrogateItemsData(Frame frame) throws IOException {
     208                List<Surrogate> surrogates = new ArrayList<Surrogate>();
     209               
     210                Consumer<? super Item> store = item -> surrogates.addAll(item.getSurrogates());
     211                frame.getItemsToSave().forEach(store);
     212                frame.getBodyItemsWithInsufficientPermissions().forEach(store);
     213               
     214                if (!surrogates.isEmpty()) {
     215                        // If there is some surrogates, write the surrogate
     216                        // terminator, then write out the surrogates.
     217                        writeSurrogateTerminator();
     218                       
     219                        for (Surrogate surrogate: surrogates) {
     220                                String output = surrogate.toString();
     221                                writeLine(output);
     222                        }
     223                }
     224        }
     225
     226        private void writeSurrogateLineData() throws IOException {
     227                List<Surrogate> surrogateLines = new ArrayList<Surrogate>();
     228               
     229                for(Item lineEnd: _lineEnds) {
     230                        List<Line> lines = lineEnd.getLines();
     231                        for (Line line: lines) {
     232                                surrogateLines.addAll(line.getSurrogates());
     233                        }
     234                }
     235               
     236                if (!surrogateLines.isEmpty()) {
     237                        // If there is some surrogates, write the surrogate
     238                        // terminator, then write out the surrogates.
     239                        writeSurrogateTerminator();
     240                       
     241                        for (Surrogate surrogate: surrogateLines) {
     242                                String output = surrogate.toString();
     243                                writeLine(output);
     244                        }
     245                }
     246        }
     247       
     248        private void writeSurrogateTerminator() throws IOException {
     249                writeLine(SURROGATE_TERMINATOR + nl);
     250        }
    143251       
    144252        private static byte[] EncryptSymmetric(byte[] toEncrypt, SecretKey key) {
     
    156264                        return null;
    157265                }
    158         }
     266        }       
    159267}
Note: See TracChangeset for help on using the changeset viewer.