Home Caesar Cipher Decryption Tool in Java
Post
Cancel

Caesar Cipher Decryption Tool in Java

One of my university modules tasked me with developing a Caesar cipher decryption tool. The tool had to be able to decrypt any encrypted text without knowing the offset used to encrypt the text. The code is surprisingly short and I am not aware of any other Java examples.  The code was originally developed with a command line interface however I have ported it to run on a tomcat server.

To tool is available here: CCDT and the text file mentioned below is from Practical Cryptography

Quick outline:

What is a Caesar cipher?
A Caesar cipher works by moving the letters in the alphabet by a certain number called the offset. If I encrypt the letter 'A' using an offset of 3 then 'A' becomes 'D'. The rotation loops around the alaphabet so the letter 'Z' would become 'C' with an offset of 3.

Patterns in a language
A language has certain patterns in the writing, for example in English the letter 'E' will appear more often than the letter 'Z' so these pattersn can be used to try and work out the rotation. The program I developed uses a text file called 'quadgrams' which contains a block of four letters with the number of occurances in a piece of text.

Brief description of the program
The program takes in a piece of encrypted text and changes the offset all the way up to 25 and for each offset it passes it to a method that works out the mathematical probability that the piece of text is now English with that offset. To work out the mathematical probability it loads the quadgrams text file into a HashMap and searches the map for quadgrams that appear in the cipered text. It then stores the overall probability for that particular offset, moves to the next offset and repeats, if the probability is higher than the previous offset then this offset and probability is stored. See flow diagram below!

CCDT Flow Chart

Disclaimer:
You can use this code anyway you like but you must provide acknowledgement to Monotok.org/Christopher Hamer. If you have any improvements or questions please comment

This is the main class:

package org.monotok.main;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

/**
 *
 * @author hammer
 */
public class CeaserCipherDecryptionTool
{
    public static void main(String[] args) throws IOException
    {
        CeaserCipherDecryptionTool ccdt = new CeaserCipherDecryptionTool();//Test
        System.out.println("Welcome to the decrypter! Please choose a file to decrypt or enter the text");
        System.out.println("Menu: \nOption 1: Choose File\nOption 2: Enter Text\n");
        Scanner option = new Scanner(System.in);
        if((option.nextInt() == 1))
        {
            System.out.println("Please enter the name of the relative file or full file location:\n");
            Scanner fileLocationScanner = new Scanner(System.in);
            String fileLocation = fileLocationScanner.nextLine();
            File localFile = new File(fileLocation);
            FileIORead getTextFromFile = new FileIORead(localFile);
            String cipherText = getTextFromFile.readMultiLine();
            ccdt.decryptCipher(cipherText);
        }
        else
        {
            System.out.println("Please enter the encrypted text to decrypt:\n");
            Scanner getText = new Scanner(System.in);
            String cipherText = getText.nextLine();
            ccdt.decryptCipher(cipherText);
        }
    }
    public String decryptCipher(String cipherText) throws IOException
    {
            cipherText = cipherText.toUpperCase();
            cipherText = cipherText.replaceAll(" ", "");
            long highestProb = 0;
            int valueOfOffsetHighestProb = 0;
            String valueOfStringDecrypted = null;
            for(int caeserCipherROT = 1; caeserCipherROT < 26; caeserCipherROT++)
            {
                StringBuilder sb=new StringBuilder();
                int offset=caeserCipherROT;
                for(int i=0;i<cipherText.length();i++)
                {
                    char t=cipherText.charAt(i);
                    if(t>='A' && t<='Z')
                    {
                        int t1=t-'A'+offset;
                        t1=t1%26;
                        sb.append((char)(t1+'A'));
                    }
                }
                String cipherTextNew = sb.toString();
                long prob;
                
                prob = calculateProbability(cipherTextNew,caeserCipherROT);
                if(prob> highestProb)
                {
                    valueOfOffsetHighestProb = caeserCipherROT;
                    highestProb = prob;
                    valueOfStringDecrypted = sb.toString();
                }
            }
            
            return ("The probability for this being English is: " + highestProb + " with an offset of: " + 
                    valueOfOffsetHighestProb + " \nThe string decrypted is: \n" + valueOfStringDecrypted);
    }
    public long calculateProbability(String cipherText, int offSet) throws IOException
            {
                String filePath = getClass().getResource("/org/monotok/main/quad.txt").getFile();
                File localFile = new File(filePath);
                FileIORead fr = new FileIORead(localFile);
                Map<String, Long> quadgramHaspMap;
                quadgramHaspMap = fr.readQuadgramsArray();
                List<Long> count = new ArrayList<>();
                int incrementer = 0;
                for (Map.Entry<String, Long> entry : quadgramHaspMap.entrySet()) 
                {
                    String key = entry.getKey();
                        if (cipherText.contains(key)) 
                        {
                            count.add(entry.getValue());

                        }
                }
                long probability = 0;
                for(int i = 0; i < count.size(); i++)
                {
                    probability += count.get(i);
                }
                //System.out.println("Probability is: " + probability + " The offset used: " + offSet);
                return probability;
            }
    
}

