import java.math.BigInteger; import java.util.StringTokenizer; import java.util.Random; import java.io.*; public class RSA { private static int KEYLENGTH = 50; private static String PUBLICKEYFILENAME = "public-key"; private static String PRIVATEKEYFILENAME = "private-key"; private static Random randGen = new Random ( ); private static void reportError (String errmsg) { System.err.println (errmsg); System.exit (1); } /** * The given file should contain two (big) integers. * Read and return them. * * @param fileName the name of the file containing the key * @return an array containing the two components of the key * @throws IllegalArgumentException if anything is wrong with the file * or the numbers it contains */ private static BigInteger [ ] keyFromFile (String fileName) throws IllegalArgumentException { File f = new File (fileName); if (!f.exists ( )) { throw new IllegalArgumentException ("File doesn't exist."); } BufferedReader in; String str; try { in = new BufferedReader (new InputStreamReader (new FileInputStream (f)) ); str = in.readLine ( ); } catch (Exception e) { throw new IllegalArgumentException ("Can't read from file."); } StringTokenizer tokens = new StringTokenizer (str); if (tokens.countTokens ( ) != 2) { throw new IllegalArgumentException ("Badly formatted key file."); } BigInteger [ ] values = new BigInteger[2]; try { values[0] = new BigInteger (tokens.nextToken ( )); values[1] = new BigInteger (tokens.nextToken ( )); } catch (Exception e) { throw new IllegalArgumentException ("Invalid key."); } if (values[0].compareTo (BigInteger.ONE) == -1 || values[1].compareTo (BigInteger.ONE) == -1) { reportError ("Key contains a negative or zero value."); } return values; } /** * Generate values for the public and private keys, and write them * to the files whose names are defined by the static variables * PUBLICKEYFILENAME and PRIVATEKEYFILENAME. * The length of the prime numbers on which these keys are based * is KEYLENGTH. * * @throws FileNotFoundException actually this should never happen */ protected static void createKeys ( ) throws FileNotFoundException { BigInteger TWO = BigInteger.ONE.add (BigInteger.ONE); StringBuffer s = new StringBuffer (KEYLENGTH); s.append ("1"); for (int k=1; kexp mod n */ protected static BigInteger modPower (BigInteger m, BigInteger exp, BigInteger n) { BigInteger rtn = BigInteger.ONE; while (exp.signum ( ) > 0) { if (exp.testBit (0)) { rtn = rtn.multiply (m).mod (n); } exp = exp.shiftRight (1); m = m.multiply (m).mod (n); } return rtn; } /** * Return the result of converting str to a BigInteger, essentially * using the ASCII codes of the characters of str as "digits". * * @param str the string to convert to a BigInteger * @return the corresponding BigInteger */ private static BigInteger toBigInteger (String str) { byte [ ] asciiValues = str.getBytes ( ); return new BigInteger (asciiValues); } /** * Return the result of converting bigInt to a string, using the bytes * of bigInt as ASCII codes of characters. * * @param bigInt the BigInteger to convert to a string * @return the corresponding string */ private static String toString (BigInteger bigInt) { byte [ ] bytes = bigInt.toByteArray ( ); return new String (bytes); } /** * Command-line arguments are either * -e str [recipient] * which indicates that a string should be encrypted using * the recipient's public key (my public key is the default), or * -d bigInt * which indicates that a big integer should be decrypted * using my private key. * If the string or bigInt argument is "-", it is read from * standard input rather than from the command line. */ public static void main (String [ ] args) throws Exception { if (args.length < 2 || args.length > 3) { reportError ("Usage:\n java RSA -e string [recipient]\n" + "or\n java RSA -d bigInteger"); } if (!args[0].equals ("-e") && !args[0].equals ("-d")) { reportError ("Usage:\n java RSA -e string [recipient]\n" + "or\n java RSA -d bigInteger"); } if (args[0].equals ("-d") && args.length > 2) { reportError ("Usage:\n java RSA -e string [recipient]\n" + "or\n java RSA -d bigInteger"); } if (args[0].equals ("-e")) { // The second argument specifies an ASCII string. // We apply the public key specified as the third argument, // or our own public key if there is no third argument. BigInteger [ ] publicKey = null; if (args.length == 3) { try { publicKey = keyFromFile (args[2]); } catch (Exception e) { reportError (e.getMessage ( ) + "\nCan't read public key."); } } else { try { publicKey = keyFromFile (PUBLICKEYFILENAME); } catch (Exception e) { createKeys ( ); } publicKey = keyFromFile (PUBLICKEYFILENAME); } String msg; if (args[1].equals ("-")) { BufferedReader in = new BufferedReader (new InputStreamReader (System.in)); msg = in.readLine ( ); } else { msg = args[1]; } System.out.println (modPower (toBigInteger (msg), publicKey[0], publicKey[1])); } else { // The second argument specifies a big integer. // We apply our private key to it. BigInteger [ ] privateKey = null; try { privateKey = keyFromFile (PRIVATEKEYFILENAME); } catch (Exception e) { createKeys ( ); } privateKey = keyFromFile (PRIVATEKEYFILENAME); String msg; if (args[1].equals ("-")) { BufferedReader in = new BufferedReader (new InputStreamReader (System.in)); msg = in.readLine ( ); } else { msg = args[1]; } System.out.println (toString (modPower (new BigInteger (msg), privateKey[0], privateKey[1]) )); } } }