©2018 by macnabbs. Proudly created with Wix.com

 
  • Alibek Jakupov

Data encryption basic algorithms: Java implementation


In this blog post we are going to see some basic data encryption algorithms, with their implementation in Java. The goal of this article is to provide some 'hands-on' experience instead of inundating the reader with piles of theoretical information, which is extremely important, but requires much more careful investigation than simple blog post.


All the code is also available on github, and can be easily used for reader's personal needs. Up we go!


Ceaser Cipher


The most well-known and the most basic algorithm. All the computer security courses start with this algorithm to show the evolution of data encryption techniques.


Quote from Wikipedia:

In cryptography, a Caesar cipher, also known as Caesar's cipher, the shift cipher, Caesar's code or Caesar shift, is one of the simplest and most widely known encryption techniques. It is a type of substitution cipher in which each letter in the plaintext is replaced by a letter some fixed number of positions down the alphabet. For example, with a left shift of 3, D would be replaced by A, E would become B, and so on. The method is named after Julius Caesar, who used it in his private correspondence. The encryption step performed by a Caesar cipher is often incorporated as part of more complex schemes, such as the Vigenère cipher, and still has modern application in the ROT13 system. As with all single-alphabet substitution ciphers, the Caesar cipher is easily broken and in modern practice offers essentially no communications security.

Here's the implementation

import java.util.Scanner;


public class Cipher {
    private static String message;
    private static String option = "";
    
    public static String encode(String message, int k) {
        String encodedMessage = "";
        for (char e:message.toCharArray()) {
            if (e+k > 122) {
                e = (char) ('A' + (e+k-123));
            } else {
                e+=k;
            }
            encodedMessage+=e;
        }
        return encodedMessage;
    }
    
    public static String decode(String message, int k) {
        String decodedMessage = "";
        for (char e:message.toCharArray()) {
            if (e-k<65) {
                int a = e-k;
                int b = 65-a;
                e = (char) ('z' - b+1);
            }else {
                e-=k;
            }
            decodedMessage+=e;
        }
        return decodedMessage;
    }
    
    public static void main (String[] args) {
        int k = 0;
        System.out.println("Enter your message");       
        Scanner input = new Scanner(System.in);
        message = input.nextLine();
        System.out.println("Enter k:");
        System.out.println("Decode or encode?");
        k = input.nextInt();
        
        option = input.nextLine();
        
        if (option.trim().toLowerCase().equals("encode")) {
            System.out.println(encode(message, k));
        } else if (option.trim().toLowerCase().equals
                ("decode")) {
            System.out.println(decode(message, k));
        } else {
            System.out.println("Unknown command");
        }
    }
}


Vigenère cipher


This method consist in encrypting alphabetic text by using a series of interwoven Caesar ciphers, based on the letters of a keyword.


Quote from Wikipedia

First described by Giovan Battista Bellaso in 1553, the cipher is easy to understand and implement, but it resisted all attempts to break it until 1863, three centuries later. This earned it the description le chiffre indéchiffrable (French for 'the indecipherable cipher'). Many people have tried to implement encryption schemes that are essentially Vigenère ciphers. In 1863, Friedrich Kasiski was the first to publish a general method of deciphering Vigenère ciphers. In the 19th century the scheme was misattributed to Blaise de Vigenère (1523–1596), and so acquired its present name. In a Caesar cipher, each letter of the alphabet is shifted along some number of places. For example, in a Caesar cipher of shift 3, A would become D, B would become E, Y would become B and so on. The Vigenère cipher has several Caesar ciphers in sequence with different shift values. To encrypt, a table of alphabets can be used, termed a tabula recta, Vigenère square or Vigenère table. It has the alphabet written out 26 times in different rows, each alphabet shifted cyclically to the left compared to the previous alphabet, corresponding to the 26 possible Caesar ciphers. At different points in the encryption process, the cipher uses a different alphabet from one of the rows. The alphabet used at each point depends on a repeating keyword.

And the implementation


import java.util.Scanner;



public class Vigenere {
    public static String encode (String input, String keyword) {
        char temp;
        String encryptedText = "";
        
        for (int i = 0, j =0; i<input.length(); i++) {
            temp = (char) ('A' + (input.charAt(i)+keyword.charAt(j))%26);
            System.out.println(input.charAt(i) + " + " + keyword.charAt(j) + " = " + temp);
            j = ++% keyword.length();
            encryptedText += temp;
        }
        
        return encryptedText;
    }
    