The file reader class:

package org.monotok.main;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;

public class FileIORead
{
    String location;
    File file;
    
    public FileIORead(File file)
    {
        this.file = file;
    }
    
    public String readFromFile() throws IOException
    {
        File newReadFile = file;
        
        BufferedReader br = new BufferedReader(new FileReader(newReadFile));
        
        return br.readLine();
    }
    
    public String readMultiLine() throws IOException
    {
        File newReadFile = file;
        StringBuilder sb = new StringBuilder();
        BufferedReader br = new BufferedReader(new FileReader(newReadFile));
        String line;
        
        try
        {
            while ((line = br.readLine()) != null)
            {
                sb.append(line += "\n");
            }
        }catch(IOException e)
        {
            e.printStackTrace();
        }
        br.close();
        return sb.toString();
    }
    public Map readQuadgramsArray() throws IOException
    {
        File newReadFile = file;
        StringBuilder sb = new StringBuilder();
        Scanner s = new Scanner(new BufferedReader(new FileReader(newReadFile)));
        Map<String, Long> quadgramArrayList = new HashMap<String, Long>();
        String[] split;
        while(s.hasNextLine())
        {
            split = s.nextLine().split(" ");
            long countQuadgrams = Long.parseLong(split[1]);
            quadgramArrayList.put(split[0], countQuadgrams);
        }
        
        return quadgramArrayList;
    }
    
    
}

This is the index.jsp file, this is basically the html homepage. Netbeans has a palette to help add elements to the page. Very helpful if you haven't got much experience in html.

<%-- 
    Document   : index
    Created on : 14-Sep-2014, 00:49:02
    Author     : hammer
--%>

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Ceasar Cipher Decryption Tool</title>
    </head>
    <body>
        <h1>Ceasar Cipher Decryption Tool</h1>
        <p>This tool has been written in Java, Servlets and JSP</p>
        <p>Enter some encrypted text in the form below and press decrypt. The result will appear in the bottom box after a short time.</p>
        <p>The code guesses the correct ofset by calculating the probability of the text being English (Seems to work with some other European Languages)</p>
        <form action="${pageContext.request.contextPath}/runBackend" method="post">
        <div> 
            <textarea name="txt_Input" rows="10" cols="80"> </textarea><br>
            <textarea name="txt_Result" rows="10" cols="80" readonly="readonly"> ${result}</textarea><br>
            <input type="submit" value="Decrypt" name="btn_decrypt" />
        </div>
        </form>
<!--        <form action="${pageContext.request.contextPath}/runBackend" method="post" enctype="multipart/form-data">
            <input name="LoadFile" type="file"> <input value="Upload" name="btn_upload" type="submit"> 
        </form>-->
    </body>
</html>

This is the Java servlet that interacts with the index page and uses the other classes.

package org.monotok.main;

import com.oreilly.servlet.MultipartRequest;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author hammer
 */
public class runBackend extends HttpServlet
{
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        CeaserCipherDecryptionTool ccdt = new CeaserCipherDecryptionTool();
        if(request.getParameter("btn_decrypt") != null)
        {
            String result = ccdt.decryptCipher(request.getParameter("txt_Input"));

            request.setAttribute("result", result);
            RequestDispatcher dispatcher = request.getRequestDispatcher("/index.jsp");
            dispatcher.forward(request, response);
        }
    }
}

Explanation of the code will be available soon.

This post is licensed under CC BY 4.0 by the author.

If you have found this site useful, please consider buying me a coffee :)

Proud supporter of the Gnome Foundation

Become a Friend of GNOME

Prevent brute force attacks against ownCloud

Fail2ban Horde Webmail

Comments powered by Disqus.