4
\$\begingroup\$

I've implemented the cryptographic method of the Fleissner-grille aka Turning-grille .

Here's the code:

import java.util.Scanner; import java.util.Random; public class fleissner { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); Scanner scanner2 = new Scanner(System.in); System.out.println("Enter text without spaces:"); String text = scanner2.nextLine(); /*In case the text has less than 36 characters, the String gets filled up with "x"*/ if(text.length()<36) { while(text.length()<36) { text = text + "x"; } } //Case that text is too long if(text.length() != 36){ text = substring(text, 0, 36); System.out.println("Text too long. The following part of the text will be encrypted: " + text); } char[][] out = encrypt(text); for (int line = 0; line < out.length; line++) { for (int column = 0; column < out[line].length; column++) { System.out.print(out[line][column] + " "); } System.out.println(); } } //This method rotates the "grille" clockwise 45 degrees public static int[][] rotate(int[][] a1) { int[][] rotated = {{a1[5][0],a1[4][0],a1[3][0],a1[2][0],a1[1][0],a1[0][0]}, {a1[5][1],a1[4][1],a1[3][1],a1[2][1],a1[1][1],a1[0][1]}, {a1[5][2],a1[4][2],a1[3][2],a1[2][2],a1[1][2],a1[0][2]}, {a1[5][3],a1[4][3],a1[3][3],a1[2][3],a1[1][3],a1[0][3]}, {a1[5][4],a1[4][4],a1[3][4],a1[2][4],a1[1][4],a1[0][4]}, {a1[5][5],a1[4][5],a1[3][5],a1[2][5],a1[1][5],a1[0][5]} }; return rotated; } //This method creates a random grille public static int[][] creategrille() { int[][] a2 = { {(int)((Math.random()) * 4 + 1),(int)((Math.random()) * 4 + 1),(int)((Math.random()) * 4 + 1)}, {(int)((Math.random()) * 4 + 1),(int)((Math.random()) * 4 + 1),(int)((Math.random()) * 4 + 1)}, {(int)((Math.random()) * 4 + 1),(int)((Math.random()) * 4 + 1),(int)((Math.random()) * 4 + 1)} }; int[][] a3 = { {(a2[2][0])%4+1,(a2[1][0])%4+1,(a2[0][0])%4+1}, {(a2[2][1])%4+1,(a2[1][1])%4+1,(a2[0][1])%4+1}, {(a2[2][2])%4+1,(a2[1][2])%4+1,(a2[0][2])%4+1} }; int[][] a4 = { {(a3[2][0])%4+1,(a3[1][0])%4+1,(a3[0][0])%4+1}, {(a3[2][1])%4+1,(a3[1][1])%4+1,(a3[0][1])%4+1}, {(a3[2][2])%4+1,(a3[1][2])%4+1,(a3[0][2])%4+1} }; int[][] a5 = { {(a4[2][0])%4+1,(a4[1][0])%4+1,(a4[0][0])%4+1}, {(a4[2][1])%4+1,(a4[1][1])%4+1,(a4[0][1])%4+1}, {(a4[2][2])%4+1,(a4[1][2])%4+1,(a4[0][2])%4+1} }; int[][] a1 = { {a2[0][0],a2[0][1],a2[0][2],a3[0][0],a3[0][1],a3[0][2]}, {a2[1][0],a2[1][1],a2[1][2],a3[1][0],a3[1][1],a3[1][2]}, {a2[2][0],a2[2][1],a2[2][2],a3[2][0],a3[2][1],a3[2][2]}, {a5[0][0],a5[0][1],a5[0][2],a4[0][0],a4[0][1],a4[0][2]}, {a5[1][0],a5[1][1],a5[1][2],a4[1][0],a4[1][1],a4[1][2]}, {a5[2][0],a5[2][1],a5[2][2],a4[2][0],a4[2][1],a4[2][2]} }; System.out.println("The grille:"); for (int line = 0; line < a1.length; line++) { for (int column = 0; column < a1[line].length; column++) { System.out.print(a1[line][column] + " "); } System.out.println(); } System.out.println(""); System.out.println("Program is using '1' as holes in the grille."); System.out.println(""); return a1; } public static char[][] encrypt(String text) { int[][] a1 = creategrille(); /*The text now gets split up to substrings with length 9. Then the grille gets filled up with the chars.*/ String text1 = substring(text, 0, 9); int[] ar = {0,9,18,27,36}; char[][] out = new char[6][6]; int i = 0; while(i<4) { int a = 0; int b = 0; int x = 0; while (x < text1.length()) { if(a1[a][b]==1){ out[a][b] = text1.charAt(x); x=x+1; if (b<5){ b=b+1; } else if(a<5){ a=a+1; b=0; } } else if (b<5){ b=b+1; } else if(a<5){ a=a+1; b=0; } } i = i+1; int m = ar[i]; int n = m+9; text1 = substring(text, m, n); a1 = rotate(a1); } return out; } //Method to divide String into smaller substrings. public static String substring(String str, int start, int end) { String out = ""; if (start > end) { return out; } if (start < 0) { start = 0; } if (end > str.length() - 1) { end = str.length(); } while (start < end) { out = out + str.charAt(start); start = start + 1; } return out; } } 

