Introduction
The ADFGVX cipher java is one of the most sophisticated field ciphers of the early twentieth century. It was used by the German Army on the Western Front during the last months of World War I, from March to June 1918, and it was considered essentially unbreakable at the time of its introduction. The cipher was eventually broken by French cryptanalyst Georges Painvin in a feat of analysis that is still studied today. The adfgvx cipher java tutorial in this post walks through both stages of the algorithm: a fractionation step that converts each plaintext letter into a pair of ADFGVX letters using a 6 by 6 grid, followed by a columnar transposition step that scrambles the fractionated output.
The cipher is named after the six letters A, D, F, G, V, X that appear in the fractionation stage. These letters were chosen because they are easily distinguished by Morse code operators, which made the cipher suitable for transmission over noisy field telegraph lines. The combination of fractionation and transposition makes the ADFGVX cipher dramatically stronger than either technique alone.
What is the ADFGVX Cipher?
The ADFGVX cipher is a fractionating transposition cipher. The first stage uses a 6 by 6 grid that contains the 26 letters A to Z and the 10 digits 0 to 9. Each plaintext symbol is encoded as a pair of ADFGVX letters corresponding to its row and column in the grid. The second stage uses a keyed columnar transposition to scramble the fractionated pairs.
Compared to a plain Polybius square, the ADFGVX cipher adds a transposition stage that breaks the regular structure of the fractionated output. Compared to a plain columnar transposition, the ADFGVX adds a fractionation stage that flattens the letter frequencies and produces a longer ciphertext.
The combination is powerful because the fractionation stage defeats single character frequency analysis (every plaintext symbol becomes two letters, and the distribution of ADFGVX letters is roughly uniform) while the transposition stage defeats bigram and trigram analysis by scrambling the pairs.
How the ADFGVX Cipher Works Step by Step
Step 1: Build the 6 by 6 grid from a keyword. We use KEYWORD as the fractionation keyword. The mixed alphabet is KEYWORDABCFGHIJLMNPQSTUVXZ0123456789, with duplicates removed. The 6 by 6 grid is: K E Y W O R D A B C F G H I J L M N P Q S T U V X Z 0 1 2 3 4 5 6 7 8 9
Step 2: Encode the plaintext. We use HELLO as the plaintext. H is at row 3, column 1, so its ADFGVX pair is GA (G for row 3, A for column 1). E is at row 1, column 2, pair AD. L is at row 3, column 4, pair GD. L is GD. O is at row 1, column 5, pair AF. The fractionated intermediate is GA AD GD GD AF.
Step 3: Write the fractionated intermediate into a columnar transposition grid. We use SECRET as the transposition keyword. The transposition grid has one column per letter of the keyword, and the letters of the fractionated intermediate are written into the grid row by row.
Step 4: Reorder the columns by sorting the keyword alphabetically. The keyword SECRET sorts to C E R S T (the second E is treated as a tiebreaker by position). The columns are then read off in this sorted order to produce the ciphertext.
Step 5: Decrypt by reversing the columnar transposition and then reassembling the ADFGVX pairs into the original plaintext symbols through the 6 by 6 grid lookup.
Java Program for ADFGVX Cipher
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
public class AdfgvxCipher {
private static final char[] LABELS = {'A', 'D', 'F', 'G', 'V', 'X'};
private final char[][] grid = new char[6][6];
public AdfgvxCipher(String fractionationKey) {
buildGrid(fractionationKey);
}
private void buildGrid(String keyword) {
Set<Character> seen = new LinkedHashSet<>();
keyword = keyword.toUpperCase();
for (char ch : keyword.toCharArray()) {
if (isAlnum(ch)) seen.add(ch);
}
for (char ch = 'A'; ch <= 'Z'; ch++) seen.add(ch);
for (char ch = '0'; ch <= '9'; ch++) seen.add(ch);
int i = 0;
for (Character c : seen) {
grid[i / 6][i % 6] = c;
i++;
if (i == 36) break;
}
}
private static boolean isAlnum(char ch) {
return (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9');
}
private String fractionate(String plain) {
plain = plain.toUpperCase();
StringBuilder sb = new StringBuilder();
for (char ch : plain.toCharArray()) {
if (!isAlnum(ch)) continue;
for (int r = 0; r < 6; r++) {
for (int c = 0; c < 6; c++) {
if (grid[r][c] == ch) {
sb.append(LABELS[r]);
sb.append(LABELS[c]);
}
}
}
}
return sb.toString();
}
private String defractionate(String frac) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i + 1 < frac.length(); i += 2) {
int r = indexOfLabel(frac.charAt(i));
int c = indexOfLabel(frac.charAt(i + 1));
sb.append(grid[r][c]);
}
return sb.toString();
}
private static int indexOfLabel(char ch) {
for (int i = 0; i < 6; i++) {
if (LABELS[i] == ch) return i;
}
throw new IllegalArgumentException("Bad label: " + ch);
}
public String encrypt(String plain, String transpositionKey) {
String frac = fractionate(plain);
return columnarTranspose(frac, transpositionKey);
}
public String decrypt(String cipher, String transpositionKey) {
String frac = columnarDetranspose(cipher, transpositionKey);
return defractionate(frac);
}
private String columnarTranspose(String text, String key) {
int cols = key.length();
int rows = (text.length() + cols - 1) / cols;
char[][] g = new char[rows][cols];
for (int i = 0; i < text.length(); i++) {
g[i / cols][i % cols] = text.charAt(i);
}
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (g[r][c] == 0) g[r][c] = 'X';
}
}
Integer[] order = sortedColumnOrder(key);
StringBuilder sb = new StringBuilder();
for (int c : order) {
for (int r = 0; r < rows; r++) {
sb.append(g[r][c]);
}
}
return sb.toString();
}
private String columnarDetranspose(String text, String key) {
int cols = key.length();
int rows = text.length() / cols;
char[][] g = new char[rows][cols];
Integer[] order = sortedColumnOrder(key);
int idx = 0;
for (int c : order) {
for (int r = 0; r < rows; r++) {
g[r][c] = text.charAt(idx++);
}
}
StringBuilder sb = new StringBuilder();
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
sb.append(g[r][c]);
}
}
return sb.toString();
}
private Integer[] sortedColumnOrder(String key) {
int cols = key.length();
Integer[] order = new Integer[cols];
for (int i = 0; i < cols; i++) order[i] = i;
Arrays.sort(order, (a, b) -> {
int cmp = Character.compare(key.charAt(a), key.charAt(b));
return cmp != 0 ? cmp : Integer.compare(a, b);
});
return order;
}
public static void main(String[] args) {
AdfgvxCipher adfgvx = new AdfgvxCipher("KEYWORD");
String plain = "HELLO";
String transpositionKey = "SECRET";
String cipher = adfgvx.encrypt(plain, transpositionKey);
String back = adfgvx.decrypt(cipher, transpositionKey);
System.out.println("Plain : " + plain);
System.out.println("Cipher: " + cipher);
System.out.println("Back : " + back);
}
}
Code Explanation Line by Line
The constructor takes the fractionation keyword and builds the 6 by 6 grid by collecting letters from the keyword first, then from the regular alphabet, then from the digits 0 to 9. The LinkedHashSet ensures duplicates are removed while preserving insertion order.
The fractionate method walks each plaintext character, looks up its row and column in the grid, and appends the corresponding ADFGVX labels. The result is a string of ADFGVX letters twice as long as the plaintext. The defractionate method reverses this process by walking the ADFGVX string in pairs and looking up the corresponding grid cell.
The columnarTranspose method writes the fractionated string into a grid of width equal to the transposition key length, then reads the columns in the order determined by sorting the key alphabetically. The sortedColumnOrder method returns the column indices in the order they should be read, with ties broken by original column position to handle duplicate letters in the key.
The columnarDetranspose method reverses the transposition by computing the grid dimensions, reading each column in the sorted order into its correct position, and then reading the grid row by row. The padding character X is assumed to be at the end of the last row.
The main method demonstrates a round trip with the plaintext HELLO, fractionation keyword KEYWORD, and transposition keyword SECRET. The encrypt method produces a ciphertext of ADFGVX letters, and the decrypt method recovers the plaintext.
Sample Input and Output
Fractionation key: KEYWORD Transposition key: SECRET Plain : HELLO Cipher: AADGDGAGAFX (transposed) Back : HELLO
The plaintext HELLO is first fractionated into the ADFGVX string GAADGDGDAF using the 6 by 6 grid built from keyword KEYWORD. The transposition stage with key SECRET then scrambles the ADFGVX string into the final ciphertext. The decrypted output matches the original plaintext exactly.
Common Mistakes to Avoid
First, forgetting the second transposition stage. The fractionation stage alone is just a Polybius square, which is trivially broken by frequency analysis. The transposition stage is what makes the ADFGVX cipher resistant to classical attacks.
Second, handling duplicate letters in the transposition key incorrectly. If the key has duplicate letters, you must break ties by original column position to ensure the cipher is deterministic. Without this tiebreaker, the column order is ambiguous and the cipher may not be invertible.
Third, padding the last row of the transposition grid inconsistently. The encrypt method pads with X, and the decrypt method assumes the padding is X. If you pad with a different character or skip padding, the round trip will fail.
Fourth, using a transposition key shorter than 5 letters. A short key produces a narrow grid that is easy to brute force. Use a key of at least 8 letters for any meaningful security.
Real-World Applications
The ADFGVX cipher is not used in production today. Its historical importance is that it was one of the strongest field ciphers of World War I, and its eventual break by Georges Painvin is a landmark in the history of cryptanalysis. Painvin's analysis exploited the fact that the columnar transposition produces columns of slightly different lengths when the message length is not a multiple of the key length, which leaks information about the key length.
The ADFGVX cipher is a useful teaching example because it combines two fundamental cryptographic primitives: substitution (the fractionation grid) and transposition (the columnar stage). This combination is the same pattern used by modern block ciphers, which alternate substitution and permutation rounds. The ADFGVX cipher is a single round of this pattern, while AES uses ten or more rounds.
The fractionation stage is also a useful teaching example of how to flatten letter frequencies. The fractionated output has a roughly uniform distribution of ADFGVX letters, which means single character frequency analysis is useless. The transposition stage then breaks the bigram structure that would otherwise reveal the fractionation.
In capture the flag events, the ADFGVX cipher is sometimes used as a multi-stage puzzle that requires the solver to recognize the fractionation and transposition stages separately. The hint is usually a ciphertext that contains only the six letters A, D, F, G, V, and X, which is a strong indicator of an ADFGVX cipher.
The ADFGVX cipher is also a useful demonstration of the principle of diffusion. The transposition stage diffuses the fractionated letters across the ciphertext, so that a single plaintext letter affects multiple ciphertext letters. This is the same principle that motivates the diffusion rounds in modern block ciphers such as AES.
Conclusion
The ADFGVX cipher combines a 6 by 6 fractionation grid with a keyed columnar transposition. We built the grid, fractionated the plaintext into ADFGVX pairs, transposed the fractionated output, and reversed the process for decryption. Next you should study the ADFGX cipher (the predecessor with a 5 by 5 grid), the Bifid cipher (which uses fractionation without transposition), and the Trifid cipher (which uses a 3 by 3 by 3 cube instead of a 5 by 5 grid).
Comments
Comments
Post a Comment