How to Make an Encryption Program With Processing

by Neo_256 in Circuits > Software

757 Views, 6 Favorites, 0 Comments

How to Make an Encryption Program With Processing

program picture.png
text encryption software (how to use)

Hello everyone

Recently I was reading something about Caesar encryption and wondered how to set up such a shifting series without anyone coming up with the key. When I followed the train of thought further I thought of different variants, of which I would like to deepen the best one in my opinion here.

To follow along in this Instructable you don't need to have any prior knowledge of data encryption. To understand the code as well, some knowledge of Java is quite good.

Supplies

  • Processing (and a device running it)
  • this Instructable

Caesar Encryption

caesar.png

Let's start with the basics. Caesar encryption is one of the oldest and simplest forms of encryption. It takes the alphabet and shifts each letter by a certain number. So if the key is 2, the word "hello" will then be h + 2 = j, e + 2 = g, l + 2 = n, o + 2 = q. Encrypted the word looks like this: "jgnnq".

If you look at this you probably won't come up with the key right away. But already in Caesar's time there were mathematicians who studied the frequency of letters and found useful keys at least for long texts.

Because machines can figure that out very quickly in this day and age, we need a better kind of encryption.

Data Encryption in General

transmission.png

In general, data encryption works by encrypting a file with some algorithm and visually speaking, putting it in a lock. This lock is then sent from the sender to the receiver. The important question now is: How does the key get securely from the sender to the receiver?

For this purpose, each computer has a few "open locks" into which any other computer can put something. This lock is then locked and only the receiver has the key to this lock. So the sender can put something in once and say that the lock should close, but has no access to it afterwards. The receiver has the key stored internally in the computer and thus it is never sent and should not leak out.

Neo_256’s Encryption Idea

encrypted.png
decrypted.png

Admittedly, I didn't implement the locks part quite the same way, as I focused more on the algorithm itself.

So what can be improved? It is important, first of all, that it is not just one number by which you move the letters, but different ones. So you can actually think of any sequence, such as 647282289, and repeat it over and over again. But for me it was still not sure enough. The numbers are random, but I wanted to use another advantage of mathematics. From number theory we know that there are different sets of numbers. Among other things also the number set of the irrational numbers. Irrational numbers are numbers which cannot be represented as a fraction. They have an infinite number of decimal places and no repeating sequence. Pi (3.14) or e (2.72) are such numbers. There are many more of them. I have therefore limited my selection to pi, e, root 2 and root 3. Between these numbers, a sequence of numbers for the encryption is to be chosen with the help of random.

But you can come up with the whole sequence of numbers, if you come across it. So one more step has to be done. For this I thought about starting somewhere in these numbers and proceeding from there. Finding the starting point from the outside is so difficult that I don't think anyone would make the effort.

Perhaps someone is now wondering: How can the whole thing then be decoded again? I have decided in this first version of the encryption program to write the key as a number under the encrypted text and to roll up everything from behind for the decryption, because the last state of the variables as they are used in the code are stored. Of course, this is not very secure. But why it is still useful I will explain in a later step.

Important Lists

By list I mean letters and numbers, which are essential for the calculation.

First of all, the characters that the text may contain are important. I have created my own list for this purpose. When creating it, I made sure not to just take the alphabet as it comes, but I sorted the lowercase letters according to their frequency and put numbers as well as special characters in between. The upper case letters are "only" sorted alphabetically. There are 91 characters in total. The last character is the space bar. All in all, these characters are all allowed:

+e1t"a2o*n3i%h4s&r5l/d6u(c7m)w8y=f9g?p0b^v!k,j.x;q:z-_[]{}=><@#|ABCDEFGHIJKLMNOPQRSTUVWXYZ 

It was also important to me to determine how many decimal places the irrational numbers I use have. For this I chose 40 decimal places which makes a number of 41 digits. This number is the same for all irrational numbers.

How to Do It in Processing

code_picture.png
Background.png

In this step, I would like to go into the most important code passages and comment on the most important in more detail. You can find other information about the code in more detail in step 7.

If you haven't got processing you can download it from here.

import controlP5.*;
import java.io.*;
import java.util.*;

The first thing are the required libraries. The controlP5 library is for the text fields. java.io is responsible for the input and output. and java.util is for the scanner. You can install the comtrolP5 library from here. The others should be preinstalled.

