Keyboard Shortcuts N Next post
P Previous post
S Save / unsave
R Read aloud
T Toggle theme
/ Focus search
Esc Close panels
🔥
Ready to read...
Cryptography Cryptography Tutorial Java Java and Cryptography Mastery Series Module 1 - Classical Ciphers

Java Program for Columnar Transposition Cipher

Reviewed & accurate
AI Summary

Introduction

The columnar transposition cipher is a classical transposition cipher that rearranges the letters of the plaintext rather than replacing them. Its exact origin is unclear, but it was in regular use by military forces from the 18th century onward and was widely deployed during World War I. The French, German, and Austrian armies all used variants of columnar transposition for field ciphers. In this columnar transposition cipher java tutorial we will implement the full algorithm with a numeric key.

The key idea behind transposition is fundamentally different from substitution. Substitution ciphers like Caesar and Vigenere replace each letter with another letter. Transposition ciphers like columnar transposition keep every letter the same but move them to different positions. This means the frequency distribution of letters is preserved, which is a clue that a cryptanalyst can use to identify the cipher type.

What is the Columnar Transposition Cipher?

The columnar transposition cipher is a transposition cipher that writes the plaintext into a grid row by row, then reads it off column by column in an order determined by a numeric key. The key is a permutation of the integers 1 through n, where n is the number of columns. The order in which we read the columns is determined by sorting the columns by their key number.

For example, the keyword ZEBRA has 5 letters. Sorting them alphabetically gives A B E R Z, so the original positions of those letters define the read order. The A is at position 5, the B at position 2, the E at position 3, the R at position 4, and the Z at position 1. So the columns are read in the order 5, 2, 3, 4, 1, or equivalently we read the column whose key number is 1 first, then 2, and so on.

Compared to substitution ciphers, transposition ciphers are weak on their own because they preserve letter frequencies. However, they become much stronger when combined with substitution in product ciphers. The German ADFGVX cipher of World War I is a famous example: it applies a substitution (Polybius square) followed by a columnar transposition. Modern block ciphers like AES use both substitution and permutation in their design, following the principles laid out by Claude Shannon.

How the Columnar Transposition Cipher Works Step by Step

Suppose our plaintext is WEAREDISCOVEREDFLEEATONCE and our keyword is ZEBRA.

Step 1: Determine the number of columns. The keyword ZEBRA has 5 letters, so there are 5 columns.

Step 2: Determine the order in which to read the columns. Sort the letters of ZEBRA alphabetically: A, B, E, R, Z. Now find where each sorted letter originally appeared. A was at position 5 (1-based), B at position 2, E at position 3, R at position 4, Z at position 1. So the read order is: column 5 first, then column 2, then column 3, then column 4, then column 1.

Step 3: Write the plaintext into the grid row by row, 5 letters per row: Row 1: W E A R E Row 2: D I S C O Row 3: V E R E D Row 4: F L E E A Row 5: T O N C E

Step 4: Read the columns in the order determined by the key. Column 5 contains E O D A E. Column 2 contains E I E L O. Column 3 contains A S R E N. Column 4 contains R C E E C. Column 1 contains W D V F T.

Step 5: Concatenate the columns in order: EODAE IELIO ASREN RCEEC WDVFT. The ciphertext is EODAE IELIOASRENRCEECWDVFT (with spaces removed). To decrypt, fill the grid column by column in the key order and read row by row.

Java Program for Columnar Transposition Cipher


import java.util.*;

public class ColumnarTransposition {

    public static int[] getKeyOrder(String key) {
        key = key.toUpperCase().replaceAll("[^A-Z]", "");
        int n = key.length();
        Character[] chars = new Character[n];
        for (int i = 0; i < n; i++) chars[i] = key.charAt(i);
        Integer[] indices = new Integer[n];
        for (int i = 0; i < n; i++) indices[i] = i;
        Arrays.sort(indices, (a, b) -> {
            if (chars[a] != chars[b]) return chars[a] - chars[b];
            return a - b; // stable for duplicates
        });
        int[] order = new int[n];
        for (int rank = 0; rank < n; rank++) {
            order[indices[rank]] = rank;
        }
        return order;
    }

    public static String encrypt(String text, String key) {
        text = text.toUpperCase().replaceAll("[^A-Z]", "");
        int n = key.replaceAll("[^A-Z]", "").length();
        while (text.length() % n != 0) text += "X";
        int rows = text.length() / n;
        char[][] grid = new char[rows][n];
        for (int i = 0; i < text.length(); i++) {
            grid[i / n][i % n] = text.charAt(i);
        }
        int[] order = getKeyOrder(key);
        StringBuilder sb = new StringBuilder();
        for (int rank = 0; rank < n; rank++) {
            for (int col = 0; col < n; col++) {
                if (order[col] == rank) {
                    for (int r = 0; r < rows; r++) {
                        sb.append(grid[r][col]);
                    }
                    break;
                }
            }
        }
        return sb.toString();
    }