    public static String decode (String input, String keyword) {
        char temp;
        String encryptedText = "";
        
        for (int i = 0, j =0; i<input.length(); i++) {
            temp = (char) ('A' + (input.charAt(i)- keyword.charAt(j) + 26)%26);
            System.out.println(input.charAt(i) + " + " + keyword.charAt(j) + " = " + temp);
            j = ++% keyword.length();
            encryptedText += temp;
        }
        
        return encryptedText;
    }
    
    public static void main (String[] args) {
        System.out.println("Enter your sequence");
        String input = "";
        String keyword = "";
        String option ="";
        
        Scanner scanner = new Scanner (System.in);
        input = scanner.nextLine();
        input = input.trim();
        System.out.println("Enter your keyword");
        keyword =scanner.nextLine();
        keyword = keyword.trim();
        System.out.println("Enter Option");
        option = scanner.nextLine();
        
        if (option.trim().toLowerCase().equals("encode")) {
            System.out.println(encode(input, keyword));
        } else if (option.trim().toLowerCase().equals("decode")) {
            System.out.println(decode(input, keyword));
        } else {
            System.out.println("Unknown Option");
        }
        
    }
}

Route Cipher


In cryptography, a transposition cipher is a technique of encryption by which the indices held by units of plaintext (characters or groups of characters) are shifted according to a regular system, so that the encrypted text constitutes a permutation of the initial data. Consequetly, the order of the units is changed (the initial text is reordered). Mathematically a bijective function is used on the characters' positions to encrypt and an inverse function to decrypt.


Route cipher is one of the forms of transposition cipher.


As Wikipedia says:

In a route cipher, the plaintext is first written out in a grid of given dimensions, then read off in a pattern given in the key. For example, using the same plaintext that we used for rail fence:
W R I O R F E O E 
E E S V E L A N J 
A D C E D E T C X 

The key might specify "spiral inwards, clockwise, starting from the top right". That would give a cipher text of:
EJXCTEDEC DAEWRIORF EONALEVSE

Route ciphers have many more keys than a rail fence. In fact, for messages of reasonable length, the number of possible keys is potentially too great to be enumerated even by modern machinery. However, not all keys are equally good. Badly chosen routes will leave excessive chunks of plaintext, or text simply reversed, and this will give cryptanalysts a clue as to the routes. A variation of the route cipher was the Union Route Cipher, used by Union forces during the American Civil War. This worked much like an ordinary route cipher, but transposed whole words instead of individual letters. Because this would leave certain highly sensitive words exposed, such words would first be concealed by code. The cipher clerk may also add entire null words, which were often chosen to make the ciphertext humorous.

Java implementation

import java.util.Random;
import java.util.Scanner;


import sun.net.www.content.text.plain;



public class RouteCipher {
    private static String plainText = "";
    private static int rows = 0;
    private static int columns = 0;
    private static char[][] array;
    private static Scanner scanner;
    private static String encodedMessage = "";
    private static String decodedMessage;
    
    
    public static void main (String[] args) {
        scanner = new Scanner (System.in);
        System.out.println("Enter text");
        plainText = scanner.nextLine();
        plainText = plainText.trim();
        plainText = plainText.replaceAll("\\s","");
        Random random = new Random();
        
        if (plainText.length()%4 ==0) {
            rows = plainText.length()/4;
            columns = 4;
        } else {
            while (plainText.length()%4!=0) {
                plainText += (char)('A' 
                + random.nextInt(41));
            }
            System.out.println(plainText);
            rows = plainText.length()/4;
            columns = 4;
        }
        
        array = new char[rows][columns];
        
        for (int i = 0, k =0; i<rows; i++) {
            for (int j =0; j<columns; j++) {
                System.out.println(
                        plainText.toCharArray()[k]);
                array[i][j] = plainText.toCharArray()[k];
                k = ++% plainText.length();
            }
        }
        
        System.out.println("Message in a table");
        for (int i = 0; i<rows; i++) {
            for (int j =0; j<columns; j++) {
                System.out.print(array[i][j] + " ");
            }
            System.out.println();
        }
        
        System.out.println("Transformation matrix");
        for (int j = columns-1; j >= 0; j--) {
            for (int i = rows-1; i >= 0; i--) {
                System.out.print(array[i][j] + " ");
                encodedMessage += array[i][j];
            }
            System.out.println();
        }
        
        System.out.println("The " +
                "encrypted message is: "+ encodedMessage);
    }
}



