Merge "AAFcli.java -Declare "value" on a separate line"
[aaf/authz.git] / cadi / core / src / main / java / org / onap / aaf / cadi / Symm.java
index fd60b0c..b1ec4ca 100644 (file)
@@ -7,9 +7,9 @@
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -32,6 +32,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.security.SecureRandom;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.Random;
 
 import javax.crypto.CipherInputStream;
@@ -42,38 +43,37 @@ import org.onap.aaf.cadi.config.Config;
 
 /**
  * Key Conversion, primarily "Base64"
- * 
+ *
  * Base64 is required for "Basic Authorization", which is an important part of the overall CADI Package.
- * 
- * Note: This author found that there is not a "standard" library for Base64 conversion within Java.  
- * The source code implementations available elsewhere were surprisingly inefficient, requiring, for 
+ *
+ * Note: This author found that there is not a "standard" library for Base64 conversion within Java.
+ * The source code implementations available elsewhere were surprisingly inefficient, requiring, for
  * instance, multiple string creation, on a transaction pass.  Integrating other packages that might be
- * efficient enough would put undue Jar File Dependencies given this Framework should have none-but-Java 
+ * efficient enough would put undue Jar File Dependencies given this Framework should have none-but-Java
  * dependencies.
- * 
+ *
  * The essential algorithm is good for a symmetrical key system, as Base64 is really just
- * a symmetrical key that everyone knows the values.  
- * 
- * This code is quite fast, taking about .016 ms for encrypting, decrypting and even .08 for key 
- * generation. The speed quality, especially of key generation makes this a candidate for a short term token 
+ * a symmetrical key that everyone knows the values.
+ *
+ * This code is quite fast, taking about .016 ms for encrypting, decrypting and even .08 for key
+ * generation. The speed quality, especially of key generation makes this a candidate for a short term token
  * used for identity.
- * 
- * It may be used to easily avoid placing Clear-Text passwords in configurations, etc. and contains 
- * supporting functions such as 2048 keyfile generation (see keygen).  This keyfile should, of course, 
- * be set to "400" (Unix) and protected as any other mechanism requires. 
- * 
- * However, this algorithm has not been tested against hackers.  Until such a time, utilize more tested
- * packages to protect Data, especially sensitive data at rest (long term). 
- * 
+ *
+ * It may be used to easily avoid placing Clear-Text passwords in configurations, etc. and contains
+ * supporting functions such as 2048 keyfile generation (see keygen).  This keyfile should, of course,
+ * be set to "400" (Unix) and protected as any other mechanism requires.
+ *
+ * AES Encryption is also employed to include standards.
+ *
  * @author Jonathan
  *
  */
 public class Symm {
-    private static final byte[] DOUBLE_EQ = new byte[] {'=','='}; 
+    private static final byte[] DOUBLE_EQ = new byte[] {'=','='};
     public static final String ENC = "enc:";
     private static final Object LOCK = new Object();
     private static final SecureRandom random = new SecureRandom();
-    
+
     public final char[] codeset;
     private final int splitLinesAt;
     private final String encoding;
@@ -82,18 +82,19 @@ public class Symm {
     private byte[] keyBytes = null;
     //Note: AES Encryption is not Thread Safe.  It is Synchronized
     //private AES aes = null;  // only initialized from File, and only if needed for Passwords
-    
+    private String name;
+
     /**
      * This is the standard base64 Key Set.
      * RFC 2045
      */
     public static final Symm base64 = new Symm(
             "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray()
-            ,76, Config.UTF_8,true);
+            ,76, Config.UTF_8,true, "Base64");
 
     public static final Symm base64noSplit = new Symm(
             "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray()
-            ,Integer.MAX_VALUE, Config.UTF_8,true);
+            ,Integer.MAX_VALUE, Config.UTF_8,true, "Base64, no Split");
 
     /**
      * This is the standard base64 set suitable for URLs and Filenames
@@ -101,13 +102,13 @@ public class Symm {
      */
     public static final Symm base64url = new Symm(
             "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".toCharArray()
-            ,76, Config.UTF_8,true);
+            ,76, Config.UTF_8,true, "Base64 for URL");
 
     /**
      * A Password set, using US-ASCII
      * RFC 4648
      */