//arrays of irrational numbers
int[] pi = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5, 0, 2, 8, 8, 4, 1, 9, 7, 1};
int[] e = {2, 7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9, 0, 4, 5, 2, 3, 5, 3, 6, 0, 2, 8, 7, 4, 7, 1, 3, 5, 2, 6, 6, 2, 4, 9, 7, 7, 5, 7, 2};
int[] root2 = {1, 4, 1, 4, 2, 1, 3, 5, 6, 2, 3, 7, 3, 0, 9, 5, 0, 4, 8, 8, 0, 1, 6, 8, 8, 7, 2, 4, 2, 0, 9, 6, 9, 8, 0, 7, 8, 5, 6, 9, 6};
int[] root3 = {1, 7, 3, 2, 0, 5, 0, 8, 0, 7, 5, 6, 8, 8, 7, 7, 2, 9, 3, 5, 2, 7, 4, 4, 6, 3, 4, 1, 5, 0, 5, 8, 7, 2, 3, 6, 6, 9, 4, 2, 8};
int randomNumber = int(random(4));

I copied this code here that you can copy the numbers from the irrational number to your own code and that you see that I saved most of these numbers in an array because you can access it easily. randomNumber is picking a random number and this is then the irrational number used to encrypt the messages.

//starting point
inList = int((num/2) * (random(82) / 100));

The last thing I want to point out is the way the starting point is calculated. In the program you can type in a number between 1 and 100. This number is then devided by two because we only have 41 numbers to choose a starting point from. So now is the highest number possible 50, which is still to high. To make the starting point even more random there is a random number created between 1 and 82. I took 82 because 41 is 82% of 50. Now the number is divided by 100 to get a 0. something number which is multiplied to the number typed in.

You still have to add the background as a file to Processing if you're using my code. It's the one above this step. To do this, go to sketch -> add file and select it. It should be called Background.png. Unfortunately I couldn't upload the exported program here because the file type is not supported but you can do it yourself if you go to file and then click on export. I attached the whole processing code below.

You can change how many lines you want to encrypt. Just be careful because the number you choose has to be the number you want to encrypt +1 because you also want to be able to decrypt your text at some point. The line you have to change is:

String[] textE = new String[200];

you can change 200 to what you want. Have fun!

Why It’s Safe From Outsiders

background with lock.png

The encrypted text is relatively safe as long as the person who wants to read the text does not have this encryption and decryption program. There are several criteria that make the program secure in this situation:

  • The numbers of the key are not intuitive and thus the meaning is unknown.
  • It is not clear which irrational number was used for the encryption.
  • The program must be rolled up from the back, which is quite time-consuming, especially if there is a lot in the document.
  • You can't just compare the frequency of the occurring letters and guess the text.
  • I made the list with the letters for the encryption myself and that makes it almost impossible to guess this order.


Code in Detail

Now it's time to get down to business. I will now explain the individual elements of the code piece by piece. I will not go into the code pieces mentioned in step 5.

//preparing the text field
ControlP5 number, encryptionFile, decryptionFile;
String fileE = "abc";
String fileD = "abc";
int num = 99;

In this section I prepare the text field and the "default inputs", which should give an error at least for the two strings and thus make the user select the correct file. For "num" I chose any number between 1 and 100.

//list with letters numbers and other characters
char[] characters = {'+', 'e', '1', 't', '"', 'a', '2', 'o', '*', 'n', '3', 'i', '%', 'h', '4', 's', '&', 'r', '5', 'l', '/', 'd', '6', 'u', '(', 'c', '7', 'm', ')', 'w', '8', 'y', '=', 'f', '9', 'g', '?', 'p', '0', 'b', '^', 'v', '!', 'k', ',', 'j', '.', 'x', ';', 'q', ':', 'z', '-', '_', '[', ']', '{', '}', '=', '>', '<', '@', '#', '|', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' '};
String charactersString = new String(characters);

I have the list with the letters once as char array and once as string.

Regarding the variables defined afterwards, I would like to say that their task should be clear from their name. Thus, not all of them will be dealt with.

So now we come to the setup() part.

  //create a window
  size(1200, 800);
  background(0);
  
  //load images
  backgroundImage = loadImage("Background.png");

First, a window is created and a background image is defined.

  //generate textfields
  number = new ControlP5(this);
  number.setFont(createFont("Arial", 40));
  number.addTextfield(" ").setPosition(820, 200).setSize(75, 70).setAutoClear(false);
  
  encryptionFile = new ControlP5(this);
  encryptionFile.setFont(createFont("Arial", 40));
  encryptionFile.addTextfield(" ").setPosition(160, 300).setSize(735, 70).setAutoClear(false);
  encryptionFile.addBang("confirm").setPosition(895, 300).setSize(100, 70);
  
  decryptionFile = new ControlP5(this);
  decryptionFile.setFont(createFont("Arial", 40));
  decryptionFile.addTextfield(" ").setPosition(160, 300).setSize(735, 70).setAutoClear(false);
  decryptionFile.addBang("verify").setPosition(895, 300).setSize(100, 70);

After that, the text fields are created. Then the font is chosen, the position is set and a button for the input is created and written on.

