Remove Code from cadi, it is now in authz
[aaf/cadi.git] / core / src / main / java / org / onap / aaf / cadi / Symm.java
diff --git a/core/src/main/java/org/onap/aaf/cadi/Symm.java b/core/src/main/java/org/onap/aaf/cadi/Symm.java
deleted file mode 100644 (file)
index beb0c40..0000000
+++ /dev/null
@@ -1,811 +0,0 @@
-/*******************************************************************************\r
- * ============LICENSE_START====================================================\r
- * * org.onap.aaf\r
- * * ===========================================================================\r
- * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
- * * ===========================================================================\r
- * * Licensed under the Apache License, Version 2.0 (the "License");\r
- * * you may not use this file except in compliance with the License.\r
- * * You may obtain a copy of the License at\r
- * * \r
- *  *      http://www.apache.org/licenses/LICENSE-2.0\r
- * * \r
- *  * Unless required by applicable law or agreed to in writing, software\r
- * * distributed under the License is distributed on an "AS IS" BASIS,\r
- * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * * See the License for the specific language governing permissions and\r
- * * limitations under the License.\r
- * * ============LICENSE_END====================================================\r
- * *\r
- * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
- * *\r
- ******************************************************************************/\r
-package org.onap.aaf.cadi;\r
-\r
-import java.io.ByteArrayInputStream;\r
-import java.io.ByteArrayOutputStream;\r
-import java.io.DataInputStream;\r
-import java.io.DataOutputStream;\r
-import java.io.File;\r
-import java.io.FileInputStream;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-import java.io.OutputStream;\r
-import java.security.SecureRandom;\r
-import java.util.ArrayList;\r
-import java.util.Random;\r
-\r
-import javax.crypto.CipherInputStream;\r
-import javax.crypto.CipherOutputStream;\r
-\r
-import org.onap.aaf.cadi.Access.Level;\r
-import org.onap.aaf.cadi.config.Config;\r
-\r
-/**\r
- * Key Conversion, primarily "Base64"\r
- * \r
- * Base64 is required for "Basic Authorization", which is an important part of the overall CADI Package.\r
- * \r
- * Note: This author found that there is not a "standard" library for Base64 conversion within Java.  \r
- * The source code implementations available elsewhere were surprisingly inefficient, requiring, for \r
- * instance, multiple string creation, on a transaction pass.  Integrating other packages that might be\r
- * efficient enough would put undue Jar File Dependencies given this Framework should have none-but-Java \r
- * dependencies.\r
- * \r
- * The essential algorithm is good for a symmetrical key system, as Base64 is really just\r
- * a symmetrical key that everyone knows the values.  \r
- * \r
- * This code is quite fast, taking about .016 ms for encrypting, decrypting and even .08 for key \r
- * generation. The speed quality, especially of key generation makes this a candidate for a short term token \r
- * used for identity.\r
- * \r
- * It may be used to easily avoid placing Clear-Text passwords in configurations, etc. and contains \r
- * supporting functions such as 2048 keyfile generation (see keygen).  This keyfile should, of course, \r
- * be set to "400" (Unix) and protected as any other mechanism requires. \r
- * \r
- * However, this algorithm has not been tested against hackers.  Until such a time, utilize more tested\r
- * packages to protect Data, especially sensitive data at rest (long term). \r
- *\r
- */\r
-public class Symm {\r
-       private static final byte[] DOUBLE_EQ = new byte[] {'=','='}; \r
-       public static final String ENC = "enc:";\r
-       private static final SecureRandom random = new SecureRandom();\r
-       \r
-       public final char[] codeset;\r
-       private final int splitLinesAt;\r
-       private final String encoding;\r
-       private final Convert convert;\r
-       private final boolean endEquals;\r
-       //Note: AES Encryption is not Thread Safe.  It is Synchronized\r
-       private static AES aes = null;  // only initialized from File, and only if needed for Passwords\r
-       \r
-       /**\r
-        * This is the standard base64 Key Set.\r
-        * RFC 2045\r
-        */\r
-       public static final Symm base64 = new Symm(\r
-                       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray()\r
-                       ,76, Config.UTF_8,true);\r
-\r
-       public static final Symm base64noSplit = new Symm(\r
-                       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray()\r
-                       ,Integer.MAX_VALUE, Config.UTF_8,true);\r
-\r
-       /**\r
-        * This is the standard base64 set suitable for URLs and Filenames\r
-        * RFC 4648\r
-        */\r
-       public static final Symm base64url = new Symm(\r
-                       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".toCharArray()\r
-                       ,76, Config.UTF_8,true);\r
-\r
-       /**\r
-        * A Password set, using US-ASCII\r
-        * RFC 4648\r
-        */\r
-       public static final Symm encrypt = new Symm(base64url.codeset,1024, "US-ASCII", false);\r
-\r
-       /**\r
-        * A typical set of Password Chars\r
-        * Note, this is too large to fit into the algorithm. Only use with PassGen\r
-        */\r
-       private static char passChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+!@#$%^&*(){}[]?:;,.".toCharArray();\r
-                       \r
-\r
-\r
-       /**\r
-        * Use this to create special case Case Sets and/or Line breaks\r
-        * \r
-        * If you don't know why you need this, use the Singleton Method\r
-        * \r
-        * @param codeset\r
-        * @param split\r
-        */\r
-       public Symm(char[] codeset, int split, String charset, boolean useEndEquals) {\r
-               this.codeset = codeset;\r
-               splitLinesAt = split;\r
-               encoding = charset;\r
-               endEquals = useEndEquals;\r
-               char prev = 0, curr=0, first = 0;\r
-               int offset=Integer.SIZE; // something that's out of range for integer array\r
-               \r
-               // There can be time efficiencies gained when the underlying keyset consists mainly of ordered \r
-               // data (i.e. abcde...).  Therefore, we'll quickly analyze the keyset.  If it proves to have\r
-               // too much entropy, the "Unordered" algorithm, which is faster in such cases is used.\r
-               ArrayList<int[]> la = new ArrayList<int[]>();\r
-               for(int i=0;i<codeset.length;++i) {\r
-                       curr = codeset[i];\r
-                       if(prev+1==curr) { // is next character in set\r
-                               prev = curr;\r
-                       } else {\r
-                               if(offset!=Integer.SIZE) { // add previous range \r
-                                       la.add(new int[]{first,prev,offset});\r
-                               }\r
-                               first = prev = curr;\r
-                               offset = curr-i;\r
-                       }\r
-               }\r
-               la.add(new int[]{first,curr,offset});\r
-               if(la.size()>codeset.length/3) {\r
-                       convert = new Unordered(codeset);\r
-               } else { // too random to get speed enhancement from range algorithm\r
-                       int[][] range = new int[la.size()][];\r
-                       la.toArray(range);\r
-                       convert = new Ordered(range);\r
-               }\r
-       }\r
-       \r
-       public Symm copy(int lines) {\r
-               return new Symm(codeset,lines,encoding,endEquals);\r
-       }\r
-       \r
-       // Only used by keygen, which is intentionally randomized. Therefore, always use unordered\r
-       private  Symm(char[] codeset, Symm parent) {\r
-               this.codeset = codeset;\r
-               splitLinesAt = parent.splitLinesAt;\r
-               endEquals = parent.endEquals;\r
-               encoding = parent.encoding;\r
-               convert = new Unordered(codeset);\r
-       }\r
-\r
-       /**\r
-        * Obtain the base64() behavior of this class, for use in standard BASIC AUTH mechanism, etc.\r
-        * @return\r
-        */\r
-       @Deprecated\r
-       public static final Symm base64() {\r
-               return base64;\r
-       }\r
-\r
-       /**\r
-        * Obtain the base64() behavior of this class, for use in standard BASIC AUTH mechanism, etc.  \r
-        * No Line Splitting\r
-        * @return\r
-        */\r
-       @Deprecated\r
-       public static final Symm base64noSplit() {\r
-               return base64noSplit;\r
-       }\r
-\r
-       /**\r
-        * Obtain the base64 "URL" behavior of this class, for use in File Names, etc. (no "/")\r
-        */\r
-       @Deprecated\r
-       public static final Symm base64url() {\r
-               return base64url;\r
-       }\r
-\r
-       /**\r
-        * Obtain a special ASCII version for Scripting, with base set of base64url use in File Names, etc. (no "/")\r
-        */\r
-       public static final Symm baseCrypt() {\r
-               return encrypt;\r
-       }\r
-\r
-       /*\r
-        *  Note: AES Encryption is NOT thread-safe.  Must surround entire use with synchronized\r
-        */\r
-       private synchronized void exec(AESExec exec) throws IOException {\r
-               if(aes == null) {\r
-                       try {\r
-                               byte[] bytes = new byte[AES.AES_KEY_SIZE/8];\r
-                               int offset = (Math.abs(codeset[0])+47)%(codeset.length-bytes.length);\r
-                               for(int i=0;i<bytes.length;++i) {\r
-                                       bytes[i] = (byte)codeset[i+offset];\r
-                               }\r
-                               aes = new AES(bytes,0,bytes.length);\r
-                       } catch (Exception e) {\r
-                               throw new IOException(e);\r
-                       }\r
-               }\r
-               exec.exec(aes);\r
-       }\r
-       \r
-       private static interface AESExec {\r
-               public void exec(AES aes) throws IOException;\r
-       }\r
-       \r
-    public byte[] encode(byte[] toEncrypt) throws IOException {\r
-               ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(toEncrypt.length*1.25));\r
-               encode(new ByteArrayInputStream(toEncrypt),baos);\r
-               return baos.toByteArray();\r
-       }\r
-\r
-    public byte[] decode(byte[] encrypted) throws IOException {\r
-               ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(encrypted.length*1.25));\r
-               decode(new ByteArrayInputStream(encrypted),baos);\r
-               return baos.toByteArray();\r
-       }\r
-\r
-       /**\r
-     *  Helper function for String API of "Encode"\r
-     *  use "getBytes" with appropriate char encoding, etc.\r
-     *  \r
-     * @param str\r
-     * @return\r
-     * @throws IOException\r
-     */\r
-    public String encode(String str) throws IOException {\r
-       byte[] array;\r
-       try { \r
-               array = str.getBytes(encoding);\r
-       } catch (IOException e) {\r
-               array = str.getBytes(); // take default\r
-       }\r
-       // Calculate expected size to avoid any buffer expansion copies within the ByteArrayOutput code\r
-       ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(array.length*1.363)); // account for 4 bytes for 3 and a byte or two more\r
-       \r
-       encode(new ByteArrayInputStream(array),baos);\r
-       return baos.toString(encoding);\r
-    }\r
-    \r
-    /**\r
-     * Helper function for the String API of "Decode"\r
-     * use "getBytes" with appropriate char encoding, etc.\r
-     * @param str\r
-     * @return\r
-     * @throws IOException\r
-     */\r
-    public String decode(String str) throws IOException {\r
-       byte[] array;\r
-       try { \r
-               array = str.getBytes(encoding);\r
-       } catch (IOException e) {\r
-               array = str.getBytes(); // take default\r
-       }\r
-       // Calculate expected size to avoid any buffer expansion copies within the ByteArrayOutput code\r
-       ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(array.length*.76)); // Decoding is 3 bytes for 4.  Allocate slightly more than 3/4s\r
-       decode(new ByteArrayInputStream(array), baos);\r
-       return baos.toString(encoding);\r
-       }\r
-\r
-       /**\r
-     * Convenience Function\r
-     * \r
-     * encode String into InputStream and call encode(InputStream, OutputStream)\r
-     * \r
-     * @param string\r
-     * @param out\r
-     * @throws IOException\r
-     */\r
-       public void encode(String string, OutputStream out) throws IOException {\r
-               encode(new ByteArrayInputStream(string.getBytes()),out);\r
-       }\r
-\r
-       /**\r
-        * Convenience Function\r
-        * \r
-        * encode String into InputStream and call decode(InputStream, OutputStream)\r
-        * \r
-        * @param string\r
-        * @param out\r
-        * @throws IOException\r
-        */\r
-       public void decode(String string, OutputStream out) throws IOException {\r
-               decode(new ByteArrayInputStream(string.getBytes()),out);\r
-       }\r
-\r
-    public void encode(InputStream is, OutputStream os, byte[] prefix) throws IOException {\r
-       os.write(prefix);\r
-       encode(is,os);\r
-    }\r
-\r
-       /** \r
-     * encode InputStream onto Output Stream\r
-     * \r
-     * @param is\r
-     * @param estimate\r
-     * @return\r
-     * @throws IOException\r
-     */\r
-    public void encode(InputStream is, OutputStream os) throws IOException {\r
-       // StringBuilder sb = new StringBuilder((int)(estimate*1.255)); // try to get the right size of StringBuilder from start.. slightly more than 1.25 times \r
-       int prev=0;\r
-       int read, idx=0, line=0;\r
-       boolean go;\r
-       do {\r
-               read = is.read();\r
-               if(go = read>=0) {\r
-                       if(line>=splitLinesAt) {\r
-                               os.write('\n');\r
-                               line = 0;\r
-                       }\r
-                       switch(++idx) { // 1 based reading, slightly faster ++\r
-                               case 1: // ptr is the first 6 bits of read\r
-                                       os.write(codeset[read>>2]);\r
-                                       prev = read;\r
-                                       break;\r
-                               case 2: // ptr is the last 2 bits of prev followed by the first 4 bits of read\r
-                                       os.write(codeset[((prev & 0x03)<<4) | (read>>4)]);\r
-                                       prev = read;\r
-                                       break;\r
-                               default: //(3+) \r
-                                               // Char 1 is last 4 bits of prev plus the first 2 bits of read\r
-                                           // Char 2 is the last 6 bits of read\r
-                                       os.write(codeset[(((prev & 0xF)<<2) | (read>>6))]);\r
-                                       if(line==splitLinesAt) { // deal with line splitting for two characters\r
-                                               os.write('\n');\r
-                                               line=0;\r
-                                       }\r
-                                       os.write(codeset[(read & 0x3F)]);\r
-                                       ++line;\r
-                                       idx = 0;\r
-                                       prev = 0;\r
-                       }\r
-                       ++line;\r
-               } else { // deal with any remaining bits from Prev, then pad\r
-                       switch(idx) {\r
-                               case 1: // just the last 2 bits of prev\r
-                                       os.write(codeset[(prev & 0x03)<<4]);\r
-                                       if(endEquals)os.write(DOUBLE_EQ);\r
-                                       break;\r
-                               case 2: // just the last 4 bits of prev\r
-                                       os.write(codeset[(prev & 0xF)<<2]);\r
-                                       if(endEquals)os.write('=');\r
-                                       break;\r
-                       }\r
-                       idx = 0;\r
-               }\r
-               \r
-       } while(go);\r
-    }\r
-\r
-    public void decode(InputStream is, OutputStream os, int skip) throws IOException {\r
-       is.skip(skip);\r
-       decode(is,os);\r
-    }\r
-\r
-    /**\r
-        * Decode InputStream onto OutputStream\r
-        * @param is\r
-        * @param os\r
-        * @throws IOException\r
-        */\r
-    public void decode(InputStream is, OutputStream os) throws IOException {\r
-          int read, idx=0;\r
-          int prev=0, index;\r
-               while((read = is.read())>=0) {\r
-                       index = convert.convert(read);\r
-                       if(index>=0) {\r
-                       switch(++idx) { // 1 based cases, slightly faster ++\r
-                               case 1: // index goes into first 6 bits of prev\r
-                                       prev = index<<2; \r
-                                       break;\r
-                               case 2: // write second 2 bits of into prev, write byte, last 4 bits go into prev\r
-                                       os.write((byte)(prev|(index>>4)));\r
-                                       prev = index<<4;\r
-                                       break;\r
-                               case 3: // first 4 bits of index goes into prev, write byte, last 2 bits go into prev\r
-                                       os.write((byte)(prev|(index>>2)));\r
-                                       prev = index<<6;\r
-                                       break;\r
-                               default: // (3+) | prev and last six of index\r
-                                       os.write((byte)(prev|(index&0x3F)));\r
-                                       idx = prev = 0;\r
-                       }\r
-                       }\r
-               };\r
-               os.flush();\r
-   }\r
-   \r
-   /**\r
-    * Interface to allow this class to choose which algorithm to find index of character in Key\r
-    *\r
-    */\r
-   private interface Convert {\r
-          public int convert(int read) throws IOException;\r
-   }\r
-\r
-   /**\r
-    * Ordered uses a range of orders to compare against, rather than requiring the investigation\r
-    * of every character needed.\r
-    *\r
-    */\r
-   private static final class Ordered implements Convert {\r
-          private int[][] range;\r
-          public Ordered(int[][] range) {\r
-                  this.range = range;\r
-          }\r
-          public int convert(int read) throws IOException {\r
-                  switch(read) {\r
-                          case -1: \r
-                          case '=':\r
-                          case '\n': \r
-                                  return -1;\r
-                  }\r
-                  for(int i=0;i<range.length;++i) {\r
-                          if(read >= range[i][0] && read<=range[i][1]) {\r
-                                  return read-range[i][2];\r
-                          }\r
-                  }\r
-                  throw new IOException("Unacceptable Character in Stream");\r
-          }\r
-   }\r
-   \r
-   /**\r
-    * Unordered, i.e. the key is purposely randomized, simply has to investigate each character\r
-    * until we find a match.\r
-    *\r
-    */\r
-   private static final class Unordered implements Convert {\r
-          private char[] codec;\r
-          public Unordered(char[] codec) {\r
-                  this.codec = codec;\r
-          }\r
-          public int convert(int read) throws IOException {\r
-                  switch(read) {\r
-                          case -1: \r
-                          case '=':\r
-                          case '\n': \r
-                                  return -1;\r
-                  }\r
-                  for(int i=0;i<codec.length;++i) {\r
-                          if(codec[i]==read)return i;\r
-                  }\r
-                 // don't give clue in Encryption mode\r
-                 throw new IOException("Unacceptable Character in Stream");\r
-          }\r
-   }\r
-\r
-   /**\r
-    * Generate a 2048 based Key from which we extract our code base\r
-    * \r
-    * @return\r
-    * @throws IOException\r
-    */\r
-   public byte[] keygen() throws IOException {\r
-               byte inkey[] = new byte[0x600];\r
-               new SecureRandom().nextBytes(inkey);\r
-               ByteArrayOutputStream baos = new ByteArrayOutputStream(0x800);\r
-               base64url.encode(new ByteArrayInputStream(inkey), baos);\r
-               return baos.toByteArray();\r
-   }\r
-   \r
-   // A class allowing us to be less predictable about significant digits (i.e. not picking them up from the\r
-   // beginning, and not picking them up in an ordered row.  Gives a nice 2048 with no visible patterns.\r
-   private class Obtain {\r
-          private int last;\r
-          private int skip;\r
-          private int length;\r
-          private byte[] key;\r
-  \r
-          private Obtain(Symm b64, byte[] key) {\r
-                  skip = Math.abs(key[key.length-13]%key.length);\r
-                  if((key.length&0x1) == (skip&0x1)) { // if both are odd or both are even\r
-                          ++skip;\r
-                  }\r
-                  length = b64.codeset.length;\r
-                  last = 17+length%59; // never start at beginning\r
-                  this.key = key;\r
-          }\r
-          \r
-          private int next() {\r
-                  return Math.abs(key[(++last*skip)%key.length])%length;\r
-          }\r
-   };\r
-  \r
-   /**\r
-    * Obtain a Symm from "keyfile" (Config.KEYFILE) property\r
-    * \r
-    * @param acesss\r
-    * @return\r
-    */\r
-   public static Symm obtain(Access access) {\r
-               Symm symm = Symm.baseCrypt();\r
-\r
-               String keyfile = access.getProperty(Config.CADI_KEYFILE,null);\r
-               if(keyfile!=null) {\r
-                       File file = new File(keyfile);\r
-                       try {\r
-                               access.log(Level.INIT, Config.CADI_KEYFILE,"points to",file.getCanonicalPath());\r
-                       } catch (IOException e1) {\r
-                               access.log(Level.INIT, Config.CADI_KEYFILE,"points to",file.getAbsolutePath());\r
-                       }\r
-                       if(file.exists()) {\r
-                               try {\r
-                                       FileInputStream fis = new FileInputStream(file);\r
-                                       try {\r
-                                               symm = Symm.obtain(fis);\r
-                                       } finally {\r
-                                               try {\r
-                                                  fis.close();\r
-                                               } catch (IOException e) {\r
-                                               }\r
-                                       }\r
-                               } catch (IOException e) {\r
-                                       access.log(e, "Cannot load keyfile");\r
-                               }\r
-                       }\r
-               }\r
-               return symm;\r
-   }\r
-  /**\r
-   *  Create a new random key \r
-   */\r
-  public Symm obtain() throws IOException {\r
-               byte inkey[] = new byte[0x800];\r
-               new SecureRandom().nextBytes(inkey);\r
-               return obtain(inkey);\r
-  }\r
-  \r
-  /**\r
-   * Obtain a Symm from 2048 key from a String\r
-   * \r
-   * @param key\r
-   * @return\r
-   * @throws IOException\r
-   */\r
-  public static Symm obtain(String key) throws IOException {\r
-         return obtain(new ByteArrayInputStream(key.getBytes()));\r
-  }\r
-  \r
-  /**\r
-   * Obtain a Symm from 2048 key from a Stream\r
-   * \r
-   * @param is\r
-   * @return\r
-   * @throws IOException\r
-   */\r
-  public static Symm obtain(InputStream is) throws IOException {\r
-         ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
-         try {\r
-                 base64url.decode(is, baos);\r
-         } catch (IOException e) {\r
-                 // don't give clue\r
-                 throw new IOException("Invalid Key");\r
-         }\r
-         byte[] bkey = baos.toByteArray();\r
-         if(bkey.length<0x88) { // 2048 bit key\r
-                 throw new IOException("Invalid key");\r
-         }\r
-         return baseCrypt().obtain(bkey);\r
-  }\r
-\r
-  /**\r
-   * Convenience for picking up Keyfile\r
-   * \r
-   * @param f\r
-   * @return\r
-   * @throws IOException\r
-   */\r
-  public static Symm obtain(File f) throws IOException {\r
-         FileInputStream fis = new FileInputStream(f);\r
-         try {\r
-                 return obtain(fis);\r
-         } finally {\r
-                 fis.close();\r
-         }\r
-  }\r
-  /**\r
-   * Decrypt into a String\r
-   *\r
-   *  Convenience method\r
-   * \r
-   * @param password\r
-   * @return\r
-   * @throws IOException\r
-   */\r
-  public String enpass(String password) throws IOException {\r
-         ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
-         enpass(password,baos);\r
-         return new String(baos.toByteArray());\r
-  }\r
-\r
-  /**\r
-   * Create an encrypted password, making sure that even short passwords have a minimum length.\r
-   * \r
-   * @param password\r
-   * @param os\r
-   * @throws IOException\r
-   */\r
-  public void enpass(final String password, final OutputStream os) throws IOException {\r
-               final ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
-               DataOutputStream dos = new DataOutputStream(baos);\r
-               byte[] bytes = password.getBytes();\r
-               if(this.getClass().getSimpleName().startsWith("base64")) { // don't expose randomization\r
-                       dos.write(bytes);\r
-               } else {\r
-                       \r
-                       Random r = new SecureRandom();\r
-                       int start = 0;\r
-                       byte b;\r
-                       for(int i=0;i<3;++i) {\r
-                               dos.writeByte(b=(byte)r.nextInt());\r
-                               start+=Math.abs(b);\r
-                       }\r
-                       start%=0x7;\r
-                       for(int i=0;i<start;++i) {\r
-                               dos.writeByte(r.nextInt());\r
-                       }\r
-                       dos.writeInt((int)System.currentTimeMillis());\r
-                       int minlength = Math.min(0x9,bytes.length);\r
-                       dos.writeByte(minlength); // expect truncation\r
-                       if(bytes.length<0x9) {\r
-                               for(int i=0;i<bytes.length;++i) {\r
-                                       dos.writeByte(r.nextInt());\r
-                                       dos.writeByte(bytes[i]);\r
-                               }\r
-                               // make sure it's long enough\r
-                               for(int i=bytes.length;i<0x9;++i) {\r
-                                       dos.writeByte(r.nextInt());\r
-                               }\r
-                       } else {\r
-                               dos.write(bytes);\r
-                       }\r
-               }\r
-               \r
-               // 7/21/2016 jg add AES Encryption to the mix\r
-               exec(new AESExec() {\r
-                       @Override\r
-                       public void exec(AES aes) throws IOException {\r
-                               CipherInputStream cis = aes.inputStream(new ByteArrayInputStream(baos.toByteArray()), true);\r
-                               try {\r
-                                       encode(cis,os);\r
-                               } finally {\r
-                                       os.flush();\r
-                                       cis.close();\r
-                               }\r
-                       }\r
-               });\r
-               synchronized(ENC) {\r
-               }\r
-       }\r
-\r
-  /**\r
-   * Decrypt a password into a String\r
-   * \r
-   * Convenience method\r
-   * \r
-   * @param password\r
-   * @return\r
-   * @throws IOException\r
-   */\r
-  public String depass(String password) throws IOException {\r
-         if(password==null)return null;\r
-         ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
-         depass(password,baos);\r
-         return new String(baos.toByteArray());\r
-  }\r
-  \r
-  /**\r
-   * Decrypt a password\r
-   * \r
-   * Skip Symm.ENC\r
-   * \r
-   * @param password\r
-   * @param os\r
-   * @return\r
-   * @throws IOException\r
-   */\r
-  public long depass(final String password, final OutputStream os) throws IOException {\r
-         int offset = password.startsWith(ENC)?4:0;\r
-         final ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
-         final ByteArrayInputStream bais =  new ByteArrayInputStream(password.getBytes(),offset,password.length()-offset);\r
-         exec(new AESExec() {\r
-               @Override\r
-               public void exec(AES aes) throws IOException {\r
-                         CipherOutputStream cos = aes.outputStream(baos, false);\r
-                         decode(bais,cos);\r
-                         cos.close(); // flush\r
-               }\r
-         });\r
-         byte[] bytes = baos.toByteArray();\r
-         DataInputStream dis = new DataInputStream(new ByteArrayInputStream(bytes));\r
-         long time;\r
-         if(this.getClass().getSimpleName().startsWith("base64")) { // don't expose randomization\r
-                 os.write(bytes);\r
-                 time = 0L;\r
-         } else {\r
-                 int start=0;\r
-                 for(int i=0;i<3;++i) {\r
-                         start+=Math.abs(dis.readByte());\r
-                 }\r
-                 start%=0x7;\r
-                 for(int i=0;i<start;++i) {\r
-                         dis.readByte();\r
-                 }\r
-                 time = (dis.readInt() & 0xFFFF)|(System.currentTimeMillis()&0xFFFF0000);\r
-                 int minlength = dis.readByte();\r
-                 if(minlength<0x9){\r
-                       DataOutputStream dos = new DataOutputStream(os);\r
-                       for(int i=0;i<minlength;++i) {\r
-                               dis.readByte();\r
-                               dos.writeByte(dis.readByte());\r
-                       }\r
-                 } else {\r
-                         int pre =((Byte.SIZE*3+Integer.SIZE+Byte.SIZE)/Byte.SIZE)+start; \r
-                         os.write(bytes, pre, bytes.length-pre);\r
-                 }\r
-         }\r
-         return time;\r
-  }\r
-\r
-  public static String randomGen(int numBytes) {\r
-         return randomGen(passChars,numBytes);  \r
-  }\r
-  \r
-  public static String randomGen(char[] chars ,int numBytes) {\r
-           int rint;\r
-           StringBuilder sb = new StringBuilder(numBytes);\r
-           for(int i=0;i<numBytes;++i) {\r
-               rint = random.nextInt(chars.length);\r
-               sb.append(chars[rint]);\r
-           }\r
-           return sb.toString();\r
-  }\r
-  // Internal mechanism for helping to randomize placement of characters within a Symm codeset\r
-  // Based on an incoming data stream (originally created randomly, but can be recreated within \r
-  // 2048 key), go after a particular place in the new codeset.  If that codeset spot is used, then move\r
-  // right or left (depending on iteration) to find the next available slot.  In this way, key generation \r
-  // is speeded up by only enacting N iterations, but adds a spreading effect of the random number stream, so that keyset is also\r
-  // shuffled for a good spread. It is, however, repeatable, given the same number set, allowing for \r
-  // quick recreation when the official stream is actually obtained.\r
-  public Symm obtain(byte[] key) throws IOException {\r
-         try {\r
-               byte[] bytes = new byte[AES.AES_KEY_SIZE/8];\r
-               int offset = (Math.abs(key[(47%key.length)])+137)%(key.length-bytes.length);\r
-               for(int i=0;i<bytes.length;++i) {\r
-                       bytes[i] = key[i+offset];\r
-               }\r
-\r
-               aes = new AES(bytes,0,bytes.length);\r
-         } catch (Exception e) {\r
-                 throw new IOException(e);\r
-         }\r
-               int filled = codeset.length;\r
-               char[] seq = new char[filled];\r
-               int end = filled--;\r
-               \r
-               boolean right = true;\r
-               int index;\r
-               Obtain o = new Obtain(this,key);\r
-               \r
-               while(filled>=0) {\r
-                       index = o.next();\r
-                       if(index<0 || index>=codeset.length) {\r
-                               System.out.println("uh, oh");\r
-                       }\r
-                       if(right) { // alternate going left or right to find the next open slot (keeps it from taking too long to hit something) \r
-                               for(int j=index;j<end;++j) {\r
-                                       if(seq[j]==0) {\r
-                                               seq[j]=codeset[filled];\r
-                                               --filled;\r
-                                               break;\r
-                                       }\r
-                               }\r
-                               right = false;\r
-                       } else {\r
-                               for(int j=index;j>=0;--j) {\r
-                                       if(seq[j]==0) {\r
-                                               seq[j]=codeset[filled];\r
-                                               --filled;\r
-                                               break;\r
-                                       }\r
-                               }\r
-                               right = true;\r
-                       }\r
-               }\r
-               return new Symm(seq,this);\r
-       }\r
-}\r