My question now is: How to improve my code? Especially I am interested in improving the creategrille method, but I would also appreciate suggestions to other parts of the code.

\$\endgroup\$
2
  • \$\begingroup\$ This is of course just for practice, but cryptography requires secure random numbers, sensibly implemented by the SecureRandom class (and underlying implementations) within Java. \$\endgroup\$ Commented Jan 28, 2020 at 0:04
  • \$\begingroup\$ Oh, thanks for the hint. I didn't knew there's an extra class for that. \$\endgroup\$ Commented Jan 28, 2020 at 6:21

2 Answers 2

3
\$\begingroup\$

Some advice about Java code :

All the Java classes have names beginning with uppercase letter, so instead of fleissner you have to rename your class Fleissner.

The String java class contains a method called substring so you haven't to redefine it. Your method creategrille can be simplified using matrix properties to avoid writing of all elements of matrix, let's start from the begin: you defined the matrix a2 in this way:

int[][] a2 = { {(int)((Math.random()) * 4 + 1),(int)((Math.random()) * 4 + 1),(int)((Math.random()) * 4 + 1)}, {(int)((Math.random()) * 4 + 1),(int)((Math.random()) * 4 + 1),(int)((Math.random()) * 4 + 1)}, {(int)((Math.random()) * 4 + 1),(int)((Math.random()) * 4 + 1),(int)((Math.random()) * 4 + 1)} }; 

This is a matrix that can be rewritten like this:

final int n = 3; int[][] a2 = new int[n][n]; for (int i = 0; i < n; ++i) { for(int j = 0; j < n; ++j) { a2[i][j] = (int)((Math.random()) * 4 + 1); } } 

I defined a final n variable containing the number of rows that will not change later in the method. You defined three a3, a4, a5 in the following way:

int[][] a3 = { {(a2[2][0])%4+1,(a2[1][0])%4+1,(a2[0][0])%4+1}, {(a2[2][1])%4+1,(a2[1][1])%4+1,(a2[0][1])%4+1}, {(a2[2][2])%4+1,(a2[1][2])%4+1,(a2[0][2])%4+1} }; int[][] a4 = { {(a3[2][0])%4+1,(a3[1][0])%4+1,(a3[0][0])%4+1}, {(a3[2][1])%4+1,(a3[1][1])%4+1,(a3[0][1])%4+1}, {(a3[2][2])%4+1,(a3[1][2])%4+1,(a3[0][2])%4+1} }; int[][] a5 = { {(a4[2][0])%4+1,(a4[1][0])%4+1,(a4[0][0])%4+1}, {(a4[2][1])%4+1,(a4[1][1])%4+1,(a4[0][1])%4+1}, {(a4[2][2])%4+1,(a4[1][2])%4+1,(a4[0][2])%4+1} }; 

Probably you made a cut and paste to define these matrices: the code can be simplified defining an helper function to create matrix and then call the function like the example code below:

private static int[][] getMatrix(int[][] original) { final int n = original.length; int[][] created = new int[n][n]; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { created[i][j] = original[n - i - 1][i] % 4 + 1; } } return created; } //inside your creategrille method int[][] a3 = getMatrix(a2); int[][] a4 = getMatrix(a3); int[][] a5 = getMatrix(a4); 

Finally you can create your matrix a1 composed of the four matrices, your code is the following:

int[][] a1 = { {a2[0][0],a2[0][1],a2[0][2],a3[0][0],a3[0][1],a3[0][2]}, {a2[1][0],a2[1][1],a2[1][2],a3[1][0],a3[1][1],a3[1][2]}, {a2[2][0],a2[2][1],a2[2][2],a3[2][0],a3[2][1],a3[2][2]}, {a5[0][0],a5[0][1],a5[0][2],a4[0][0],a4[0][1],a4[0][2]}, {a5[1][0],a5[1][1],a5[1][2],a4[1][0],a4[1][1],a4[1][2]}, {a5[2][0],a5[2][1],a5[2][2],a4[2][0],a4[2][1],a4[2][2]} }; 

Your matrix is composed like this:

a2 a3 a5 a4 

Using an helper function you can generate the four pieces of your matrix and after join them in the final matrix like the code below with an helper function f:

private static void f(int[][] a1, int[][] piece, int x, int y) { final int n = piece.length; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { a1[x + i][y + j] = piece[i][j]; } } } //inside your creategrille method int[][]a1 = new int[n * 2][n * 2]; f(a1, a2, 0, 0); f(a1, a3, 0, n); f(a1, a5, n, 0); f(a1, a4, n, n); 

Same approach for rotate method, instead of :

public static int[][] rotate(int[][] a1) { int[][] rotated = {{a1[5][0],a1[4][0],a1[3][0],a1[2][0],a1[1][0],a1[0][0]}, {a1[5][1],a1[4][1],a1[3][1],a1[2][1],a1[1][1],a1[0][1]}, {a1[5][2],a1[4][2],a1[3][2],a1[2][2],a1[1][2],a1[0][2]}, {a1[5][3],a1[4][3],a1[3][3],a1[2][3],a1[1][3],a1[0][3]}, {a1[5][4],a1[4][4],a1[3][4],a1[2][4],a1[1][4],a1[0][4]}, {a1[5][5],a1[4][5],a1[3][5],a1[2][5],a1[1][5],a1[0][5]} }; return rotated; } 

This can be simplified like below:

public static int[][] rotate(int[][] a1) { final int n = 6; int[][] rotated = new int[n][n]; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { rotated[i][j] = a1[n - j - 1][i]; } } return rotated; } 

When you write code, try put spaces between operands and operator , this improves readibility of code.

\$\endgroup\$
1
  • \$\begingroup\$ That really helps me to improve the code, especially the creategrille-method. Thanks very much! \$\endgroup\$ Commented Dec 11, 2019 at 20:54
2
\$\begingroup\$

1) The variable "scanner" is not used.

Scanner scanner = new Scanner(System.in) 

2) Instead of building a string in a loop (padding), I suggest that you use a java.lang.StringBuilder

 StringBuilder stringBuilder = new StringBuilder(scanner2.nextLine()); /*In case the text has less than 36 characters, the String gets filled up with "x"*/ while (stringBuilder.length() < 36) { stringBuilder.append('x'); } 

3) Instead of concatening a string in the java.io.PrintStream#println(java.lang.String), you can use java.io.PrintStream#printf(java.lang.String, java.lang.Object...) Instead.

 //[...] //Case that text is too long if (textLength != 36) { text = substring(text, 0, 36); System.out.printf("Text too long. The following part of the text will be encrypted: %s\n", text); } //[...] 

4) In the rotate method, you can directly return the array.

 //This method rotates the "grille" clockwise 45 degrees public static int[][] rotate(int[][] a1) { return new int[][] { { a1[5][0], a1[4][0], a1[3][0], a1[2][0], a1[1][0], a1[0][0] }, { a1[5][1], a1[4][1], a1[3][1], a1[2][1], a1[1][1], a1[0][1] }, { a1[5][2], a1[4][2], a1[3][2], a1[2][2], a1[1][2], a1[0][2] }, { a1[5][3], a1[4][3], a1[3][3], a1[2][3], a1[1][3], a1[0][3] }, { a1[5][4], a1[4][4], a1[3][4], a1[2][4], a1[1][4], a1[0][4] }, { a1[5][5], a1[4][5], a1[3][5], a1[2][5], a1[1][5], a1[0][5] } }; } 

5) In the creategrille method, i suggest that you create a method to generate the expression (int) ((Math.random()) * 4 + 1)

 //This method creates a random grille public static int[][] creategrille() { //[...] int[][] a2 = { { generateRandomTimeFourPlusOne(), generateRandomTimeFourPlusOne(), generateRandomTimeFourPlusOne() }, { generateRandomTimeFourPlusOne(), generateRandomTimeFourPlusOne(), generateRandomTimeFourPlusOne() }, { generateRandomTimeFourPlusOne(), generateRandomTimeFourPlusOne(), generateRandomTimeFourPlusOne() } }; //[...] } //[...] private static int generateRandomTimeFourPlusOne() { return (int) ((Math.random()) * 4 + 1); } //[...] 

6) In the substring method, the out variable is useless, return directly an empty String in the first check and use a java.lang.StringBuilder in the loop; to build the result.

 public static String substring(String str, int start, int end) { if (start > end) { return ""; } if (start < 0) { start = 0; } if (end > str.length() - 1) { end = str.length(); } StringBuilder out = new StringBuilder(); while (start < end) { out.append(str.charAt(start)); start = start + 1; } return out.toString(); } 

7) In my opinion, you should rename the method substring to safeSubstring.

Edited code

 public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("Enter text without spaces:"); StringBuilder stringBuilder = new StringBuilder(scanner.nextLine()); /*In case the text has less than 36 characters, the String gets filled up with "x"*/ while (stringBuilder.length() < 36) { stringBuilder.append('x'); } String text = stringBuilder.toString(); //Case that text is too long if (text.length() != 36) { text = safeSubstring(text, 0, 36); System.out.println("Text too long. The following part of the text will be encrypted: " + text); } char[][] out = encrypt(text); for (int line = 0; line < out.length; line++) { for (int column = 0; column < out[line].length; column++) { System.out.print(out[line][column] + " "); } System.out.println(); } } //This method rotates the "grille" clockwise 45 degrees public static int[][] rotate(int[][] a1) { return new int[][] { { a1[5][0], a1[4][0], a1[3][0], a1[2][0], a1[1][0], a1[0][0] }, { a1[5][1], a1[4][1], a1[3][1], a1[2][1], a1[1][1], a1[0][1] }, { a1[5][2], a1[4][2], a1[3][2], a1[2][2], a1[1][2], a1[0][2] }, { a1[5][3], a1[4][3], a1[3][3], a1[2][3], a1[1][3], a1[0][3] }, { a1[5][4], a1[4][4], a1[3][4], a1[2][4], a1[1][4], a1[0][4] }, { a1[5][5], a1[4][5], a1[3][5], a1[2][5], a1[1][5], a1[0][5] } }; } //This method creates a random grille public static int[][] creategrille() { int[][] a2 = { { generateRandomTimeFourPlusOne(), generateRandomTimeFourPlusOne(), generateRandomTimeFourPlusOne() }, { generateRandomTimeFourPlusOne(), generateRandomTimeFourPlusOne(), generateRandomTimeFourPlusOne() }, { generateRandomTimeFourPlusOne(), generateRandomTimeFourPlusOne(), generateRandomTimeFourPlusOne() } }; int[][] a3 = { { (a2[2][0]) % 4 + 1, (a2[1][0]) % 4 + 1, (a2[0][0]) % 4 + 1 }, { (a2[2][1]) % 4 + 1, (a2[1][1]) % 4 + 1, (a2[0][1]) % 4 + 1 }, { (a2[2][2]) % 4 + 1, (a2[1][2]) % 4 + 1, (a2[0][2]) % 4 + 1 } }; int[][] a4 = { { (a3[2][0]) % 4 + 1, (a3[1][0]) % 4 + 1, (a3[0][0]) % 4 + 1 }, { (a3[2][1]) % 4 + 1, (a3[1][1]) % 4 + 1, (a3[0][1]) % 4 + 1 }, { (a3[2][2]) % 4 + 1, (a3[1][2]) % 4 + 1, (a3[0][2]) % 4 + 1 } }; int[][] a5 = { { (a4[2][0]) % 4 + 1, (a4[1][0]) % 4 + 1, (a4[0][0]) % 4 + 1 }, { (a4[2][1]) % 4 + 1, (a4[1][1]) % 4 + 1, (a4[0][1]) % 4 + 1 }, { (a4[2][2]) % 4 + 1, (a4[1][2]) % 4 + 1, (a4[0][2]) % 4 + 1 } }; int[][] a1 = { { a2[0][0], a2[0][1], a2[0][2], a3[0][0], a3[0][1], a3[0][2] }, { a2[1][0], a2[1][1], a2[1][2], a3[1][0], a3[1][1], a3[1][2] }, { a2[2][0], a2[2][1], a2[2][2], a3[2][0], a3[2][1], a3[2][2] }, { a5[0][0], a5[0][1], a5[0][2], a4[0][0], a4[0][1], a4[0][2] }, { a5[1][0], a5[1][1], a5[1][2], a4[1][0], a4[1][1], a4[1][2] }, { a5[2][0], a5[2][1], a5[2][2], a4[2][0], a4[2][1], a4[2][2] } }; System.out.println("The grille:"); for (int line = 0; line < a1.length; line++) { for (int column = 0; column < a1[line].length; column++) { System.out.print(a1[line][column] + " "); } System.out.println(); } System.out.println(""); System.out.println("Program is using '1' as holes in the grille."); System.out.println(""); return a1; } private static int generateRandomTimeFourPlusOne() { return (int) ((Math.random()) * 4 + 1); } public static char[][] encrypt(String text) { int[][] a1 = creategrille(); /*The text now gets split up to substrings with length 9. Then the grille gets filled up with the chars.*/ String text1 = safeSubstring(text, 0, 9); int[] ar = { 0, 9, 18, 27, 36 }; char[][] out = new char[6][6]; int i = 0; while (i < 4) { int a = 0; int b = 0; int x = 0; while (x < text1.length()) { if (a1[a][b] == 1) { out[a][b] = text1.charAt(x); x = x + 1; if (b < 5) { b = b + 1; } else if (a < 5) { a = a + 1; b = 0; } } else if (b < 5) { b = b + 1; } else if (a < 5) { a = a + 1; b = 0; } } i = i + 1; int m = ar[i]; int n = m + 9; text1 = safeSubstring(text1, m, n); a1 = rotate(a1); } return out; } //Method to divide String into smaller substrings. public static String safeSubstring(String str, int start, int end) { if (start > end) { return ""; } if (start < 0) { start = 0; } if (end > str.length() - 1) { end = str.length(); } StringBuilder out = new StringBuilder(); while (start < end) { out.append(str.charAt(start)); start = start + 1; } return out.toString(); } 
\$\endgroup\$
3
  • \$\begingroup\$ Why should I name it "safeSubstring"? Is there a way to make the "creategrille"-method shorter? \$\endgroup\$ Commented Dec 11, 2019 at 14:01
  • \$\begingroup\$ In my opinion, safeSubstring is a better name; since there's already a substring method java.lang.String#substring(int). Your version adds the overflow checks, so that's why. For your other question, you can extract the arrays into methods. There's probably a way to use a loop, but I didn't have the time to try yet. \$\endgroup\$ Commented Dec 11, 2019 at 17:01
  • \$\begingroup\$ Thanks for the clarification. If you have time to try, please let me know your solution! \$\endgroup\$ Commented Dec 11, 2019 at 17:44

You must log in to answer this question.