Then we get to the draw() part.

  image(backgroundImage, 0, 0, windowWidth, windowHeight);
  update();

The background is always drawn when calling the draw() function, because you don't want to see the other input fields when changing modes, which you can't use at all. Update is a function which will be explained in more detail later. But I'll say this much in advance: It's about the button.

  //drawing the button
  stroke(0);
  rect(buttonX, buttonY, buttonSizeX, buttonSizeY);
  fill(0);
  textSize(40);
  text(textB[textNumber], 30, 50);

The button should be drawn next and its position determined. For this I take a rectangle. The text size is set, because it can still change within the code and the button should always look the same. Then text is written over the rectangle that will be used as the button. This button is later used to switch between the modes. Therefore the text depends on the mode we are in. I thought that it is easy to switch between these texts with an array. So this is called textB.

  //preparing the text
  textSize(60);
  fill(255, 255, 0);
  //checking the condition for the graphics
  if(encryption == true){
    text("Encryption mode", 400, 100);
    
    //text in the window
    textSize(40);
    fill(255, 200, 0);
    text("Type in a number between 1 and 100:", 50, 250);
    text("File:", 50, 350);
    text("Status:", 300, 700);
    
    //set visibility of textfields
    number.setVisible(true);
    encryptionFile.setVisible(true);
    decryptionFile.setVisible(false);
    
    //look if the button is clicked and fill with a different color
    if(overButtonE(buttonEX, buttonEY, buttonESizeX, buttonESizeY)){
      fill(200, 200, 200);
      buttonEOver = true;
    }else{
      fill(150, 150, 150);
      buttonEOver = false;
    }
    //create the "encrypt now" button
    rect(buttonEX, buttonEY, buttonESizeX, buttonESizeY);
    textSize(40);
    fill(0);
    text(textEncrypt, buttonEX + 10, buttonEY + 50);
  }else{
    text("Decryption mode", 400, 100);
    
    //text in the window
    textSize(40);
    fill(255, 200, 0);
    text("File:", 50, 350);
    text("Status:", 300, 700);
    
    //set visibility of textfields
    number.setVisible(false);
    encryptionFile.setVisible(false);
    decryptionFile.setVisible(true);
    
    //look if the button is clicked and fill with a different color
    if(overButtonD(buttonDX, buttonDY, buttonDSizeX, buttonDSizeY)){
      fill(200, 200, 200);
      buttonDOver = true;
    }else{
      fill(150, 150, 150);
      buttonDOver = false;
    }
    //create the "encrypt now" button
    rect(buttonDX, buttonDY, buttonDSizeX, buttonDSizeY);
    textSize(40);
    fill(0);
    text(textD, buttonDX + 10, buttonDY + 50);
  }
  
  if(actionDone == true){
    textSize(40);
    fill(255, 200, 0);
    text("done", 500, 700);
  }
  if(wrongPath == true){
    textSize(30);
    fill(255, 0, 0);
    text("Could not open file, please check path", 200, 400);
  }

Next, prepare the text and set the window to the correct mode. For this purpose there is (of course) a variable (boolean encryption). If this mode is true, the text is output accordingly and the associated ControlP5 text fields are made visible. Afterwards it is checked whether the mode was changed. Another button for encryption is created. If the variable "encryption" is wrong, then the same is done for the decryption mode. At the end of draw() variables are checked to tell the user if something didn't work or if the file is through.

Now let's get to the functions that are important and executed depending on what the user does.

