/* * ***************************************** * This class: RSA * Main class: Encryption * Using a predetermined public/private keypair (no current plans to write * a key generator), this is the encryption box. * ******************************************* * File: rsa.java * $id */ import java.io.*; import java.lang.*; import java.math.*; /** * Handles encryption and decryption with a basic RSA algorithm of text already * entered by the user and stored in Text. */ public class RSA { public static final int chunkSize = 3; // how much it encrypts at once static int leftPosition = 0; // index within the text block static BigInteger number = BigInteger.ZERO; // what holds the number in progress static BigInteger temp[] = {BigInteger.ZERO, BigInteger.ZERO}; // use in decryption static StringBuffer output = new StringBuffer(); /** * Called by Encryption when the user wants to encrypt. Manages delegation * of tasks to other methods in this class and in Text, as appropriate. * * @see Text.addMuck * @see Text.unpackPart * @see blockToNumber * @see theEncryptMath * @see Text.concatenateToCipher */ // umbrella activity public static void encrypt() { if (Encryption.debug) System.out.println("number " + number); Encryption.currentCase.addMuck(); while (leftPosition < Encryption.currentCase.plainBlock.length()) { number = BigInteger.ZERO; output.delete (0, output.length()); // clear the buffer to Text Encryption.currentCase.unpackPart(leftPosition); blockToNumber(); theEncryptMath(); Encryption.currentCase.concatenateToCipher(output.toString()); leftPosition += chunkSize; } } /** * Called by Encryption when the user wants to decrypt. Manages delegation * of tasks to other methods in this class and in Text, as appropriate. * * @see Text.pullFromCipherBlock * @see theDecryptMath * @see backToText * @see Text.concatenateToPlain */ // other umbrella activity public static void decrypt() { while (leftPosition < Encryption.currentCase.cipherBlock.length()) { Encryption.currentCase.pullFromCipherBlock (Key.semiprimeLength, leftPosition); number = BigInteger.valueOf(Encryption.currentCase.cipherSegment); theDecryptMath(); backToText(); Encryption.currentCase.concatenateToPlain(); leftPosition += Key.semiprimeLength; } } /** * Requests letter values from Text, then stores the numerical value of the * text chunk in the variable number. Called by encrypt. * * @see Text.toASCIIValue */ static void blockToNumber(){ int chunkValue = 0; for (int i = 0; i < chunkSize; i++) { chunkValue += Encryption.currentCase.toASCIIValue(i) * Math.pow(256, i); if (Encryption.debug) System.out.println("blockToNumber " + chunkValue); } number = number.add(BigInteger.valueOf((long)chunkValue)); if (Encryption.debug) System.out.println("number " + number); } /** * Converts plaintext number to ciphertext output. Also checks that the * output is the correct length. Called by encrypt. * * @see checkDigits */ static void theEncryptMath(){ number = number.modPow(Key.exponent, Key.semiprime); if (Encryption.debug) System.out.println("theEncryptMath " + number); output.append(number.toString()); if (Encryption.debug) System.out.println("output " + output); checkDigits(); } /** * Converts ciphertext number to plaintext number. Called by decrypt. */ static void theDecryptMath(){ // modPow cipher number with decrypting exponent number = number.modPow(Key.dexponent, Key.semiprime); if (Encryption.debug) System.out.println("number " + number); } /** * Takes the plaintext number and pushes digit values over to Text to be * added to an array of plaintext characters. Called by decrypt. * * @see Text.toASCIIChar */ static void backToText(){ // find quotient with divisor 256**(chunkSize - 1) give this to Text to // put in plainArray last column. Remainder becomes new dividend. // Then, 256**(chunkSize - 2) with the same thing, ending at 256**0. temp[0] = BigInteger.ZERO; temp[1] = BigInteger.ZERO; if (Encryption.debug) System.out.println("temp " + temp[0] + " " + temp[1]); if (Encryption.debug) System.out.println("number " + number); for (int i = (chunkSize - 1); i >= 0; i--){ if (Encryption.debug) System.out.println("index " + i); temp = number.divideAndRemainder(BigInteger.valueOf((long)Math.pow(256, i))); if (Encryption.debug) System.out.println("temp " + temp[0] + " " + temp[1]); Encryption.currentCase.toASCIIChar(temp[0].intValue(), i); number = temp[1]; } } /** * Makes sure that the StringBuffer representation of the ciphernumber is * the correct length, according to the length of the semiprime in use, * and prepends a 0 if too short. Called by theEncryptMath. */ static void checkDigits(){ // Checks that all output strings are as long as the semiprime. // If not, prepends (which should be a method) a "0". while (output.length() < Key.semiprimeLength) { output.insert(0, 0); if (Encryption.debug) System.out.println("short a digit "+ output); } if (output.length() > Key.semiprimeLength) { System.out.print("output too long. return to continue: "); try{ Encryption.in.readLine(); } catch (IOException e) { } } if (Encryption.debug) System.out.println("digits checked"); } /** * Called by Encryption when beginning a new loop to clear the variables. */ static void clearAll(){ // resets values leftPosition = 0; output.delete(0, output.length()); number = BigInteger.ZERO; if (Encryption.debug) { System.out.println("cleared? l " + leftPosition + " o " + output + " n " + number); } } }