
/**
 * Title:        El Gamal Busting System<p>
 * Description:  <p>
 * Copyright:    Copyright (c) Dr. Brooke Stephens, Jeffrey Walton<p>
 * Company:      CMSC 443, UMBC<p>
 * NOTE: The file named "in.txt" contains the cipher-text and should be located
 * in the same directory as ElGamal.class, otherwise "in.txt" should be the
 * absolute path to the cipher-text file.  Change the file names to suite
 * your taste<p>
 * @author Dr. Brooke Stephens, Jeffrey Walton
 * @version 1.0
 */

import java.math.BigInteger;
import java.util.*;
import java.io.*;
import stephens.DLP;
public class ElGamal {

  // Input (cipher) and output (plain) files
  //   Change to suite your taste.
  public static String in = "in.txt";
  public static String out = "out.txt";

  public ElGamal() { }

  public static void main (String[] argv ) throws IOException {

    // Test from CMSC 443 Class notes
    //   Verify that we calculate a = 309
    // BigInteger alpha = new BigInteger("3");
    // BigInteger beta = new BigInteger("525");
    // BigInteger p = new BigInteger("809");
    // Note:  This example does not need the last
    //   decryption ( char c = number / 256 ... ).
    //   View the results before the last round.

    // Mollin textbook example, page 143.
    //   in.txt should have the following entry:
    //   "1664, 1241"
    //   Note also that in Mollin's example, a = 1009
    //   We find another solution (a = 121).  This does
    //   not affect the decryption.  The answer we should
    //   get is 1483 (which we do infact recover).
    // Note:  The Mollin example does not need the last
    //   decryption ( char c = number / 256 ... ).
    //   View the results before the last round.
    // BigInteger alpha = new BigInteger("6");
    // BigInteger beta = new BigInteger("1729");
    // BigInteger p = new BigInteger("1777");

    // Spring 2001 Easy Cipher
    BigInteger alpha = new BigInteger("726659");
    BigInteger beta = new BigInteger("143198");
    BigInteger p = new BigInteger("875759");

    System.out.println( "Solving Discrete Lop Problem..." );

    DLP problem = new DLP(alpha, beta, p);
    BigInteger solution = problem.SolveDLP();

    System.out.println("\nProblem is " + alpha + "^a mod " + p + " = " + beta );
    System.out.println("  Solution is " + alpha + "^" + solution + " mod " + p + " = " + beta );

    System.out.println("\nVerifying Solution...");
    BigInteger verify = alpha;
               verify = verify.modPow( solution, p );
    System.out.println("  Original beta is " + beta);
    System.out.println("  Calculated beta is " + verify);

    if( 0 == beta.compareTo(verify) ) {
      System.out.println("\nSolution verified.");
      System.out.println("  Private exponent 'a' is " + solution );
    } else {
      System.out.println("\nError - Solution not verified.");
    }

    System.out.println("\nPerforming El Gamal decryption of " + in + "...");
    // Shamelessly ripped from Thomas long's RSA code
    // Modified with a string tokenizer and output file
    //   (and of course El Gamal decryption)
    DataInput  in_file  = new DataInputStream(new FileInputStream(in));
    BigInteger beta_inv_a;
    BigInteger gamma;

    // Used for final unwind - not part of El Gamal
    Vector cipher = new Vector();

    // Reads a line of (beta, gamma) pairs
    String     cipher_text;

    // Read the file
    while( null != ( cipher_text = in_file.readLine() ) ) {

      // The lines we read are (beta, gamma) pairs
      StringTokenizer st = new StringTokenizer(cipher_text, " \t\n\r");

      // Break out the values
      beta_inv_a = new BigInteger( st.nextToken() );
      gamma      = new BigInteger( st.nextToken() );

      // 'a' is solution from above
      beta_inv_a = beta_inv_a.modPow(solution, p);

      // Finally, calculate the inverse
      beta_inv_a = beta_inv_a.modInverse(p);

      BigInteger temp = beta_inv_a.multiply(gamma);
      temp = temp.mod(p);

      // Place the value into the cipher vector
      cipher.add(new Integer(temp.intValue()) );

    } // End ReadFile()

    // We are almost there.  Dr. Stephens' has one
    //   last trick up his sleeve.  This part is
    //   not part of El Gamal.
    String plain_text = new String();
    
    //System.out.println("\nPerforming final decryption of " + in + "...");
    System.out.println("\nthese are ASCII couplets\n");
    for ( int i = 0; i < cipher.size(); i++ ) {
     int number = ((Integer)cipher.get(i)).intValue();
     System.out.println(number+"  \n");
    //  char second = (char) ( number / 256  );
    // char first  = (char) ( number - second * 256 );

    // plain_text += first;
    // plain_text += second;

      // Uncomment if you want to see the couplets
      // System.out.println( first + " " + second );
    }

    // Regergitate to the Screen
    //System.out.println( "\nRecovered plain text:" );
    //System.out.println( plain_text );

    // Finally, write the recoverd plain text to a file
    DataOutput out_file = new DataOutputStream(new FileOutputStream(out));
    out_file.writeBytes( plain_text );

  } // End main ()

} // End class ElGamal