Playfair cipher


Quote from Wikipedia:

The Playfair cipher or Playfair square or Wheatstone-Playfair cipher is a manual symmetric encryption technique and was the first literal digram substitution cipher. The scheme was invented in 1854 by Charles Wheatstone, but bears the name of Lord Playfair for promoting its use. The technique encrypts pairs of letters (bigrams or digrams), instead of single letters as in the simple substitution cipher and rather more complex Vigenère cipher systems then in use. The Playfair is thus significantly harder to break since the frequency analysis used for simple substitution ciphers does not work with it. The frequency analysis of bigrams is possible, but considerably more difficult. With 600[1] possible bigrams rather than the 26 possible monograms (single symbols, usually letters in this context), a considerably larger cipher text is required in order to be useful.

P L A Y F
I R E X M
B C D G H
K N O Q S
T U V W Z

Encrypting the message "Hide the gold in the tree stump" (note the null "X" used to separate the repeated "E"s) :
HI DE TH EG OL DI NT HE TR EX ES TU MP

Here is the source code:

import java.util.Scanner;


import sun.reflect.ReflectionFactory.GetReflectionFactoryAction;


public class Playfair {
    private static char[][] alphaMatrix;
    private static String key;
    private static String message;
    private static Scanner scanner;
    private static String encryptedMessage = "";
    
    public static int getRow(char letter, char[][] alphaMatrix) {
        int row = -1;
        
        for (int i = 0; i<5; i++) {
            for (int j =0; j<5; j++ ) {
                if (alphaMatrix[i][j]==letter) {
                    row = i;
                }
            }
        }
        
        return row;
    }
    
    public static int getColumn(char letter, char[][] alphaMatrix) {
        int column = -1;
        
        for (int i = 0; i<5; i++) {
            for (int j =0; j<5; j++ ) {
                if (alphaMatrix[i][j]==letter) {
                    column = j;
                }
            }
        }
        
        return column;
    }
    