void decryption(){  
  actionDone = false;
  actionDoing = true;
  
  if(actionDoing == true){
    textSize(40);
    fill(255, 200, 0);
    text("doing", 500, 700);
  }
  
  try{
    //read the lines in the file and save it in the String[]
    file = new File(fileE);
    fileReader = new BufferedReader(new FileReader(file));
    lineCounter = 0;
    
    while((textE[lineCounter] = fileReader.readLine()) != null)
        lineCounter++;
  }
  
  catch(Exception e){
    wrongPath = true;
  }
  
  lineCounter--;
  
  //decide which irrational number is used for encryption
  if(Integer.parseInt(str(textE[lineCounter].charAt(0))) == 1){
    for(int i = 0; i < 41; i++){
      code[i] = pi[i];
    }
  }else if(Integer.parseInt(str(textE[lineCounter].charAt(0))) == 8){
    for(int i = 0; i < 41; i++){
      code[i] = e[i];
    }
  }else if(Integer.parseInt(str(textE[lineCounter].charAt(0))) == 4){
    for(int i = 0; i < 41; i++){
      code[i] = wurzel2[i];
    }  
  }else{
    for(int i = 0; i < 41; i++){
      code[i] = wurzel3[i];
    }
  }
  
  char one = textE[lineCounter].charAt(1);
  inList = Integer.parseInt(str(one));
  try{
    char two = textE[lineCounter].charAt(2);
    inList = inList * 10;
    inList += Integer.parseInt(str(two));
  }
  catch(Exception e){
  }
  
  StringBuilder textER = new StringBuilder();
  
  textES = new StringBuilder();
  
  for(int i = 0; i < lineCounter; i++){
    textER.append(textE[i]);
    textER.reverse();
    textE[i] = textER.toString();
    textER.reverse();
    textER.delete(0, textE[i].length());
  }
  
  inList--;
  
  //replacing the characters
  for(int i = lineCounter-1; i >= 0; i--){
    println(lineCounter);
    for(int j = 0; j < textE[i].length(); j++){
      //character for processing
      currentChar = textE[i].charAt(j);
      currentIndex = charactersString.indexOf(currentChar);
      if(inList < 0)
        inList += 41;
      indexE = currentIndex - code[inList];
      inList--;
      if(indexE < 0)
        indexE += 91;
      println(indexE);
      println(currentChar);
      textES.append(charactersString.charAt(indexE));
    }
    textE[i] = textES.toString();
    println(textES);
    textES.delete(0, textES.length());
  }
  
  StringBuilder textERR = new StringBuilder();
  
  for(int i = 0; i < lineCounter; i++){
    textERR.append(textE[i]);
    textERR.reverse();
    textE[i] = textERR.toString();
    textERR.reverse();
    textERR.delete(0, textE[i].length());
  }
  
  try{
    outputFile = new File(fileE);
    outputFileWriter = new FileWriter(outputFile);
    for(int i = 0; i < lineCounter; i++)
      outputFileWriter.write(textE[i] + "\n");
    outputFileWriter.flush();
    outputFileWriter.close();
    println("done");
  }
  
  catch(Exception e){
    println("could not write");
  }
  
  actionDone = true;
  actionDoing = false;
}

First, the status is changed so that the user gets feedback on his action. Accordingly, a text is output. Then an attempt is made to open and read the file and it is cached in textE. If the file cannot be found, the user is informed about this via a text. After that the first number of the code for decryption is read. This indicates the irrational number which was used. This is then copied into the code[] array to be used further. After that the beginning in the text is found out, which represent the next two numbers of the mostly three-digit code. The strings are reversed because the encoding has to be rolled up from behind. After that the characters are replaced the number of numbers back. To make the message look the same as before, the strings have to be reversed again. Then they are written into the file and "done" as text.

The encryption function is very similar to decryption(), except for the selection of the irrational number and the starting number. Also, the strings do not have to be reversed.

void update(){
  if(overButton(buttonX, buttonY, buttonSizeX, buttonSizeY)){
    fill(255, 160, 0);
    buttonOver = true;
  }else{
    fill(255, 130, 0);
    buttonOver = false;
  }
}

This funktion determines which color the button in the upper left corner is showing or to say it differently if the mouse is over or not.

void mouseClicked(){
  if(buttonOver == true){
    actionDone = false;
    if(encryption == true){
      encryption = false;
      textNumber = 0;
    }else{
      encryption = true;
      textNumber = 1;
    }
  }
  if(buttonEOver == true){
    encryption();
  }
  if(buttonDOver == true){
    decryption();
  }
}

Looks whether the mouse is clicked or not and then takes an action accordingly.

//is mouse over decrypt now button?
boolean overButtonD(int x, int y, int buttonDSizeX, int buttonDSizeY){
  if (mouseX >= x && mouseX <= x + buttonDSizeX && 
      mouseY >= y && mouseY <= y + buttonDSizeY) {
    return true;
  } else {
    return false;
  }
}


//is mouse over encrypt now button?
boolean overButtonE(int x, int y, int buttonESizeX, int buttonESizeY){
  if (mouseX >= x && mouseX <= x + buttonESizeX && 
      mouseY >= y && mouseY <= y + buttonESizeY) {
    return true;
  } else {
    return false;
  }
}


//is mouse over mode button?
boolean overButton(int x, int y, int buttonSizeX, int buttonSizeY){
  if (mouseX >= x && mouseX <= x + buttonSizeX && 
      mouseY >= y && mouseY <= y + buttonSizeY) {
    return true;
  } else {
    return false;
  }
}

With these three functions you check if your mouse is over one of the buttons and if it is and you ask for this function it returns true.

//Store the text from the textfields
void confirm(){
  num = int(number.get(Textfield.class, " ").getText());
  fileE = encryptionFile.get(Textfield.class, " ").getText();
}
void verify(){
  fileD = decryptionFile.get(Textfield.class, " ").getText();
}

The last function is there to store the text from the textfields in the according variable.