-    public static final Symm encrypt = new Symm(base64url.codeset,1024, "US-ASCII", false);
+    public static final Symm encrypt = new Symm(base64url.codeset,1024, "US-ASCII", false, "Base64, 1024 size");
     private static final byte[] EMPTY = new byte[0];
 
     /**
@@ -115,36 +116,37 @@ public class Symm {
      * Note, this is too large to fit into the algorithm. Only use with PassGen
      */
     private static char passChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+!@#$%^&*(){}[]?:;,.".toCharArray();
-            
+
 
     private static Symm internalOnly = null;
-    
+
     /**
      * Use this to create special case Case Sets and/or Line breaks
-     * 
+     *
      * If you don't know why you need this, use the Singleton Method
-     * 
+     *
      * @param codeset
      * @param split
      */
-    public Symm(char[] codeset, int split, String charset, boolean useEndEquals) {
+    public Symm(char[] codeset, int split, String charset, boolean useEndEquals, String name) {
         this.codeset = codeset;
         splitLinesAt = split;
         encoding = charset;
         endEquals = useEndEquals;
+        this.name = name;
         char prev = 0, curr=0, first = 0;
         int offset=Integer.SIZE; // something that's out of range for integer array
-        
-        // There can be time efficiencies gained when the underlying keyset consists mainly of ordered 
+
+        // There can be time efficiencies gained when the underlying keyset consists mainly of ordered
         // data (i.e. abcde...).  Therefore, we'll quickly analyze the keyset.  If it proves to have
         // too much entropy, the "Unordered" algorithm, which is faster in such cases is used.
         ArrayList<int[]> la = new ArrayList<>();
-        for(int i=0;i<codeset.length;++i) {
+        for (int i=0;i<codeset.length;++i) {
             curr = codeset[i];
-            if(prev+1==curr) { // is next character in set
+            if (prev+1==curr) { // is next character in set
                 prev = curr;
             } else {
-                if(offset!=Integer.SIZE) { // add previous range 
+                if (offset!=Integer.SIZE) { // add previous range
                     la.add(new int[]{first,prev,offset});
                 }
                 first = prev = curr;
@@ -152,7 +154,7 @@ public class Symm {
             }
         }
         la.add(new int[]{first,curr,offset});
-        if(la.size()>codeset.length/3) {
+        if (la.size()>codeset.length/3) {
             convert = new Unordered(codeset);
         } else { // too random to get speed enhancement from range algorithm
             int[][] range = new int[la.size()][];
@@ -160,11 +162,11 @@ public class Symm {
             convert = new Ordered(range);
         }
     }
-    
+
     public Symm copy(int lines) {
-        return new Symm(codeset,lines,encoding,endEquals);
+        return new Symm(codeset,lines,encoding,endEquals, "Copied " + lines);
     }
-    
+
     // Only used by keygen, which is intentionally randomized. Therefore, always use unordered
     private  Symm(char[] codeset, Symm parent) {
         this.codeset = codeset;
@@ -184,7 +186,7 @@ public class Symm {
     }
 
     /**
-     * Obtain the base64() behavior of this class, for use in standard BASIC AUTH mechanism, etc.  
+     * Obtain the base64() behavior of this class, for use in standard BASIC AUTH mechanism, etc.
      * No Line Splitting
      * @return
      */
@@ -210,17 +212,17 @@ public class Symm {
 
     public <T> T exec(SyncExec<T> exec) throws Exception {
         synchronized(LOCK) {
-            if(keyBytes == null) {
+            if (keyBytes == null) {
                 keyBytes = new byte[AES.AES_KEY_SIZE/8];
                 int offset = (Math.abs(codeset[0])+47)%(codeset.length-keyBytes.length);
-                for(int i=0;i<keyBytes.length;++i) {
+                for (int i=0;i<keyBytes.length;++i) {
                     keyBytes[i] = (byte)codeset[i+offset];
                 }
             }
         }
         return exec.exec(new AES(keyBytes,0,keyBytes.length));
     }
-    
+
     public interface Encryption {
         public CipherOutputStream outputStream(OutputStream os, boolean encrypt);
         public CipherInputStream inputStream(InputStream is, boolean encrypt);
@@ -229,9 +231,9 @@ public class Symm {
     public static interface SyncExec<T> {
         public T exec(Encryption enc) throws IOException, Exception;
     }
-    
+
     public byte[] encode(byte[] toEncrypt) throws IOException {
-            if(toEncrypt==null) {
+            if (toEncrypt==null) {
                 return EMPTY;
             } else {
             ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(toEncrypt.length*1.25));
@@ -249,7 +251,7 @@ public class Symm {
     /**
      *  Helper function for String API of "Encode"
      *  use "getBytes" with appropriate char encoding, etc.
-     *  
+     *
      * @param str
      * @return
      * @throws IOException
@@ -257,7 +259,7 @@ public class Symm {
     public String encode(String str) throws IOException {
         byte[] array;
         boolean useDefaultEncoding = false;
-        try { 
+        try {
             array = str.getBytes(encoding);
         } catch (IOException e) {
             array = str.getBytes(); // take default
@@ -265,14 +267,14 @@ public class Symm {
         }
         // Calculate expected size to avoid any buffer expansion copies within the ByteArrayOutput code
         ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(array.length*1.363)); // account for 4 bytes for 3 and a byte or two more
-        
+
         encode(new ByteArrayInputStream(array),baos);
         if (useDefaultEncoding) {
             return baos.toString();
         }
         return baos.toString(encoding);
     }
-    
+
     /**
      * Helper function for the String API of "Decode"
      * use "getBytes" with appropriate char encoding, etc.
@@ -283,7 +285,7 @@ public class Symm {
     public String decode(String str) throws IOException {
         byte[] array;
         boolean useDefaultEncoding = false;
-        try { 
+        try {
             array = str.getBytes(encoding);
         } catch (IOException e) {
             array = str.getBytes(); // take default
@@ -300,9 +302,9 @@ public class Symm {
 
     /**
      * Convenience Function
-     * 
+     *
      * encode String into InputStream and call encode(InputStream, OutputStream)
-     * 
+     *
      * @param string
      * @param out
      * @throws IOException
@@ -313,9 +315,9 @@ public class Symm {
 
     /**
      * Convenience Function
-     * 
+     *
      * encode String into InputStream and call decode(InputStream, OutputStream)
-     * 
+     *
      * @param string
      * @param out
      * @throws IOException
@@ -329,23 +331,23 @@ public class Symm {
         encode(is,os);
     }
 
-    /** 
+    /**
      * encode InputStream onto Output Stream
-     * 
+     *
      * @param is
      * @param estimate
      * @return
      * @throws IOException
      */
     public void encode(InputStream is, OutputStream os) throws IOException {
-        // StringBuilder sb = new StringBuilder((int)(estimate*1.255)); // try to get the right size of StringBuilder from start.. slightly more than 1.25 times 
+        // StringBuilder sb = new StringBuilder((int)(estimate*1.255)); // try to get the right size of StringBuilder from start.. slightly more than 1.25 times
         int prev=0;
         int read, idx=0, line=0;
         boolean go;
         do {
             read = is.read();
-            if(go = read>=0) {
-                if(line>=splitLinesAt) {
+            if (go = read>=0) {
+                if (line>=splitLinesAt) {
                     os.write('\n');
                     line = 0;
                 }
@@ -358,11 +360,11 @@ public class Symm {
                         os.write(codeset[((prev & 0x03)<<4) | (read>>4)]);
                         prev = read;
                         break;
-                    default: //(3+) 
+                    default: //(3+)
                             // Char 1 is last 4 bits of prev plus the first 2 bits of read
                             // Char 2 is the last 6 bits of read
                         os.write(codeset[(((prev & 0xF)<<2) | (read>>6))]);
-                        if(line==splitLinesAt) { // deal with line splitting for two characters
+                        if (line==splitLinesAt) { // deal with line splitting for two characters
                             os.write('\n');
                             line=0;
                         }
@@ -376,21 +378,21 @@ public class Symm {
                 switch(idx) {
                     case 1: // just the last 2 bits of prev
                         os.write(codeset[(prev & 0x03)<<4]);
-                        if(endEquals)os.write(DOUBLE_EQ);
+                        if (endEquals)os.write(DOUBLE_EQ);
                         break;
                     case 2: // just the last 4 bits of prev
                         os.write(codeset[(prev & 0xF)<<2]);
-                        if(endEquals)os.write('=');
+                        if (endEquals)os.write('=');
                         break;
                 }
                 idx = 0;
             }
-            
-        } while(go);
+
+        } while (go);
     }
 
     public void decode(InputStream is, OutputStream os, int skip) throws IOException {
-        if(is.skip(skip)!=skip) {
+        if (is.skip(skip)!=skip) {
             throw new IOException("Error skipping on IOStream in Symm");
         }
         decode(is,os);
@@ -405,12 +407,12 @@ public class Symm {
     public void decode(InputStream is, OutputStream os) throws IOException {
        int read, idx=0;
        int prev=0, index;
-           while((read = is.read())>=0) {
+           while ((read = is.read())>=0) {
                index = convert.convert(read);
-               if(index>=0) {
+               if (index>=0) {
                 switch(++idx) { // 1 based cases, slightly faster ++
                     case 1: // index goes into first 6 bits of prev
-                        prev = index<<2; 
+                        prev = index<<2;
                         break;
                     case 2: // write second 2 bits of into prev, write byte, last 4 bits go into prev
                         os.write((byte)(prev|(index>>4)));
@@ -428,7 +430,7 @@ public class Symm {
            };
            os.flush();
    }
-   
+
    /**
     * Interface to allow this class to choose which algorithm to find index of character in Key
     * @author Jonathan
@@ -452,22 +454,22 @@ public class Symm {
        public int convert(int read) throws IOException {
            // System.out.print((char)read);
            switch(read) {
-               case -1: 
+               case -1:
                case '=':
                case ' ':
                case '\n':
                case '\r':
                    return -1;
            }
-           for(int i=0;i<range.length;++i) {
-               if(read >= range[i][0] && read<=range[i][1]) {
+           for (int i=0;i<range.length;++i) {
+               if (read >= range[i][0] && read<=range[i][1]) {
                    return read-range[i][2];
                }
            }
            throw new IOException("Unacceptable Character in Stream");
        }
    }
-   
+
    /**
     * Unordered, i.e. the key is purposely randomized, simply has to investigate each character
     * until we find a match.
@@ -481,14 +483,14 @@ public class Symm {
        }
        public int convert(int read) throws IOException {
            switch(read) {
-               case -1: 
+               case -1:
                case '=':
                  case '\n':
                  case '\r':
                    return -1;
            }
-           for(int i=0;i<codec.length;++i) {
-               if(codec[i]==read)return i;
+           for (int i=0;i<codec.length;++i) {
+               if (codec[i]==read)return i;
            }
           // don't give clue in Encryption mode
           throw new IOException("Unacceptable Character in Stream");
@@ -497,7 +499,7 @@ public class Symm {
 
    /**
     * Generate a 2048 based Key from which we extract our code base
-    * 
+    *
     * @return
     * @throws IOException
     */
@@ -508,7 +510,7 @@ public class Symm {
         base64url.encode(new ByteArrayInputStream(inkey), baos);
         return baos.toByteArray();
    }
-   
+
    // A class allowing us to be less predictable about significant digits (i.e. not picking them up from the
    // beginning, and not picking them up in an ordered row.  Gives a nice 2048 with no visible patterns.
    private class Obtain {
@@ -516,33 +518,33 @@ public class Symm {
        private int skip;
        private int length;
        private byte[] key;
-  
+
        private Obtain(Symm b64, byte[] key) {
            skip = Math.abs(key[key.length-13]%key.length);
-           if((key.length&0x1) == (skip&0x1)) { // if both are odd or both are even
+           if ((key.length&0x1) == (skip&0x1)) { // if both are odd or both are even
                ++skip;
            }
            length = b64.codeset.length;
            last = 17+length%59; // never start at beginning
            this.key = key;
        }
-       
+
        private int next() {
              return Math.abs(key[(++last*skip)%key.length])%length;
        }
    };
-  
+
    /**
     * Obtain a Symm from "keyfile" (Config.KEYFILE) property
-    * 
+    *
     * @param acesss
     * @return
- * @throws IOException 
- * @throws CadiException 
+ * @throws IOException
+ * @throws CadiException
     */
    public static Symm obtain(Access access) throws CadiException {
         String keyfile = access.getProperty(Config.CADI_KEYFILE,null);
-        if(keyfile!=null) {
+        if (keyfile!=null) {
             Symm symm = Symm.baseCrypt();
 
             File file = new File(keyfile);
@@ -551,7 +553,7 @@ public class Symm {
             } catch (IOException e1) {
                 access.log(Level.INIT, Config.CADI_KEYFILE,"points to",file.getAbsolutePath());
             }
-            if(file.exists()) {
+            if (file.exists()) {
                 try {
                     FileInputStream fis = new FileInputStream(file);
                     try {
@@ -584,28 +586,32 @@ public class Symm {
         }
    }
   /**
-   *  Create a new random key 
+   *  Create a new random key
    */
   public Symm obtain() throws IOException {
         byte inkey[] = new byte[0x800];
         new SecureRandom().nextBytes(inkey);
-        return obtain(inkey);
+        Symm s = obtain(inkey);
+        s.name = "from Random";
+        return s;
   }
-  
+
   /**
    * Obtain a Symm from 2048 key from a String
-   * 
+   *
    * @param key
    * @return
    * @throws IOException
    */
   public static Symm obtain(String key) throws IOException {
-      return obtain(new ByteArrayInputStream(key.getBytes()));
+      Symm s = obtain(new ByteArrayInputStream(key.getBytes()));
+      s.name = "from String";
+      return s;
   }
-  
+
   /**
    * Obtain a Symm from 2048 key from a Stream
-   * 
+   *
    * @param is
    * @return
    * @throws IOException
@@ -619,15 +625,17 @@ public class Symm {
           throw new IOException("Invalid Key");
       }
       byte[] bkey = baos.toByteArray();
-      if(bkey.length<0x88) { // 2048 bit key
+      if (bkey.length<0x88) { // 2048 bit key
           throw new IOException("Invalid key");
       }
-      return baseCrypt().obtain(bkey);
+      Symm s = baseCrypt().obtain(bkey);
+      s.name = "from InputStream";
+      return s;
   }
 
   /**
    * Convenience for picking up Keyfile
-   * 
+   *
    * @param f
    * @return
    * @throws IOException
@@ -635,7 +643,9 @@ public class Symm {
   public static Symm obtain(File f) throws IOException {
       FileInputStream fis = new FileInputStream(f);
       try {
-          return obtain(fis);
+          Symm s = obtain(fis);
+          s.name = "From " + f.getCanonicalPath() + " dated " + new Date(f.lastModified());
+          return s;
       } finally {
           fis.close();
       }
@@ -644,7 +654,7 @@ public class Symm {
    * Decrypt into a String
    *
    *  Convenience method
-   * 
+   *
    * @param password
    * @return
    * @throws IOException
@@ -657,50 +667,50 @@ public class Symm {
 
   /**
    * Create an encrypted password, making sure that even short passwords have a minimum length.
-   * 
+   *
    * @param password
    * @param os
    * @throws IOException
    */
   public void enpass(final String password, final OutputStream os) throws IOException {
-        if(password==null) {
+        if (password==null) {
             throw new IOException("Invalid password passed");
         }
         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
         DataOutputStream dos = new DataOutputStream(baos);
         byte[] bytes = password.getBytes();
-        if(this.getClass().getSimpleName().startsWith("base64")) { // don't expose randomization
+        if (this.getClass().getSimpleName().startsWith("base64")) { // don't expose randomization
             dos.write(bytes);
         } else {
-            
+
             Random r = new SecureRandom();
             int start = 0;
             byte b;
-            for(int i=0;i<3;++i) {
+            for (int i=0;i<3;++i) {
                 dos.writeByte(b=(byte)r.nextInt());
                 start+=Math.abs(b);
             }
             start%=0x7;
-            for(int i=0;i<start;++i) {
+            for (int i=0;i<start;++i) {
                 dos.writeByte(r.nextInt());
             }
             dos.writeInt((int)System.currentTimeMillis());
             int minlength = Math.min(0x9,bytes.length);
             dos.writeByte(minlength); // expect truncation
-            if(bytes.length<0x9) {
-                for(int i=0;i<bytes.length;++i) {
+            if (bytes.length<0x9) {
+                for (int i=0;i<bytes.length;++i) {
                     dos.writeByte(r.nextInt());
                     dos.writeByte(bytes[i]);
                 }
                 // make sure it's long enough
-                for(int i=bytes.length;i<0x9;++i) {
+                for (int i=bytes.length;i<0x9;++i) {
                     dos.writeByte(r.nextInt());
                 }
             } else {
                 dos.write(bytes);
             }
         }
-        
+
         // 7/21/2016 Jonathan add AES Encryption to the mix
         try {
             exec(new SyncExec<Void>() {
@@ -725,25 +735,25 @@ public class Symm {
 
   /**
    * Decrypt a password into a String
-   * 
+   *
    * Convenience method
-   * 
+   *
    * @param password
    * @return
    * @throws IOException
    */
   public String depass(String password) throws IOException {
-      if(password==null)return null;
+      if (password==null)return null;
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
       depass(password,baos);
       return new String(baos.toByteArray());
   }
-  
+
   /**
    * Decrypt a password
-   * 
+   *
    * Skip Symm.ENC
-   * 
+   *
    * @param password
    * @param os
    * @return
@@ -772,28 +782,28 @@ public class Symm {
       byte[] bytes = baos.toByteArray();
       DataInputStream dis = new DataInputStream(new ByteArrayInputStream(bytes));
       long time;
-      if(this.getClass().getSimpleName().startsWith("base64")) { // don't expose randomization
+      if (this.getClass().getSimpleName().startsWith("base64")) { // don't expose randomization
           os.write(bytes);
           time = 0L;
       } else {
           int start=0;
-          for(int i=0;i<3;++i) {
+          for (int i=0;i<3;++i) {
               start+=Math.abs(dis.readByte());
           }
           start%=0x7;
-          for(int i=0;i<start;++i) {
+          for (int i=0;i<start;++i) {
               dis.readByte();
           }
           time = (dis.readInt() & 0xFFFF)|(System.currentTimeMillis()&0xFFFF0000);
           int minlength = dis.readByte();
-          if(minlength<0x9){
+          if (minlength<0x9){
             DataOutputStream dos = new DataOutputStream(os);
-            for(int i=0;i<minlength;++i) {
+            for (int i=0;i<minlength;++i) {
                 dis.readByte();
                 dos.writeByte(dis.readByte());
             }
           } else {
-              int pre =((Byte.SIZE*3+Integer.SIZE+Byte.SIZE)/Byte.SIZE)+start; 
+              int pre =((Byte.SIZE*3+Integer.SIZE+Byte.SIZE)/Byte.SIZE)+start;
               os.write(bytes, pre, bytes.length-pre);
           }
       }
@@ -801,24 +811,24 @@ public class Symm {
   }
 
   public static String randomGen(int numBytes) {
-      return randomGen(passChars,numBytes);  
+      return randomGen(passChars,numBytes);
   }
-  
+
   public static String randomGen(char[] chars ,int numBytes) {
         int rint;
         StringBuilder sb = new StringBuilder(numBytes);
-        for(int i=0;i<numBytes;++i) {
+        for (int i=0;i<numBytes;++i) {
             rint = random.nextInt(chars.length);
             sb.append(chars[rint]);
         }
         return sb.toString();
   }
   // Internal mechanism for helping to randomize placement of characters within a Symm codeset
-  // Based on an incoming data stream (originally created randomly, but can be recreated within 
+  // Based on an incoming data stream (originally created randomly, but can be recreated within
   // 2048 key), go after a particular place in the new codeset.  If that codeset spot is used, then move
-  // right or left (depending on iteration) to find the next available slot.  In this way, key generation 
+  // right or left (depending on iteration) to find the next available slot.  In this way, key generation
   // is speeded up by only enacting N iterations, but adds a spreading effect of the random number stream, so that keyset is also
-  // shuffled for a good spread. It is, however, repeatable, given the same number set, allowing for 
+  // shuffled for a good spread. It is, however, repeatable, given the same number set, allowing for
   // quick recreation when the official stream is actually obtained.
   public Symm obtain(byte[] key) throws IOException {
       int filled = codeset.length;
@@ -829,14 +839,14 @@ public class Symm {
       int index;
       Obtain o = new Obtain(this,key);
 
-      while(filled>=0) {
+      while (filled>=0) {
           index = o.next();
-          if(index<0 || index>=codeset.length) {
+          if (index<0 || index>=codeset.length) {
               System.out.println("uh, oh");
           }
-          if(right) { // alternate going left or right to find the next open slot (keeps it from taking too long to hit something) 
-              for(int j=index;j<end;++j) {
-                  if(seq[j]==0) {
+          if (right) { // alternate going left or right to find the next open slot (keeps it from taking too long to hit something)
+              for (int j=index;j<end;++j) {
+                  if (seq[j]==0) {
                       seq[j]=codeset[filled];
                       --filled;
                       break;
@@ -844,8 +854,8 @@ public class Symm {
               }
               right = false;
           } else {
-              for(int j=index;j>=0;--j) {
-                  if(seq[j]==0) {
+              for (int j=index;j>=0;--j) {
+                  if (seq[j]==0) {
                       seq[j]=codeset[filled];
                       --filled;
                       break;
@@ -855,11 +865,12 @@ public class Symm {
           }
       }
       Symm newSymm = new Symm(seq,this);
+      newSymm.name = "from bytes";
       // Set the KeyBytes
       try {
           newSymm.keyBytes = new byte[AES.AES_KEY_SIZE/8];
           int offset = (Math.abs(key[(47%key.length)])+137)%(key.length-newSymm.keyBytes.length);
-          for(int i=0;i<newSymm.keyBytes.length;++i) {
+          for (int i=0;i<newSymm.keyBytes.length;++i) {
               newSymm.keyBytes[i] = key[i+offset];
           }
       } catch (Exception e) {
@@ -868,15 +879,15 @@ public class Symm {
 
       return newSymm;
   }
-  
-  /** 
+
+  /**
    * This Symm is generated for internal JVM use.  It has no external keyfile, but can be used
    * for securing Memory, as it remains the same ONLY of the current JVM
    * @return
- * @throws IOException 
+ * @throws IOException
    */
   public static synchronized Symm internalOnly() throws IOException {
-      if(internalOnly==null) {
+      if (internalOnly==null) {
           ByteArrayInputStream baos = new ByteArrayInputStream(keygen());
           try {
               internalOnly = Symm.obtain(baos);
@@ -886,4 +897,9 @@ public class Symm {
       }
       return internalOnly;
   }
+
+  @Override
+  public String toString() {
+      return name;
+  }
 }