    public static void main (String[] args) {
        System.out.println("Welcome");
        scanner = new Scanner(System.in);
        System.out.println("Enter your key:");
        key = scanner.nextLine();
        key = key.replaceAll("\\s","").trim().toUpperCase();
        String temp = "";
        
        for (char letter:key.toCharArray()) {
            if (!(temp.indexOf(letter)>=0)) {
                temp+=letter;
            }
        }
        
        key = temp;
        
        alphaMatrix = new char[5][5];
        
        int counter = 0;
        char symbol;
        
        //create a string then transform to matrix
        while (key.toCharArray().length != 26) {
            symbol = (char) ('A' + counter);
            if ((key.indexOf(symbol)<0) && (symbol!= 'Q') ) {
                key +=symbol;
            }
            symbol = (char) ('A' + counter++);
        }
        System.out.println(key);
        
        //transform a string to matrix
        for (int i = 0, k =0; i<5; i++) {
            for (int j =0; j<5; j++) {
                alphaMatrix[i][j] = key.toCharArray()[k];
                k = ++% key.length();
            }
        }
        //now the matrix is ready
        
        for (int i = 0; i<5; i++) {
            for (int j =0; j<5; j++ ) {
                System.out.print(alphaMatrix[i][j] + " ");
            }
            System.out.println();
        }
        
        System.out.println("Enter your message: ");
        message = scanner.nextLine();
        message = message.replaceAll("\\s","").trim().toUpperCase();
        
        //replace the repeating symbols
        
        for (int i =0; i < message.length()-1; i++) {
            if (message.
                    toCharArray()[i]==
                        message.toCharArray()[i+1]) {
                message = message.substring(0,i+1) 
                + 'X' + message.substring(i+1,message.length());
            }
        }
        
        
        if (message.length()%2 !=0) {
            message +='Z';
        }
        System.out.println(message);
        
        //start working with letter pairs
        //if the letters get columns and getrows correspond...
        //either...
        for (int i =0; i< message.length(); i++) {
            System.out.println(message.
                    toCharArray()[i] + "~" + 
                    message.toCharArray()[i+1]);
            if (getColumn(message.
                    toCharArray()[i], alphaMatrix) == getColumn(message.
                            toCharArray()[i+1], alphaMatrix)) {
                System.out.println("The columns are equal");
                if (getRow(message.
                        toCharArray()[i], alphaMatrix) != 4) {
                    encryptedMessage +=alphaMatrix[getRow(message.
                            toCharArray()[i], alphaMatrix)+1]
                            [getColumn(message.
                                    toCharArray()[i], alphaMatrix)];
                } else {
                    encryptedMessage +=alphaMatrix[0]
                            [getColumn(message.
                                    toCharArray()[i], alphaMatrix)];
                }
                if (getRow(message.
                        toCharArray()[i+1], alphaMatrix) != 4) {
                    encryptedMessage +=alphaMatrix[getRow(message.
                            toCharArray()[i+1], alphaMatrix)+1]
                            [getColumn(message.
                                    toCharArray()[i+1], alphaMatrix)];
                } else {
                    encryptedMessage +=alphaMatrix[0]
                            [getColumn(message.
                                    toCharArray()[i+1], alphaMatrix)];
                }
            }else if (getRow(message.
                    toCharArray()[i], alphaMatrix) == getRow(message.
                            toCharArray()[i+1], alphaMatrix)) {
                System.out.println("The rows are equal");
                if (getColumn(message.
                        toCharArray()[i], alphaMatrix) != 4) {
                    encryptedMessage +=alphaMatrix[getRow(message.
                            toCharArray()[i], alphaMatrix)]
                            [getColumn(message.
                                    toCharArray()[i], alphaMatrix)+1];
                } else {
                    encryptedMessage +=alphaMatrix[getRow(message.
                            toCharArray()[i], alphaMatrix)]
                            [0];
                }
                if (getRow(message.
                        toCharArray()[i+1], alphaMatrix) != 4) {
                    encryptedMessage +=alphaMatrix[getRow(message.
                            toCharArray()[i+1], alphaMatrix)]
                            [getColumn(message.
                                    toCharArray()[i+1], alphaMatrix)+1];
                } else {
                    encryptedMessage +=alphaMatrix[getRow(message.
                            toCharArray()[i+1], alphaMatrix)]
                            [0];
                }
            } else {
                System.out.println("Neither");
                encryptedMessage +=alphaMatrix[getRow(message.
                        toCharArray()[i], alphaMatrix)]
                        [getColumn(message.
                                toCharArray()[i+1], alphaMatrix)];
                encryptedMessage +=alphaMatrix[getRow(message.
                        toCharArray()[i+1], alphaMatrix)]
                        [getColumn(message.
                                toCharArray()[i], alphaMatrix)];
            }
            i++;
        }
        
        System.out.println(encryptedMessage);
    }
}


One-time-pad


This is the method that cannot be cracked, but needs the use of a one-time pre-shared key the same size as, or longer than, the message being sent.

In this technique, a plaintext is paired with a random secret key (also referred to as a one-time pad). Then, each bit or character of the plaintext is encrypted by combining it with the corresponding bit or character from the pad using modular addition. If the key is (1) truly random, (2) at least as long as the plaintext, (3) never reused in whole or in part, and (4) kept completely secret, then the resulting ciphertext will be impossible to decrypt or break. It has also been proven that any cipher with the property of perfect secrecy must use keys with effectively the same requirements as OTP keys. Digital versions of one-time pad ciphers have been used by nations for critical diplomatic and military communication, but the problems of secure key distribution have made them impractical for most applications. First described by Frank Miller in 1882, the one-time pad was re-invented in 1917. On July 22, 1919, U.S. Patent 1,310,719 was issued to Gilbert Vernam for the XOR operation used for the encryption of a one-time pad. Derived from his Vernam cipher, the system was a cipher that combined a message with a key read from a punched tape. In its original form, Vernam's system was vulnerable because the key tape was a loop, which was reused whenever the loop made a full cycle. One-time use came later, when Joseph Mauborgne recognized that if the key tape were totally random, then cryptanalysis would be impossible. The "pad" part of the name comes from early implementations where the key material was distributed as a pad of paper, allowing the current top sheet to be torn off and destroyed after use. For concealment the pad was sometimes so small that a powerful magnifying glass was required to use it. The KGB used pads of such size that they could fit in the palm of a hand, or in a walnut shell. To increase security, one-time pads were sometimes printed onto sheets of highly flammable nitrocellulose, so that they could easily be burned after use. There is some ambiguity to the term "Vernam cipher" because some sources use "Vernam cipher" and "one-time pad" synonymously, while others refer to any additive stream cipher as a "Vernam cipher", including those based on a cryptographically secure pseudorandom number generator (CSPRNG).

(Wikipedia)

     H       E       L       L       O  message
   7 (H)   4 (E)  11 (L)  11 (L)  14 (O) message
+ 23 (X)  12 (M)   2 (C)  10 (K)  11 (L) key
= 30      16      13      21      25     message + key
=  4 (E)  16 (Q)  13 (N)  21 (V)  25 (Z) (message + key) mod 26
      E       Q       N       V       Z  → ciphertext

E       Q       N       V       Z  ciphertext
    4 (E)  16 (Q)  13 (N)  21 (V)  25 (Z) ciphertext
-  23 (X)  12 (M)   2 (C)  10 (K)  11 (L) key
= -19       4      11      11      14     ciphertext – key
=   7 (H)   4 (E)  11 (L)  11 (L)  14 (O) ciphertext – key (mod 26)
       H       E       L       L       O  → message

Java code

Jva.util.Random;
import java.util.Scanner;


import sun.net.www.content.text.plain;



public class OneTimePad {
    private static String plainText = "";
    private static String key = "";
    private static String encryptedMessage = "";
    private static int messageSize;
    private static Scanner scanner;
    private static String option;
    
    public static String encrypt (String plainText, String key) {
        String encryptedMessage = "";
        char letter;
        int index;
        
        for (int i =0 ; i < plainText.length(); i++) {
            index = plainText.toCharArray()[i] + key.toCharArray()[i];
            
            if (index <26) {
                index= index;
            } else {
                index = index%26;
            }
            letter = (char) ('A' + index);
            System.out.println(
                    plainText.toCharArray()[i] + 
                    " + " + key.toCharArray()[i] + 
                    " = " + index + " ~ " + 
                    letter); 
            encryptedMessage += letter;
        }
        
        return encryptedMessage;
    }
    
    public static String decrypt (String plainText, String key) {
        String decryptedMessage = "";
        char letter;
        int index;
        
        for (int i =0 ; i < plainText.length(); i++) {
            index = plainText.toCharArray()[i] - key.toCharArray()[i];
            
            if (index > 0) {
                index = index;
            } else {
                index +=26;
            }
            if (index == 26) {
                index = 0;
            }
            letter = (char) ('A' + index);
            System.out.println(
                    plainText.toCharArray()[i] + 
                    " - " + key.toCharArray()[i] + 
                    " = " + index + " ~ " + 
                    letter); 
            decryptedMessage += letter;
        }
        
        return decryptedMessage;
    }
    
    public static void main (String[] args) {
        System.out.println("Welcome");
        
        scanner = new Scanner (System.in);
        Random random = new Random();
        
        System.out.println("Enter your message:");
        
        plainText = scanner.nextLine();
        plainText = plainText.replaceAll("\\s","").trim().toUpperCase();
        plainText = plainText.replace("1", "ONE");
        plainText = plainText.replace("2", "TWO");
        plainText = plainText.replace("3", "THREE");
        plainText = plainText.replace("4", "FOUR");
        plainText = plainText.replace("5", "FIVE");
        plainText = plainText.replace("6", "SIX");
        plainText = plainText.replace("7", "SEVEN");
        plainText = plainText.replace("8", "EIGHT");
        plainText = plainText.replace("9", "NINE");
        plainText = plainText.replace("0", "ZERO");
        
        messageSize = plainText.length();
        
        System.out.println("The modified message is: " + plainText);
        
        System.out.println("Enter option");
        option = scanner.nextLine();
        
        if (option.trim().toLowerCase().equals("encrypt")) {
            for (int i =0; i< messageSize; i++) {
                key += (char) ('A' + random.nextInt(26));
            }
            
            System.out.println("The key is:" + key);
            
            encryptedMessage = encrypt(plainText, key);
            
            System.out.println("The encrypted message is: " + encryptedMessage);
        } else if (option.trim().toLowerCase().equals
                ("decrypt")) {
            System.out.println("Eneter key");
            
            key = scanner.nextLine();
            
            encryptedMessage = decrypt (plainText, key);
            
            System.out.println("The source text is: " + encryptedMessage);
        } else {
            System.out.println("Unknown command");
        }
    }
}

Hope this was useful. Enjoy