    public static String decrypt(String text, String key) {
        text = text.toUpperCase().replaceAll("[^A-Z]", "");
        int n = key.replaceAll("[^A-Z]", "").length();
        int rows = (text.length() + n - 1) / n;
        while (text.length() < rows * n) text += "X";
        int[] order = getKeyOrder(key);
        char[][] grid = new char[rows][n];
        int idx = 0;
        for (int rank = 0; rank < n; rank++) {
            for (int col = 0; col < n; col++) {
                if (order[col] == rank) {
                    for (int r = 0; r < rows; r++) {
                        grid[r][col] = text.charAt(idx++);
                    }
                    break;
                }
            }
        }
        StringBuilder sb = new StringBuilder();
        for (int r = 0; r < rows; r++) {
            for (int c = 0; c < n; c++) {
                sb.append(grid[r][c]);
            }
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        String plain = "WEAREDISCOVEREDFLEEATONCE";
        String key = "ZEBRA";
        String cipher = encrypt(plain, key);
        String recovered = decrypt(cipher, key);
        System.out.println("Plain   : " + plain);
        System.out.println("Key     : " + key);
        System.out.println("Cipher  : " + cipher);
        System.out.println("Decoded : " + recovered);
    }
}

Code Explanation Line by Line

The getKeyOrder method takes the keyword and returns an array where order[col] is the rank of that column. For example, if the keyword is ZEBRA, then order[0] = 4 (column 1 has rank 4 because Z is the last alphabetically), order[1] = 1 (column 2 has rank 1 because B is the second alphabetically), and so on. We use a stable sort so that duplicate letters in the keyword do not cause ambiguity.

The encrypt method first cleans the plaintext, then pads it with X characters until its length is a multiple of n. This padding ensures the grid is rectangular, which simplifies both encryption and decryption. We then fill the grid row by row, read the columns in order of their rank, and concatenate the results.

The decrypt method reverses the process. We compute the grid dimensions, then fill the grid column by column in the key order. Each column receives the next chunk of ciphertext. Finally, we read the grid row by row to recover the plaintext.

The reason we need both order[rank] = col and a lookup-by-rank loop is that the order array maps column to rank, but during decryption we need to go in the opposite direction (rank to column). The inner loop finds the column whose order equals the current rank.

Sample Input and Output

Plain   : WEAREDISCOVEREDFLEEATONCE
Key     : ZEBRA
Cipher  : EODAEIELIOASRENRCEECWDVFT
Decoded : WEAREDISCOVEREDFLEEATONCE

The output shows the plaintext correctly scrambled and then recovered. Notice that the same plaintext letters appear in the ciphertext, just rearranged. This is the defining property of any transposition cipher.

Common Mistakes to Avoid

1. Forgetting to pad the plaintext. If the plaintext length is not a multiple of n, the grid is jagged and the column lengths differ. Padding with X is the standard solution.

2. Using an unstable sort for the key. If the keyword has duplicate letters (like the second E in ZEBRA's reordered form), the order of those duplicate columns is undefined. Use a stable sort or break ties by original column index.

3. Confusing the order array. The convention here is that order[col] gives the rank of that column, not the column at that rank. Getting this backwards silently produces wrong ciphertext.

4. Not stripping non-letter characters. Spaces and punctuation should be removed before encrypting, otherwise they end up in the grid and produce messy ciphertext.

5. Off-by-one errors when filling or reading the grid. Always test with a small example where you can verify by hand before running on larger inputs.

Real-World Applications

The columnar transposition cipher is not used in modern security products. Its weakness, that it preserves letter frequencies, makes it unsuitable for any real-world threat model. However, transposition as a primitive is still alive and well. The block cipher AES uses a ShiftRows step that is essentially a transposition of bytes within the state matrix. Modern ciphers combine substitution and transposition in repeated rounds to create what Claude Shannon called confusion and diffusion.

In CTF competitions, columnar transposition puzzles appear occasionally. The standard attack is to guess the key length, then look for anagrams that might reveal the column order. With longer keys, this becomes a search problem solvable by simulated annealing or genetic algorithms.

The German ADFGVX cipher of World War I combined a Polybius square substitution with a columnar transposition. Breaking it was one of the great achievements of French cryptanalyst Georges Painvin in 1918. The story is a textbook example of how even a strong product cipher can fall to a determined analyst with enough ciphertext samples.

Conclusion

In this columnar transposition cipher java tutorial we built a complete transposition cipher, sorted a keyword to determine column read order, and explained how to invert the process for decryption. You now understand transposition, the difference between transposition and substitution, and the role of stable sorting. Next, study the rail fence cipher, which is the simplest transposition cipher of all and a good warm-up before tackling more complex designs.

Test Your Knowledge
How did you find this?

Comments

Join the discussion! Sign in with your Google or Blogger account, or comment as Anonymous - no account needed. For quick questions, also reach me on Telegram @cytestch.

Comments