Introduction
The two square cipher java is a classical digraph substitution cipher that sits between the simple Polybius square and the more famous four square cipher. It uses two 5 by 5 Polybius squares, one for plaintext selection and one for ciphertext selection, with one square typically reversed to make the construction reversible. The cipher was studied in the late nineteenth century as a way to break single letter frequency analysis while remaining easy to operate by hand. This two square cipher java tutorial reconstructs the algorithm from first principles and produces a complete runnable Java program.
The two square cipher is interesting because it demonstrates how a small modification to a Polybius lookup can produce a fundamentally different cipher class. By operating on pairs of letters rather than single letters, the cipher moves from a 26-element substitution to a 676-element substitution, which is dramatically harder to attack with simple statistics.
What is the Two Square Cipher?
The two square cipher is a digraph substitution cipher. The plaintext is split into pairs of letters. For each pair, the first plaintext letter is looked up in the first 5 by 5 grid and the second plaintext letter is looked up in the second 5 by 5 grid. The two letters form the opposite corners of a rectangle, and the ciphertext is the pair of letters at the other two corners.
Compared to the Playfair cipher, the two square cipher uses two separate grids instead of one shared grid. Compared to the four square cipher, the two square cipher uses only two grids instead of four. The two square cipher is slightly weaker than the four square cipher because the same grid is used for both plaintext and ciphertext selection in a symmetric way.
The two square cipher is a monoalphabetic digraph substitution, which means the same plaintext pair always produces the same ciphertext pair. This makes it vulnerable to digraph frequency analysis, but the analysis requires much more ciphertext than single letter analysis because English has 676 possible digraphs versus 26 single letters.
How the Two Square Cipher Works Step by Step
Step 1: Build two 5 by 5 grids from two keywords. We use FIRST and SECOND as the two keywords. The mixed alphabets are FIRSTABDEGHKLMNOPQUVWXY (I and J merged) for the first grid, and SECONDABFGHIKLMNPQRTUVWXY (I and J merged) for the second grid.
Step 2: Split the plaintext into pairs. We use HELLO WORLD as the plaintext. After cleaning (removing spaces and merging J into I), the plaintext is HELLOWORLD. Split into pairs: HE LL OW OR LD. If the plaintext has an odd length, append an X to make it even.
Step 3: For each pair, find the positions of the two letters in their respective grids. For HE, H is at row 2 column 1 of the first grid (using 0-indexed: row 2, column 0), and E is at row 0 column 1 of the second grid. The two letters form opposite corners of a rectangle in the combined coordinate space.
Step 4: Take the other two corners as the ciphertext. The ciphertext letters are the second grid letter at row 2 column 1 and the first grid letter at row 0 column 0. Applying this rule to each pair produces the ciphertext.
Step 5: Decrypt by reversing the lookup. The same operation is performed because the two square cipher is reciprocal when the two grids are arranged symmetrically.
Java Program for Two Square Cipher
import java.util.LinkedHashSet;
import java.util.Set;
public class TwoSquareCipher {
private final char[][] grid1 = new char[5][5];
private final char[][] grid2 = new char[5][5];
public TwoSquareCipher(String key1, String key2) {
buildGrid(grid1, key1);
buildGrid(grid2, key2);
}
private void buildGrid(char[][] grid, String keyword) {
Set<Character> seen = new LinkedHashSet<>();
keyword = keyword.toUpperCase();
for (char ch : keyword.toCharArray()) {
if (ch == 'J') ch = 'I';
if (ch >= 'A' && ch <= 'Z') seen.add(ch);
}
for (char ch = 'A'; ch <= 'Z'; ch++) {
if (ch == 'J') continue;
seen.add(ch);
}
int i = 0;
for (Character c : seen) {
grid[i / 5][i % 5] = c;
i++;
if (i == 25) break;
}
}
private int[] find(char[][] grid, char ch) {
if (ch == 'J') ch = 'I';
for (int r = 0; r < 5; r++) {
for (int c = 0; c < 5; c++) {
if (grid[r][c] == ch) return new int[]{r, c};
}
}
throw new IllegalArgumentException("Char not in grid: " + ch);
}
public String encrypt(String plain) {
plain = plain.toUpperCase().replace("J", "I").replaceAll("[^A-Z]", "");
if (plain.length() % 2 != 0) plain += "X";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < plain.length(); i += 2) {
char a = plain.charAt(i);
char b = plain.charAt(i + 1);
int[] pa = find(grid1, a);
int[] pb = find(grid2, b);
// ciphertext: same row as pa but column from pb (in grid2),
// same row as pb but column from pa (in grid1)
sb.append(grid2[pa[0]][pb[1]]);
sb.append(grid1[pb[0]][pa[1]]);
}
return sb.toString();
}
public String decrypt(String cipher) {
cipher = cipher.toUpperCase().replaceAll("[^A-Z]", "");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < cipher.length(); i += 2) {
char a = cipher.charAt(i);
char b = cipher.charAt(i + 1);
// a is from grid2, b is from grid1
int[] pa = new int[]{-1, -1};
int[] pb = new int[]{-1, -1};
for (int r = 0; r < 5; r++) {
for (int c = 0; c < 5; c++) {
if (grid2[r][c] == a) { pa[0] = r; pa[1] = c; }
if (grid1[r][c] == b) { pb[0] = r; pb[1] = c; }
}
}
// recover: row of pa in grid1, col of pb in grid1 -> plaintext letter 1
// row of pb in grid2, col of pa in grid2 -> plaintext letter 2
sb.append(grid1[pa[0]][pb[1]]);
sb.append(grid2[pb[0]][pa[1]]);
}
return sb.toString();
}
public static void main(String[] args) {
TwoSquareCipher ts = new TwoSquareCipher("FIRST", "SECOND");
String plain = "HELLO WORLD";
String cipher = ts.encrypt(plain);
String back = ts.decrypt(cipher);
System.out.println("Plain : " + plain);
System.out.println("Cipher: " + cipher);
System.out.println("Back : " + back);
}
}
Code Explanation Line by Line
The constructor takes two keywords and builds two 5 by 5 grids. The buildGrid method uses a LinkedHashSet to collect letters from the keyword first, then from the regular alphabet, with I and J merged to fit 26 letters into 25 slots. The same builder is reused for both grids.
The find method scans a grid for a given letter and returns its row and column as a two-element int array. The lookup is O(25) per call, which is acceptable for a teaching implementation. A production implementation would use a precomputed HashMap for O(1) lookup.
The encrypt method first cleans the input, merges J into I, and pads with X if the length is odd. It then walks the plaintext in pairs, finds the positions of the two letters in their respective grids, and produces the ciphertext pair by taking the other two corners of the rectangle formed by the two positions.
The ciphertext is formed by grid2[pa[0]][pb[1]] (same row as the plaintext letter 1 in grid1, but the column of the plaintext letter 2 in grid2) and grid1[pb[0]][pa[1]] (same row as the plaintext letter 2 in grid2, but the column of the plaintext letter 1 in grid1). This is the standard two square substitution rule.
The decrypt method reverses the operation. It scans grid2 to find the row of the first ciphertext letter and grid1 to find the row of the second ciphertext letter, then reconstructs the plaintext letters using the same rectangle rule. The result is the recovered plaintext.
Sample Input and Output
Key1 : FIRST Key2 : SECOND Plain : HELLO WORLD Cipher: (output of the program) Back : HELLOWORLD (or HELLOWORLDX if padded)
The plaintext HELLO WORLD is cleaned to HELLOWORLD, then split into pairs HE LL OW OR LD. Each pair is substituted by looking up the two letters in their respective grids and taking the other two corners of the rectangle. The decrypted output matches the cleaned plaintext, with a possible trailing X if the original length was odd.
Common Mistakes to Avoid
First, forgetting to merge I and J in the 5 by 5 grids. The two square cipher, like the Playfair and four square ciphers, uses 5 by 5 grids that fit only 25 letters. If you skip the merge, the grid lookup will fail for plaintexts containing J.
Second, using the wrong grid for the wrong letter. The first plaintext letter uses grid1, the second plaintext letter uses grid2. If you swap them, the cipher still produces a ciphertext, but it is not the two square cipher and the round trip will fail.
Third, forgetting to pad odd length plaintexts. If the plaintext has an odd length, the last pair is incomplete. Padding with X (or any fixed letter) is the standard solution.
Fourth, handling double letter pairs incorrectly. In the Playfair cipher, double letters in a pair require special handling. The two square cipher does not have this issue because each letter of the pair uses a different grid, so double letters simply look up the same letter in two different grids.
Real-World Applications
The two square cipher is not used in production today. Its security is weak by modern standards because it is a monoalphabetic digraph substitution, which can be broken with enough ciphertext using digraph frequency analysis.
However, the two square cipher is a useful teaching example because it introduces the concept of digraph substitution without the complexity of the four square cipher. Once a student understands the two square construction, the four square cipher is a natural extension that adds two more grids to make the cipher stronger.
The two square cipher also demonstrates the principle of using multiple substitution tables to flatten frequency statistics. By operating on pairs of letters and using two grids, the cipher effectively has a 676 by 676 substitution table, which is much harder to attack than a 26 by 26 single letter table.
In capture the flag events, the two square cipher is sometimes used as a puzzle that requires the solver to recognize the digraph structure. The hint is usually that the ciphertext length is even and that digraph frequency analysis reveals the keywords used to build the grids.
The two square cipher is also historically significant because it was a stepping stone between the simple Polybius square and the more sophisticated Playfair and four square ciphers. Studying the two square construction makes the more complex ciphers easier to understand because the underlying principle is the same: use multiple grids to make the substitution harder to attack.
Conclusion
The two square cipher is a digraph substitution cipher that uses two 5 by 5 grids. We built the grids from two keywords, looked up each plaintext pair in their respective grids, took the other two corners of the rectangle as the ciphertext, and reversed the process for decryption. Next you should study the Playfair cipher (which uses a single 5 by 5 grid with a different substitution rule), the four square cipher (which uses four 5 by 5 grids), and the bifid cipher (which uses fractionation without transposition).
Comments
Comments
Post a Comment