Advertisement
Vermiculus

LC Cipher

Feb 9th, 2012
140
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 7.04 KB | None | 0 0
  1. /**
  2.  * A Generalized Lewis Carroll Cipher
  3.  *
  4.  * @author Sean Allred
  5.  * @version 9 February 2012
  6.  */
  7. public class Cipher {
  8.     private static final int UPPER_CASE_SHIFT = 65;
  9.     private static final int LOWER_CASE_SHIFT = 97;
  10.    
  11.     private static final String ALPHABET = "abcdefghijklmnopqrstuvwxyz";
  12.    
  13.     /**
  14.      * The standard Tabula Recta as provided by Wikipedia
  15.      */
  16.     public static final char[][] stdTabulaRecta = {
  17.         "abcdefghijklmnopqrstuvwxyz".toCharArray(),
  18.         "bcdefghijklmnopqrstuvwxyza".toCharArray(),
  19.         "cdefghijklmnopqrstuvwxyzab".toCharArray(),
  20.         "defghijklmnopqrstuvwxyzabc".toCharArray(),
  21.         "efghijklmnopqrstuvwxyzabcd".toCharArray(),
  22.         "fghijklmnopqrstuvwxyzabcde".toCharArray(),
  23.         "ghijklmnopqrstuvwxyzabcdef".toCharArray(),
  24.         "hijklmnopqrstuvwxyzabcdefg".toCharArray(),
  25.         "ijklmnopqrstuvwxyzabcdefgh".toCharArray(),
  26.         "jklmnopqrstuvwxyzabcdefghi".toCharArray(),
  27.         "klmnopqrstuvwxyzabcdefghij".toCharArray(),
  28.         "lmnopqrstuvwxyzabcdefghijk".toCharArray(),
  29.         "mnopqrstuvwxyzabcdefghijkl".toCharArray(),
  30.         "nopqrstuvwxyzabcdefghijklm".toCharArray(),
  31.         "opqrstuvwxyzabcdefghijklmn".toCharArray(),
  32.         "pqrstuvwxyzabcdefghijklmno".toCharArray(),
  33.         "qrstuvwxyzabcdefghijklmnop".toCharArray(),
  34.         "rstuvwxyzabcdefghijklmnopq".toCharArray(),
  35.         "stuvwxyzabcdefghijklmnopqr".toCharArray(),
  36.         "tuvwxyzabcdefghijklmnopqrs".toCharArray(),
  37.         "uvwxyzabcdefghijklmnopqrsq".toCharArray(),
  38.         "vwxyzabcdefghijklmnopqrsqt".toCharArray(),
  39.         "wxyzabcdefghijklmnopqrsqtu".toCharArray(),
  40.         "xyzabcdefghijklmnopqrsqtuv".toCharArray(),
  41.         "yzabcdefghijklmnopqrsqtuvw".toCharArray(),
  42.         "zabcdefghijklmnopqrsqtuvwx".toCharArray()
  43.     };
  44.    
  45.     /**
  46.      * Expands a string s to have the length l
  47.      * @param s the String to expand
  48.      * @param l the length of the desired String
  49.      * @return s, copied until it has length l
  50.      */
  51.     private static String expand(String s, int l) {
  52.         String ret = new String(s);
  53.        
  54.         while(ret.length() < l) {
  55.             ret += ret;
  56.         }
  57.        
  58.         if(ret.length() > l) {
  59.             ret = ret.substring(0, l);
  60.         }
  61.        
  62.         return ret;
  63.     }
  64.  
  65.     private static String trimToLen(String s, int l) {
  66.         return (new String(s)).substring(0, l);
  67.     }
  68.    
  69.     private static String shorten(String s) {
  70.         String ret = new String();
  71.         String nxt = null;
  72.        
  73.         int len = 0;
  74.        
  75.         for(len = 1; len <= s.length(); len++) {
  76.             ret = s.substring(0, len);
  77.             if(2*len < s.length()) {
  78.                 nxt = s.substring(len, 2*len);
  79.             } else {
  80.                 nxt = s.substring(len);
  81.             }
  82.            
  83.             String t = trimToLen(ret, nxt.length());
  84.            
  85.             if(t.equalsIgnoreCase(nxt)) {
  86.                 return ret;
  87.             }
  88.            
  89.         }
  90.        
  91.         return ret;
  92.     }
  93.    
  94.     /**
  95.      * Gets the position of the first character in a character array
  96.      * @param ca a character array to search
  97.      * @param c the search character
  98.      * @return the index of the search character within the array
  99.      */
  100.     private static int getPos(char[] ca, char c) {
  101.         c = Character.toLowerCase(c);
  102.         for(int i = 0; i < ca.length; i++)
  103.             if(Character.toLowerCase(ca[i]) == c)
  104.                 return i;
  105.         return -1;
  106.     }
  107.  
  108.  
  109.    
  110.     public static String getKey(char[][] tr, String decoded, String encoded) {     
  111.         char[] dec = decoded.toCharArray();
  112.         char[] enc = encoded.toCharArray();
  113.        
  114.         char[] key = new char[decoded.length()];
  115.        
  116.         if(dec.length != enc.length) {
  117.             System.err.println("Dumbass. The decoded and encoded messages must have the same length");
  118.             return null;
  119.         }
  120.        
  121.         for(int i = 0; i < dec.length; i++) {
  122.             if(Character.isLetter(dec[i])) {               
  123.                 key[i] = ALPHABET.charAt(getPos(tr[ALPHABET.indexOf(Character.toLowerCase(dec[i]))],Character.toLowerCase(enc[i])));
  124.             } else {
  125.                 key[i] = dec[i];
  126.             }
  127.         }
  128.        
  129.         StringBuilder ret = new StringBuilder(new String(key));
  130.        
  131.         for(int i = 0; i < ret.length(); i++) {
  132.             if(!Character.isLetter(ret.charAt(i)))
  133.                 ret.deleteCharAt(i--);
  134.         }
  135.        
  136.         return shorten(ret.toString());
  137.     }
  138.    
  139.     /**
  140.      * The Tabula Recta used in this cipher
  141.      */
  142.     private char[][] tabularecta;
  143.    
  144.     /**
  145.      * The keyword this cipher is based upon
  146.      */
  147.     private String keyword;
  148.  
  149.     /**
  150.      * Set the Tabula Recta
  151.      * @param tabularecta
  152.      */
  153.     public void setTabulaRecta(char[][] tabularecta) {
  154.         //TODO: validation sudoku style
  155.         this.tabularecta = tabularecta;
  156.     }
  157.  
  158.  
  159.     /**
  160.      * Gets the keyword for this Cipher
  161.      * @return
  162.      */
  163.     public String getKeyword() {
  164.         return keyword;
  165.     }
  166.  
  167.  
  168.     /**
  169.      * Sets the keyword for this Cipher
  170.      * @param keyword the new keyword
  171.      */
  172.     public void setKeyword(String keyword) {
  173.         for(int i = 0; i < keyword.length(); i++) {
  174.             if(!Character.isLetter(keyword.charAt(i))) {
  175.                 System.err.println("Invalid keyword: letters only");
  176.                 return;
  177.             }
  178.         }
  179.  
  180.         this.keyword = keyword;
  181.     }
  182.  
  183.  
  184.     public Cipher() {
  185.         this.setKeyword("a");
  186.     }
  187.    
  188.  
  189.     public Cipher(String keyword) {
  190.         this.setKeyword(keyword);
  191.         this.setTabulaRecta(stdTabulaRecta);
  192.     }
  193.    
  194.  
  195.     public Cipher(char[][] tabularecta) {
  196.         this.setKeyword("a");
  197.         this.setTabulaRecta(tabularecta);
  198.     }
  199.    
  200.  
  201.     public Cipher(String keyword, char[][] tabularecta) {
  202.         this.setKeyword(keyword);
  203.         this.setTabulaRecta(tabularecta);
  204.     }
  205.    
  206.    
  207.     private static char encodeChar(char[][] tr, char k, char c) {
  208.        
  209.         char ret = c;
  210.        
  211.         k = Character.toUpperCase(k);
  212.        
  213.         if(Character.isUpperCase(c)) {
  214.             ret = Character.toUpperCase(tr[k - UPPER_CASE_SHIFT][c - UPPER_CASE_SHIFT]);
  215.         } else if(Character.isLowerCase(c)) {
  216.             ret = Character.toLowerCase(tr[k - UPPER_CASE_SHIFT][c - LOWER_CASE_SHIFT]);
  217.         }
  218.        
  219.         return ret;
  220.     }
  221.    
  222.     private static char decodeChar(char[][] tr, char k, char c) {
  223.        
  224.         char ret = c;
  225.        
  226.         k = Character.toUpperCase(k);
  227.        
  228.         if(Character.isUpperCase(c)) {
  229.             ret = Character.toUpperCase((char)(getPos(tr[k - UPPER_CASE_SHIFT], c) + UPPER_CASE_SHIFT));
  230.         } else if(Character.isLowerCase(c)) {
  231.             char[] t = tr[k - UPPER_CASE_SHIFT];
  232.             int pos = getPos(t, c);
  233.             ret = Character.toLowerCase((char)(pos + LOWER_CASE_SHIFT));
  234.         }
  235.        
  236.         return ret;
  237.     }
  238.    
  239.     /**
  240.      * Encode a message
  241.      * @param decoded the message to encode
  242.      * @return a encoded message based upon the Tabula Recta and Keyword of this cipher
  243.      */
  244.     public String encode(String decoded) {
  245.         StringBuilder ret = new StringBuilder(decoded);
  246.        
  247.         StringBuilder key = new StringBuilder(expand(this.keyword, decoded.length()));
  248.        
  249.         for(int i = 0; i < ret.length(); i++) {
  250.             char r = ret.charAt(i);
  251.             if(!Character.isLetter(r))
  252.                 key.insert(i, r);
  253.             else {
  254.                 ret.setCharAt(i, encodeChar(this.tabularecta, key.charAt(i), r));
  255.             }
  256.         }
  257.        
  258.         return ret.toString();
  259.     }
  260.    
  261.  
  262.     /**
  263.      * Decode (or reverse-encode) a message
  264.      * @param encoded the message to decode
  265.      * @return a 'decoded' message based upon the Tabula Recta and Keyword of this cipher
  266.      */
  267.     public String decode(String encoded) {
  268.         StringBuilder ret = new StringBuilder(encoded);
  269.        
  270.         StringBuilder key = new StringBuilder(expand(this.keyword, encoded.length()));
  271.        
  272.         for(int i = 0; i < ret.length(); i++) {
  273.             char r = ret.charAt(i);
  274.             if(!Character.isLetter(r))
  275.                 key.insert(i, r);
  276.             else {
  277.                 ret.setCharAt(i, decodeChar(this.tabularecta, key.charAt(i), r));
  278.             }
  279.         }
  280.        
  281.         return ret.toString();
  282.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement