/* * ************************************************** * This attempts to attack the RSA algorithm in a very simple manner. * * ************************** * File: AttackRSA.java * This class: AttackRSA * Main class: Encryption * * $id * * ***************************************************************************** */ import java.lang.*; import java.math.*; import java.io.*; /** * This class handles attacking RSA as entered by the user. It contains all * methods of attack, with each form of attack in its own void method. * */ class AttackRSA { /** * Guides the user through choosing an attack method, and transfers * the user to the appropriate attack. * * @throws NumberFormatException If cannot properly parse user entry * @throws WrongInputLengthException If chosenPlainText gets invalid input * @throws IOException If readLine fails */ static void attack() throws NumberFormatException, WrongInputLengthException, IOException { int choice; while (true) { // verbose section System.out.println("\n Enter 1 to try to factor the semiprime " + "using Pollard's p - 1 factorization"); System.out.println(" algorithm."); System.out.println(" Enter 2 to discover the plaintext of one " + Key.semiprimeLength + "-long segment using a chosen "); System.out.println(" plaintext attack."); System.out.println(" Or, enter 0 to go back to the main menu."); System.out.print(" Choose your attack method: "); // user triage choice = Integer.parseInt(Encryption.in.readLine()); switch (choice) { case 0: return; case 1: pollardPMinusOne(); break; case 2: chosenPlainText(); break; default: Encryption.badUser(); return; } } } /** * Takes a pre-existing semiprime from Key and tries to factor it using * Pollard's p-1 factorization algorithm. Prints result to user. * * @see Key */ static void pollardPMinusOne() { // adapted from: Cryptography Theory and Practice, 3d, // Douglas R. Stinson, p. 190. BigInteger a = new BigInteger("2"); int B = 23; // index of that number in Prime BigInteger d = BigInteger.ZERO; for (int i = 0; i <= B; i++){ a = a.modPow(Prime.thisPrime(i), Key.semiprime); } d = Key.semiprime.gcd(a.subtract(BigInteger.ONE)); if ((BigInteger.ONE.compareTo(d) + d.compareTo(Key.semiprime)) == -2) { System.out.println(" " + d); System.out.println(" is a divisor of the semiprime."); } else { System.out.println(" Pollard's algorithm did not work here."); } } /** * Requests from the user one chunk of ciphertext and discovers what three * letters were encrypted. Prints result to user. * * @throws NumberFormatException If user inputs not an integer * @throws WrongInputLengthException If user inputs incorrect length number * @throws IOException If input or output fails */ static void chosenPlainText() throws NumberFormatException, WrongInputLengthException, IOException { System.out.print("\n Enter the " + Key.semiprimeLength + "-digit " + "integer: "); BigInteger target = new BigInteger(Encryption.in.readLine()); if (Encryption.debug) System.out.println(" target " + target + " " + target.intValue()); //test length if (target.compareTo(Key.semiprime) > 0) { if (Encryption.debug) System.out.println("tested, failed size"); throw new WrongInputLengthException(); } BigInteger temp = BigInteger.ZERO; int i, j, k; StringBuffer result = new StringBuffer(); // attack here // assumes very small numbers and only three at a time -- hard-coded in if(Encryption.debug) System.out.println(" starting chosen plaintext"); for (i = 32; i <= 126; i++) { for (j = 32; j <= 126; j++) { for (k = 32; k <= 126; k++) { temp = BigInteger.valueOf(i + (j * 256) + (k * 65536)); temp = temp.modPow(Key.exponent, Key.semiprime); if (temp.equals(target)) { result.insert(0, (char)i); System.out.print("\n The plaintext was: "); // mixing the print because otherwise it shows numbers System.out.println(result.toString() + (char)j + (char)k); if (Encryption.debug) { System.out.println("ints " + i + " " + j + " " + k); } return; } } } } System.out.println("\n We could not find plaintext for your entry."); } }