import java.security.InvalidKeyException; import java.util.*; import java.io.*; // Brandon Senter & Thomas Le // CS 457: Information Security // Xunhua Wang; 09.27.2015 public class AES_NEW { public static String correctKey = ""; public static void main(String[] args) throws Exception { long startTime = System.currentTimeMillis(); // Scanner in = new Scanner(System.in); String fileName = "Le_Senter.txt"; File out = new File(fileName); if (out.exists() == false) { out.createNewFile(); } // System.out.println("Where to start?"); // int start = in.nextInt(); // // System.out.println("Where to end?"); // int end = in.nextInt(); // // in.close(); // // System.out.println("Starting AES_Decrpytion.java"); decrypt(Integer.parseInt(args[0]), Integer.parseInt(args[1])); long endTime = System.currentTimeMillis(); long totalTime = endTime - startTime; PrintWriter writer = new PrintWriter(fileName, "UTF-8"); writer.println("Correct Key: " + correctKey); writer.println("Total runtime (ms): " + totalTime); writer.close(); // System.out.println("Done."); } public static void decrypt(int start, int end) throws InvalidKeyException { byte[] potentialKey = new byte[16]; potentialKey[15] = 0x03; for (int i = 5; i <= 14; i++) potentialKey[i] = 0x00; for (int i = start; i <= end; i++) { potentialKey[0] = (byte) i; for (int j = 0; j <= 255; j++) { potentialKey[1] = (byte) j; for (int k = 0; k <= 255; k++) { potentialKey[2] = (byte) k; for (int l = 0; l <= 255; l++) { potentialKey[3] = (byte) l; for (int m = 6; m <= 254; m += 8) { potentialKey[4] = (byte) m; // for (byte ki : potentialKey) System.out.print (String.format("%02X", ki & 0xff)); // System.out.println (""); boolean isCorrect = testKey(potentialKey); if (isCorrect) { correctKey = potentialKey.toString(); return; } } // m-loop } // l-loop } // k-loop } // j-loop } // i-loop } // decrypt() public static boolean testKey(byte[] inKey) throws InvalidKeyException { String IV_string = "5BF16CF65F7D2E547AAF6522342C30D8"; String C1_string = "E84811608B52001CDD9FC48334433B6F"; String C2_string = "C87C0B94F6A7747383881E18A6518DDF"; String C3_string = "3E64B928FA5EFC67275D77D18F505335"; String C4_string = "202F8CD7D8984917681CB1686D3239FB"; byte[] iv = hexStringToByteArray(IV_string); byte[] c1 = hexStringToByteArray(C1_string); byte[] c2 = hexStringToByteArray(C2_string); byte[] c3 = hexStringToByteArray(C3_string); byte[] c4 = hexStringToByteArray(C4_string); Object roundKeys = null; roundKeys = Rijndael_Algorithm.makeKey(Rijndael_Algorithm.DECRYPT_MODE, inKey); byte[] returnArray = Rijndael_Algorithm.blockDecrypt2(c1, 0, roundKeys); if (keyCheck(iv, returnArray)) { byte[] returnArray2 = Rijndael_Algorithm.blockDecrypt2(c2, 0, roundKeys); if (keyCheck(returnArray, returnArray2)) { byte[] returnArray3 = Rijndael_Algorithm.blockDecrypt2(c3, 0, roundKeys); if (keyCheck(returnArray2, returnArray3)) { byte[] returnArray4 = Rijndael_Algorithm.blockDecrypt2(c4, 0, roundKeys); if (keyCheck(returnArray3, returnArray4)) return true; } } } return false; } public static boolean keyCheck(byte[] previous, byte[] current) { if (checkASCII(previous, xor(previous, current))) return true; return false; } public static byte[] xor(byte[] previous, byte[] current) { for (int x = 0; x < current.length; x++) { current[x] = (byte) (current[x] ^ previous[x]); } return current; } public static boolean checkASCII(byte[] previous, byte[] current) { for (int y = 0; y < current.length; y++) { if ((current[y] < 32) || (current[y] >= 127)) { continue; } else { return false; } } return true; } public static byte[] hexStringToByteArray(String s) { int len = s.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)); } return data; } }
// package sci.crypt.course.crypto;// import Rijndael_Algorithm;import java.security.SecureRandom;import java.math.BigInteger;import java.io.*;import java.util.*;/** * @author Xunhua Wang (wangxx@jmu.edu) * @date 09/27/2014 * All rights reserved */public class AESExample { public void testAESImplementationTwo () { try { int times = 1000; byte[] inKey = new byte[16]; byte[] cbcIV = new byte[16]; SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); random.nextBytes(inKey); // This generates a random AES-128 key random.nextBytes(cbcIV); // This generates a random IV // populate the plaintext String textString = "abcdefghijklmnop"; byte[] inText = textString.getBytes(); for (int i=0; i < 16; i++) inText[i] = (byte) (inText[i] ^ cbcIV[i]); // According to CBC, this is how we use the IV long time1 = 0, time2 = 0, time3 = 0, time4 = 0; Object roundKeys = null; byte[] cipherText = null; for (int i=0; i < times; i++) // To get more accurate timing results, we have to warm up your CPU a little bit.// This is the whole purpose of this line of code// This warm-up is NOT needed in your programming or real-world applications roundKeys = Rijndael_Algorithm.makeKey (Rijndael_Algorithm.ENCRYPT_MODE, inKey); // Now, we are ready and let's start the business System.out.println (System.getProperty ("line.separator") + "Testing AES implementation two ......"); time1 = System.currentTimeMillis(); // Start the timing clock // // Why do we do this 1000 times? If you choose to measure the time to perform a // single key expansion and encryption, you will always get 0, as this process is too fast // for (int i=0; i < times; i++) { // for measuring time. If you use 1 instead, you will always get 0 in time3 // AES key schedule roundKeys = Rijndael_Algorithm.makeKey (Rijndael_Algorithm.ENCRYPT_MODE, inKey); // AES encryption, the first parameter is 128-bit // plaintext, the second parameter is 0, and the // third parameter is the round keys generated by the // key schedule call cipherText = Rijndael_Algorithm.blockEncrypt2 (inText, 0, roundKeys); } time2 = System.currentTimeMillis(); // end the timing clock time3 = time2 - time1; // This is the time, in milliseconds, elapsed in this 1000 BLOCK encryptions // // Now it is time to decrypt the ciphertext // byte[] recoveredText = null; time1 = System.currentTimeMillis(); // Start the timing clock for (int i=0; i < times; i++) { roundKeys = Rijndael_Algorithm.makeKey (Rijndael_Algorithm.DECRYPT_MODE, inKey); recoveredText = Rijndael_Algorithm.blockDecrypt2 (cipherText, 0, roundKeys); } time2 = System.currentTimeMillis(); // End the timing clock time4 = time2 - time1; // This is the time, in milliseconds, elapsed in this 1000 BLOCK decryptions // How do we know whether the decryption works? We have to check the recovered cleartext for (int i=0; i < 16; i++) recoveredText[i] = (byte) (recoveredText[i] ^ cbcIV[i]); String recoveredString = new String (recoveredText); if (!recoveredString.equals (textString)) { System.out.println ("Decryption does NOT work!"); } else System.out.println ("Decryption worked beautifully and recovered the original plaintext!"); System.out.println ("It takes blockEncrypt2 " + time3 + " milliseconds to run AES-128 key scheduling & ENcryption " + times + " times"); System.out.println ("It takes blockDecrypt2 " + time4 + " milliseconds to run AES-128 key scheduling & DEcryption " + times + " times"); } catch (Exception ex) { ex.printStackTrace(); } } public void testAESSlowerImplementationOne () { try { int times = 1000; byte[] inKey = new byte[16]; byte[] cbcIV = new byte[16]; SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); random.nextBytes(inKey); // This generates a random AES-128 key random.nextBytes(cbcIV); // This generates a random IV // populate the plaintext String textString = "abcdefghijklmnop"; byte[] inText = textString.getBytes(); for (int i=0; i < 16; i++) inText[i] = (byte) (inText[i] ^ cbcIV[i]); // According to CBC, this is how we use the IV long time1 = 0, time2 = 0, time3 = 0, time4 = 0; Object roundKeys = null; byte[] cipherText = null; for (int i=0; i < times; i++) // To get more accurate timing results, we have to warm up your CPU a little bit.// This is the whole purpose of this line of code// This warm-up is NOT needed in your programming or real-world applications roundKeys = Rijndael_Algorithm.makeKey (Rijndael_Algorithm.ENCRYPT_MODE, inKey); // Now, we are ready and let's start the business System.out.println (System.getProperty ("line.separator") + "Testing AES implementation one, which is SLOWER ......"); time1 = System.currentTimeMillis(); // Start the timing clock // // Why do we do this 1000 times? If you choose to measure the time to perform a // single key expansion and encryption, you will always get 0, as this process is too fast // for (int i=0; i < times; i++) { // for measuring time. If you use 1 instead, you will always get 0 in time3 // AES key schedule roundKeys = Rijndael_Algorithm.makeKey (Rijndael_Algorithm.ENCRYPT_MODE, inKey); // AES encryption, the first parameter is 128-bit // plaintext, the second parameter is 0, and the // third parameter is the round keys generated by the // key schedule call cipherText = Rijndael_Algorithm.blockEncrypt (inText, 0, roundKeys); } time2 = System.currentTimeMillis(); // end the timing clock time3 = time2 - time1; // This is the time, in milliseconds, elapsed in this 1000 BLOCK encryptions // // Now it is time to decrypt the ciphertext // byte[] recoveredText = null; time1 = System.currentTimeMillis(); // Start the timing clock for (int i=0; i < times; i++) { roundKeys = Rijndael_Algorithm.makeKey (Rijndael_Algorithm.ENCRYPT_MODE, inKey); // Yes, you have to specify the ENCRYPTION_MODE for this slower implementation recoveredText = Rijndael_Algorithm.blockDecrypt (cipherText, 0, roundKeys); } time2 = System.currentTimeMillis(); // End the timing clock time4 = time2 - time1; // This is the time, in milliseconds, elapsed in this 1000 BLOCK decryptions // How do we know whether the decryption works? We have to check the recovered cleartext for (int i=0; i < 16; i++) recoveredText[i] = (byte) (recoveredText[i] ^ cbcIV[i]); String recoveredString = new String (recoveredText); System.out.println(recoveredString); if (!recoveredString.equals (textString)) { System.out.println ("Decryption does NOT work!"); } else System.out.println ("Decryption worked beautifully and recovered the original plaintext!"); System.out.println ("It takes blockEncrypt " + time3 + " milliseconds to run AES-128 key scheduling & ENcryption " + times + " times"); System.out.println ("It takes blockDecrypt " + time4 + " milliseconds to run AES-128 key scheduling & DEcryption " + times + " times"); } catch (Exception ex) { ex.printStackTrace(); } } public static String convertToString (byte[] data) {char[] _hexArray = {'0', '1', '2', '3', '4', '5','6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};StringBuffer sb = new StringBuffer();for (int i=0; i <data.length; i++) {sb.append("" + _hexArray[(data[i] >> 4) & 0x0f] + _hexArray[data[i] & 0x0f]);}return sb.toString(); } public static void main (String[] args) { System.out.println("Starting..."); System.out.println("..."); try { AESExample aes = new AESExample(); aes.testAESImplementationTwo();aes.testAESSlowerImplementationOne (); } catch (Exception ex) { ex.printStackTrace(); } }}
/** * @author Xunhua Wang (wangxx@jmu.edu). All rights reserved. * @date 09/25/2014 */ public class AES_Structure { public void crack (int start, int end) { byte[] myguessedkey = new byte[16]; for (int i = 0; i < 16; i ++) myguessedkey[i] = (byte) 0x00; // This may be unnecessary but to make sure ... myguessedkey[15] = (byte) 0x03; for (int i = start; i <= end; i++) { for (int j = 0; j <= 255; j++) { for (int k = 0; k <= 255; k++) { for (int x = 0; x <= 255; x++) { for (int y = 6; y <= 255; y+=8) { // Why does y start from 6 and increment by 8? Think! myguessedkey[0] = (byte) i; myguessedkey[1] = (byte) j; myguessedkey[2] = (byte) k; myguessedkey[3] = (byte) x; myguessedkey[4] = (byte) y; // // In my test run, print out myguessedkey to make sure that it is correct // This line of code prints out and slows things down // // TODO: the following two lines should be commented out when you start running your code // for (byte ki : myguessedkey) System.out.print (String.format("%02X", ki & 0xff)); System.out.println (""); // // Next, we will test whether this guessed key is good or not // TODO: YOU need to fill in the details here // boolean isCorrectKey = testOneKey (myguessedkey); if (isCorrectKey) return; } } } } } } // // Method UNFINISHED // public boolean testOneKey (byte[] inKey) { // // Is this key correct? How to find out? // // // Step 0. Prepare the IV and ciphertext blocks // String ivStr = "FEE6CB5BE4BBFC3DC623B8FE9F0006B2"; String c1Str = "C2B8B6A64DB0E2101B147381442C271C"; String c2Str = "33845FD95F0C589680CB822C6A0CB950"; String c3Str = "F4190D6C5D15FC968756DF5E229F32FA"; String c4Str = "C8406CF6E3C812EED825CB15970AFBB7"; byte[] iv = hexStringToByteArray (ivStr); byte[] c1 = hexStringToByteArray (c1Str); byte[] c2 = hexStringToByteArray (c2Str); byte[] c3 = hexStringToByteArray (c3Str); byte[] c4 = hexStringToByteArray (c4Str); // // Step 1. Prepare for the AES round keys // Object aesRoundKeys = null; try { aesRoundKeys = Rijndael_Algorithm.makeKey(Rijndael_Algorithm.DECRYPT_MODE, inKey); } catch (Exception ex) { ex.printStackTrace (); return false; } // // Step 2. Now decrypt ciphertext block 1 _and_ XOR with IV; UNFINISHED // byte[] returnArray = Rijndael_Algorithm.blockDecrypt2(c1, 0, aesRoundKeys); // TODO: XOR with IV and test whether the cleartext block is good or not. If not, return false // Otherwise, continue // // // Step 3. Now decrypt ciphertext block 2 _and_ XOR with c1; UNFINISHED // byte[] returnArray2 = Rijndael_Algorithm.blockDecrypt2(c2, 0, aesRoundKeys); // TODO: XOR with c1 and test whether the cleartext block is good or not. If not, return false // Otherwise, continue // // // Step 4. Now decrypt ciphertext block 3 _and_ XOR with c2; UNFINISHED // byte[] returnArray3 = Rijndael_Algorithm.blockDecrypt2(c3, 0, aesRoundKeys); // TODO: XOR with c2 and test whether the cleartext block is good or not. If not, return false // Otherwise, continue // // // Step 5. Now decrypt ciphertext block 4 _and_ XOR with c3; UNFINISHED // byte[] returnArray4 = Rijndael_Algorithm.blockDecrypt2(c4, 0, aesRoundKeys); // TODO: XOR with c3 and test whether the cleartext block is good or not. If not, return false // Otherwise, found the key; print the key and all four plaintext blocks to a file // // // The following line should be removed after you complete the code // return false; } // // The following method is copied from Medovar and Sharp. Thank them for the code when you get a chance // public static byte[] hexStringToByteArray(String s) { int len = s.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)); } return data; } public static void main (String args[]) { if (args.length < 2) { System.out.println ("Use java AESChallengeCrackerWithFiveLoops start end"); return; } try { int start = Integer.parseInt (args[0]); int end = Integer.parseInt (args[1]); AES_Structure acc = new AES_Structure (); acc.crack (start, end); } catch (Exception ex) { ex.printStackTrace (); } } }
import java.security.InvalidKeyException; import java.util.*; import java.io.*; // Brandon Senter & Thomas Le // CS 457: Information Security // Xunhua Wang; 09.27.2015 public class AES_NEW { public static String correctKey = ""; public static void main(String[] args) throws Exception { long startTime = System.currentTimeMillis(); // Scanner in = new Scanner(System.in); String fileName = "Le_Senter.txt"; File out = new File(fileName); if (out.exists() == false) { out.createNewFile(); } // System.out.println("Where to start?"); // int start = in.nextInt(); // // System.out.println("Where to end?"); // int end = in.nextInt(); // // in.close(); // // System.out.println("Starting AES_Decrpytion.java"); decrypt(Integer.parseInt(args[0]), Integer.parseInt(args[1])); long endTime = System.currentTimeMillis(); long totalTime = endTime - startTime; PrintWriter writer = new PrintWriter(fileName, "UTF-8"); writer.println("Correct Key: " + correctKey); writer.println("Total runtime (ms): " + totalTime); writer.close(); // System.out.println("Done."); } public static void decrypt(int start, int end) throws InvalidKeyException { byte[] potentialKey = new byte[16]; potentialKey[15] = 0x03; for (int i = 5; i <= 14; i++) potentialKey[i] = 0x00; for (int i = start; i <= end; i++) { potentialKey[0] = (byte) i; for (int j = 0; j <= 255; j++) { potentialKey[1] = (byte) j; for (int k = 0; k <= 255; k++) { potentialKey[2] = (byte) k; for (int l = 0; l <= 255; l++) { potentialKey[3] = (byte) l; for (int m = 6; m <= 254; m += 8) { potentialKey[4] = (byte) m; // for (byte ki : potentialKey) System.out.print (String.format("%02X", ki & 0xff)); // System.out.println (""); boolean isCorrect = testKey(potentialKey); if (isCorrect) { correctKey = potentialKey.toString(); return; } } // m-loop } // l-loop } // k-loop } // j-loop } // i-loop } // decrypt() public static boolean testKey(byte[] inKey) throws InvalidKeyException { String IV_string = "5BF16CF65F7D2E547AAF6522342C30D8"; String C1_string = "E84811608B52001CDD9FC48334433B6F"; String C2_string = "C87C0B94F6A7747383881E18A6518DDF"; String C3_string = "3E64B928FA5EFC67275D77D18F505335"; String C4_string = "202F8CD7D8984917681CB1686D3239FB"; byte[] iv = hexStringToByteArray(IV_string); byte[] c1 = hexStringToByteArray(C1_string); byte[] c2 = hexStringToByteArray(C2_string); byte[] c3 = hexStringToByteArray(C3_string); byte[] c4 = hexStringToByteArray(C4_string); Object roundKeys = null; roundKeys = Rijndael_Algorithm.makeKey(Rijndael_Algorithm.DECRYPT_MODE, inKey); byte[] returnArray = Rijndael_Algorithm.blockDecrypt2(c1, 0, roundKeys); if (keyCheck(iv, returnArray)) { byte[] returnArray2 = Rijndael_Algorithm.blockDecrypt2(c2, 0, roundKeys); if (keyCheck(returnArray, returnArray2)) { byte[] returnArray3 = Rijndael_Algorithm.blockDecrypt2(c3, 0, roundKeys); if (keyCheck(returnArray2, returnArray3)) { byte[] returnArray4 = Rijndael_Algorithm.blockDecrypt2(c4, 0, roundKeys); if (keyCheck(returnArray3, returnArray4)) return true; } } } return false; } public static boolean keyCheck(byte[] previous, byte[] current) { if (checkASCII(previous, xor(previous, current))) return true; return false; } public static byte[] xor(byte[] previous, byte[] current) { for (int x = 0; x < current.length; x++) { current[x] = (byte) (current[x] ^ previous[x]); } return current; } public static boolean checkASCII(byte[] previous, byte[] current) { for (int y = 0; y < current.length; y++) { if ((current[y] < 32) || (current[y] >= 127)) { continue; } else { return false; } } return true; } public static byte[] hexStringToByteArray(String s) { int len = s.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)); } return data; } }
// $Id: Rijndael_Algorithm.java,v 1.1.1.1 2005/10/11 16:49:07 ruthap Exp $ // // $Log: Rijndael_Algorithm.java,v $ // Revision 1.1.1.1 2005/10/11 16:49:07 ruthap // My Research Source Code // // Revision 1.1 1998/04/12 Paulo // + optimized methods for the default 128-bit block size. // // Revision 1.0 1998/03/11 Raif // + original version. // // $Endlog$ /* * Copyright (c) 1997, 1998 Systemics Ltd on behalf of * the Cryptix Development Team. All rights reserved. */ // package Rijndael; import java.io.PrintWriter; import java.security.InvalidKeyException; //........................................................................... /** * Rijndael --pronounced Reindaal-- is a variable block-size (128-, 192- and * 256-bit), variable key-size (128-, 192- and 256-bit) symmetric cipher.<p> * * Rijndael was written by <a href="mailto:rijmen@esat.kuleuven.ac.be">Vincent * Rijmen</a> and <a href="mailto:Joan.Daemen@village.uunet.be">Joan Daemen</a>.<p> * * Portions of this code are <b>Copyright</b> © 1997, 1998 * <a href="http://www.systemics.com/">Systemics Ltd</a> on behalf of the * <a href="http://www.systemics.com/docs/cryptix/">Cryptix Development Team</a>. * <br>All rights reserved.<p> * * <b>$Revision: 1.1.1.1 $</b> * @author Raif S. Naffah * @author Paulo S. L. M. Barreto */ public final class Rijndael_Algorithm // implicit no-argument constructor { // Debugging methods and variables //........................................................................... public static int ENCRYPT_MODE = 1; public static int DECRYPT_MODE = 2; public static int BOTH_MODE = 3; static final String NAME = "Rijndael_Algorithm"; static final boolean IN = true, OUT = false; static final boolean DEBUG = Rijndael_Properties.GLOBAL_DEBUG; static final int debuglevel = DEBUG ? Rijndael_Properties.getLevel(NAME) : 0; static final PrintWriter err = DEBUG ? Rijndael_Properties.getOutput() : null; static final boolean TRACE = Rijndael_Properties.isTraceable(NAME); static void debug (String s) { err.println(">>> "+NAME+": "+s); } static void trace (boolean in, String s) { if (TRACE) err.println((in?"==> ":"<== ")+NAME+"."+s); } static void trace (String s) { if (TRACE) err.println("<=> "+NAME+"."+s); } // Constants and variables //........................................................................... static final int BLOCK_SIZE = 16; // default block size in bytes static final int[] alog = new int[256]; static final int[] log = new int[256]; static final byte[] S = new byte[256]; static final byte[] Si = new byte[256]; static final int[] T1 = new int[256]; static final int[] T2 = new int[256]; static final int[] T3 = new int[256]; static final int[] T4 = new int[256]; static final int[] T5 = new int[256]; static final int[] T6 = new int[256]; static final int[] T7 = new int[256]; static final int[] T8 = new int[256]; static final int[] U1 = new int[256]; static final int[] U2 = new int[256]; static final int[] U3 = new int[256]; static final int[] U4 = new int[256]; static final byte[] rcon = new byte[30]; static final int[][][] shifts = new int[][][] { { {0, 0}, {1, 3}, {2, 2}, {3, 1} }, { {0, 0}, {1, 5}, {2, 4}, {3, 3} }, { {0, 0}, {1, 7}, {3, 5}, {4, 4} } }; private static final char[] HEX_DIGITS = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; static byte[][] mixColumnsG = new byte[][] { {2, 3, 1, 1}, {1, 2, 3, 1}, {1, 1, 2, 3}, {3, 1, 1, 2} }; static byte[][] invMixColumnsG = new byte[][] { {(byte)0x0E, (byte)0x0B, (byte)0x0D, (byte)0x09}, {(byte)0x09, (byte)0x0E, (byte)0x0B, (byte)0x0D}, {(byte)0x0D, (byte)0x09, (byte)0x0E, (byte)0x0B}, {(byte)0x0B, (byte)0x0D, (byte)0x09, (byte)0x0E} }; // Static code - to intialise S-boxes and T-boxes //........................................................................... static { long time = System.currentTimeMillis(); if (DEBUG && debuglevel > 6) { System.out.println("Algorithm Name: "+Rijndael_Properties.FULL_NAME); System.out.println("Electronic Codebook (ECB) Mode"); System.out.println(); } int ROOT = 0x11B; int i, j = 0; // // produce log and alog tables, needed for multiplying in the // field GF(2^m) (generator = 3) // alog[0] = 1; for (i = 1; i < 256; i++) { j = (alog[i-1] << 1) ^ alog[i-1]; if ((j & 0x100) != 0) j ^= ROOT; alog[i] = j; } for (i = 1; i < 255; i++) log[alog[i]] = i; byte[][] A = new byte[][] { {1, 1, 1, 1, 1, 0, 0, 0}, {0, 1, 1, 1, 1, 1, 0, 0}, {0, 0, 1, 1, 1, 1, 1, 0}, {0, 0, 0, 1, 1, 1, 1, 1}, {1, 0, 0, 0, 1, 1, 1, 1}, {1, 1, 0, 0, 0, 1, 1, 1}, {1, 1, 1, 0, 0, 0, 1, 1}, {1, 1, 1, 1, 0, 0, 0, 1} }; byte[] B = new byte[] { 0, 1, 1, 0, 0, 0, 1, 1}; // // substitution box based on F^{-1}(x) // int t; byte[][] box = new byte[256][8]; box[1][7] = 1; for (i = 2; i < 256; i++) { j = alog[255 - log[i]]; for (t = 0; t < 8; t++) box[i][t] = (byte)((j >>> (7 - t)) & 0x01); } // // affine transform: box[i] <- B + A*box[i] // byte[][] cox = new byte[256][8]; for (i = 0; i < 256; i++) for (t = 0; t < 8; t++) { cox[i][t] = B[t]; for (j = 0; j < 8; j++) cox[i][t] ^= A[t][j] * box[i][j]; } // // S-boxes and inverse S-boxes // for (i = 0; i < 256; i++) { S[i] = (byte)(cox[i][0] << 7); for (t = 1; t < 8; t++) S[i] ^= cox[i][t] << (7-t); Si[S[i] & 0xFF] = (byte) i; } // // T-boxes // byte[][] G = new byte[][] { {2, 1, 1, 3}, {3, 2, 1, 1}, {1, 3, 2, 1}, {1, 1, 3, 2} }; byte[][] AA = new byte[4][8]; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) AA[i][j] = G[i][j]; AA[i][i+4] = 1; } byte pivot, tmp; byte[][] iG = new byte[4][4]; for (i = 0; i < 4; i++) { pivot = AA[i][i]; if (pivot == 0) { t = i + 1; while ((AA[t][i] == 0) && (t < 4)) t++; if (t == 4) throw new RuntimeException("G matrix is not invertible"); else { for (j = 0; j < 8; j++) { tmp = AA[i][j]; AA[i][j] = AA[t][j]; AA[t][j] = (byte) tmp; } pivot = AA[i][i]; } } for (j = 0; j < 8; j++) if (AA[i][j] != 0) AA[i][j] = (byte) alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255]; for (t = 0; t < 4; t++) if (i != t) { for (j = i+1; j < 8; j++) AA[t][j] ^= mul(AA[i][j], AA[t][i]); AA[t][i] = 0; } } for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) iG[i][j] = AA[i][j + 4]; int s; for (t = 0; t < 256; t++) { s = S[t]; T1[t] = mul4(s, G[0]); T2[t] = mul4(s, G[1]); T3[t] = mul4(s, G[2]); T4[t] = mul4(s, G[3]); s = Si[t]; T5[t] = mul4(s, iG[0]); T6[t] = mul4(s, iG[1]); T7[t] = mul4(s, iG[2]); T8[t] = mul4(s, iG[3]); U1[t] = mul4(t, iG[0]); U2[t] = mul4(t, iG[1]); U3[t] = mul4(t, iG[2]); U4[t] = mul4(t, iG[3]); } // // round constants // rcon[0] = 1; int r = 1; for (t = 1; t < 30; ) rcon[t++] = (byte)(r = mul(2, r)); time = System.currentTimeMillis() - time; if (DEBUG && debuglevel > 8) { System.out.println("=========="); System.out.println(); System.out.println("Static Data"); System.out.println(); System.out.println("S[]:"); for(i=0;i<16;i++) { for(j=0;j<16;j++) System.out.print("0x"+byteToString(S[i*16+j])+", "); System.out.println();} System.out.println(); System.out.println("Si[]:"); for(i=0;i<16;i++) { for(j=0;j<16;j++) System.out.print("0x"+byteToString(Si[i*16+j])+", "); System.out.println();} System.out.println(); System.out.println("iG[]:"); for(i=0;i<4;i++){for(j=0;j<4;j++) System.out.print("0x"+byteToString(iG[i][j])+", "); System.out.println();} System.out.println(); System.out.println("T1[]:"); for(i=0;i<64;i++){for(j=0;j<4;j++) System.out.print("0x"+intToString(T1[i*4+j])+", "); System.out.println();} System.out.println(); System.out.println("T2[]:"); for(i=0;i<64;i++){for(j=0;j<4;j++) System.out.print("0x"+intToString(T2[i*4+j])+", "); System.out.println();} System.out.println(); System.out.println("T3[]:"); for(i=0;i<64;i++){for(j=0;j<4;j++) System.out.print("0x"+intToString(T3[i*4+j])+", "); System.out.println();} System.out.println(); System.out.println("T4[]:"); for(i=0;i<64;i++){for(j=0;j<4;j++) System.out.print("0x"+intToString(T4[i*4+j])+", "); System.out.println();} System.out.println(); System.out.println("T5[]:"); for(i=0;i<64;i++){for(j=0;j<4;j++) System.out.print("0x"+intToString(T5[i*4+j])+", "); System.out.println();} System.out.println(); System.out.println("T6[]:"); for(i=0;i<64;i++){for(j=0;j<4;j++) System.out.print("0x"+intToString(T6[i*4+j])+", "); System.out.println();} System.out.println(); System.out.println("T7[]:"); for(i=0;i<64;i++){for(j=0;j<4;j++) System.out.print("0x"+intToString(T7[i*4+j])+", "); System.out.println();} System.out.println(); System.out.println("T8[]:"); for(i=0;i<64;i++){for(j=0;j<4;j++) System.out.print("0x"+intToString(T8[i*4+j])+", "); System.out.println();} System.out.println(); System.out.println("U1[]:"); for(i=0;i<64;i++){for(j=0;j<4;j++) System.out.print("0x"+intToString(U1[i*4+j])+", "); System.out.println();} System.out.println(); System.out.println("U2[]:"); for(i=0;i<64;i++){for(j=0;j<4;j++) System.out.print("0x"+intToString(U2[i*4+j])+", "); System.out.println();} System.out.println(); System.out.println("U3[]:"); for(i=0;i<64;i++){for(j=0;j<4;j++) System.out.print("0x"+intToString(U3[i*4+j])+", "); System.out.println();} System.out.println(); System.out.println("U4[]:"); for(i=0;i<64;i++){for(j=0;j<4;j++) System.out.print("0x"+intToString(U4[i*4+j])+", "); System.out.println();} System.out.println(); System.out.println("rcon[]:"); for(i=0;i<5;i++){for(j=0;j<6;j++) System.out.print("0x"+byteToString(rcon[i*6+j])+", "); System.out.println();} System.out.println(); System.out.println("Total initialization time: "+time+" ms."); System.out.println(); } } // multiply two elements of GF(2^m) static final int mul (int a, int b) { return (a != 0 && b != 0) ? alog[(log[a & 0xFF] + log[b & 0xFF]) % 255] : 0; } // convenience method used in generating Transposition boxes static final int mul4 (int a, byte[] b) { if (a == 0) return 0; a = log[a & 0xFF]; int a0 = (b[0] != 0) ? alog[(a + log[b[0] & 0xFF]) % 255] & 0xFF : 0; int a1 = (b[1] != 0) ? alog[(a + log[b[1] & 0xFF]) % 255] & 0xFF : 0; int a2 = (b[2] != 0) ? alog[(a + log[b[2] & 0xFF]) % 255] & 0xFF : 0; int a3 = (b[3] != 0) ? alog[(a + log[b[3] & 0xFF]) % 255] & 0xFF : 0; return a0 << 24 | a1 << 16 | a2 << 8 | a3; } static final byte mulOneRowOneCol (byte[] inA, byte[] inB) { byte result = (byte) 0x0; for (int i=0; i < 4; i++) { int tmpInt = mul (inA[i], inB[i]); result = (byte) ((result ^ tmpInt) & 0xFF); } return result; } THE FIRST IMPLEMENTATION \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ // Basic API methods //........................................................................... /** * Convenience method to expand a user-supplied key material into a * session key, assuming Rijndael's default block size (128-bit). * * @param key The 128/192/256-bit user-key to use. * @exception InvalidKeyException If the key is invalid. */ public static Object makeKey (int mode, byte[] k) throws InvalidKeyException { return makeKey(mode, k, BLOCK_SIZE); } /** * NOTE: Xunhua Wang added this method on 02/20/2014 * * Convenience method to encrypt exactly one block of plaintext, assuming * Rijndael's default block size (128-bit). * * @param in The plaintext. * @param inOffset Index of in from which to start considering data. * @param sessionKey The session key to use for encryption. * @return The ciphertext generated from a plaintext using the session key. */ public static byte[] blockEncrypt (byte[] in, int inOffset, Object sessionKey) { if (DEBUG) trace(IN, "blockEncrypt("+in+", "+inOffset+", "+sessionKey+")"); int[][] Ke = (int[][]) ((Object[]) sessionKey)[0]; // extract encryption round keys int ROUNDS = Ke.length - 1; int[] Ker = Ke[0]; byte[] internalState = new byte[16]; // XHW, 02/20/2014 byte[] roundKeyBytes = new byte[16]; int counter = 0; for (int i = 0; i < 4; i++) { roundKeyBytes[counter++] = (byte) (Ker[i] >> 24 & 0xFF); roundKeyBytes[counter++] = (byte) (Ker[i] >> 16 & 0xFF); roundKeyBytes[counter++] = (byte) (Ker[i] >> 8 & 0xFF); roundKeyBytes[counter++] = (byte) (Ker[i] & 0xFF); } for (int i = 0; i < 16; i++) internalState[i] = (byte) ((in[inOffset + i] ^ roundKeyBytes[i]) & 0xFF); for (int r = 1; r <= ROUNDS; r++) { // apply round transforms Ker = Ke[r]; counter = 0; for (int i = 0; i < 4; i++) { roundKeyBytes[counter++] = (byte) (Ker[i] >> 24 & 0xFF); roundKeyBytes[counter++] = (byte) (Ker[i] >> 16 & 0xFF); roundKeyBytes[counter++] = (byte) (Ker[i] >> 8 & 0xFF); roundKeyBytes[counter++] = (byte) (Ker[i] & 0xFF); } for (int i = 0; i < 16; i++) internalState[i] = S[internalState[i] & 0xFF]; byte tmpByte = internalState[1]; internalState[1] = internalState[5]; internalState[5] = internalState[9]; internalState[9] = internalState[13]; internalState[13] = tmpByte; tmpByte = internalState[2]; byte tmpByte2 = internalState[6]; internalState[2] = internalState[10]; internalState[6] = internalState[14]; internalState[10] = tmpByte; internalState[14] = tmpByte2; tmpByte = internalState[15]; internalState[15] = internalState[11]; internalState[11] = internalState[7]; internalState[7] = internalState[3]; internalState[3] = tmpByte; if (r != ROUNDS) { for (int i = 0; i < 4; i++) { // column of state byte[] currentCol = {internalState[i*4], internalState[i*4+1], internalState[i*4+2], internalState[i*4+3]}; for (int j=0; j < 4; j++) { // row of constant matrix internalState[i*4 + j] = mulOneRowOneCol (mixColumnsG[j], currentCol); } } } for (int i = 0; i < 16; i++) internalState[i] = (byte) ((internalState[i] ^ roundKeyBytes[i]) & 0xFF); } // End of Rounds return internalState; } /** * NOTE: Xunhua Wang added this method on 05/27/2014 * This textbook decryption requires the generation of the encryption in the reverse order. As a result, * one has to set the mode to be ENCRYPT_MODE or BOTH_MODE * * Convenience method to decrypt exactly one block of plaintext, assuming * Rijndael's default block size (128-bit). * * @param in The ciphertext. * @param inOffset Index of in from which to start considering data. * @param sessionKey The session key to use for decryption. * @return The plaintext generated from a ciphertext using the session key. */ public static byte[] blockDecrypt (byte[] in, int inOffset, Object sessionKey) { if (DEBUG) trace(IN, "blockDecrypt("+in+", "+inOffset+", "+sessionKey+")"); /* int[][] Kd = (int[][]) ((Object[]) sessionKey)[1]; // extract decryption round keys int ROUNDS = Kd.length - 1; int[] Kdr = Kd[0]; */ int[][] Ke = (int[][]) ((Object[]) sessionKey)[0]; // extract DEcryption round keys int ROUNDS = Ke.length - 1; int[] Kdr = Ke[ROUNDS]; byte[] internalState = new byte[16]; // XHW, 02/20/2014 byte[] roundKeyBytes = new byte[16]; int counter = 0; for (int i = 0; i < 4; i++) { roundKeyBytes[counter++] = (byte) (Kdr[i] >> 24 & 0xFF); roundKeyBytes[counter++] = (byte) (Kdr[i] >> 16 & 0xFF); roundKeyBytes[counter++] = (byte) (Kdr[i] >> 8 & 0xFF); roundKeyBytes[counter++] = (byte) (Kdr[i] & 0xFF); } for (int i = 0; i < 16; i++) internalState[i] = (byte) ((in[inOffset + i] ^ roundKeyBytes[i]) & 0xFF); for (int r = 1; r <= ROUNDS; r++) { // apply round transforms // Kdr = Kd[r]; Kdr = Ke [ROUNDS - r]; counter = 0; for (int i = 0; i < 4; i++) { roundKeyBytes[counter++] = (byte) (Kdr[i] >> 24 & 0xFF); roundKeyBytes[counter++] = (byte) (Kdr[i] >> 16 & 0xFF); roundKeyBytes[counter++] = (byte) (Kdr[i] >> 8 & 0xFF); roundKeyBytes[counter++] = (byte) (Kdr[i] & 0xFF); } byte tmpByte = internalState[13]; internalState[13] = internalState[9]; internalState[9] = internalState[5]; internalState[5] = internalState[1]; internalState[1] = tmpByte; tmpByte = internalState[10]; byte tmpByte2 = internalState[14]; internalState[10] = internalState[2]; internalState[14] = internalState[6]; internalState[2] = tmpByte; internalState[6] = tmpByte2; tmpByte = internalState[3]; internalState[3] = internalState[7]; internalState[7] = internalState[11]; internalState[11] = internalState[15]; internalState[15] = tmpByte; for (int i = 0; i < 16; i++) internalState[i] = Si[internalState[i] & 0xFF]; for (int i = 0; i < 16; i++) internalState[i] = (byte) ((internalState[i] ^ roundKeyBytes[i]) & 0xFF); if (r != ROUNDS) { for (int i = 0; i < 4; i++) { // column of state byte[] currentCol = {internalState[i*4], internalState[i*4+1], internalState[i*4+2], internalState[i*4+3]}; for (int j=0; j < 4; j++) { // row of constant matrix internalState[i*4 + j] = mulOneRowOneCol (invMixColumnsG[j], currentCol); } } } } // End of Rounds return internalState; } // Rijndael own methods //........................................................................... /** @return The default length in bytes of the Algorithm input block. */ public static int blockSize() { return BLOCK_SIZE; } /** * Expand a user-supplied key material into a session key. * * @param key The 128/192/256-bit user-key to use. * @param blockSize The block size in bytes of this Rijndael. * @exception InvalidKeyException If the key is invalid. */ public static synchronized Object makeKey (int mode, byte[] k, int blockSize) throws InvalidKeyException { if (DEBUG) trace(IN, "makeKey("+k+", "+blockSize+")"); if (k == null) throw new InvalidKeyException("Empty key"); if (!(k.length == 16 || k.length == 24 || k.length == 32)) throw new InvalidKeyException("Incorrect key length"); int ROUNDS = getRounds(k.length, blockSize); int BC = blockSize / 4; int[][] Ke = new int[ROUNDS + 1][BC]; // encryption round keys int[][] Kd = new int[ROUNDS + 1][BC]; // decryption round keys int ROUND_KEY_COUNT = (ROUNDS + 1) * BC; int KC = k.length / 4; int[] tk = new int[KC]; int i, j; // copy user material bytes into temporary ints for (i = 0, j = 0; i < KC; ) tk[i++] = (k[j++] & 0xFF) << 24 | (k[j++] & 0xFF) << 16 | (k[j++] & 0xFF) << 8 | (k[j++] & 0xFF); // copy values into round key arrays int t = 0; if (mode == ENCRYPT_MODE) { for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) { Ke[t / BC][t % BC] = tk[j]; } } else if (mode == DECRYPT_MODE) { for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) { Kd[ROUNDS - (t / BC)][t % BC] = tk[j]; } } else { for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) { Ke[t / BC][t % BC] = tk[j]; Kd[ROUNDS - (t / BC)][t % BC] = tk[j]; } } int tt, rconpointer = 0; while (t < ROUND_KEY_COUNT) { // extrapolate using phi (the round key evolution function) tt = tk[KC - 1]; tk[0] ^= (S[(tt >>> 16) & 0xFF] & 0xFF) << 24 ^ (S[(tt >>> 8) & 0xFF] & 0xFF) << 16 ^ (S[ tt & 0xFF] & 0xFF) << 8 ^ (S[(tt >>> 24) & 0xFF] & 0xFF) ^ (rcon[rconpointer++] & 0xFF) << 24; if (KC != 8) for (i = 1, j = 0; i < KC; ) tk[i++] ^= tk[j++]; else { for (i = 1, j = 0; i < KC / 2; ) tk[i++] ^= tk[j++]; tt = tk[KC / 2 - 1]; tk[KC / 2] ^= (S[ tt & 0xFF] & 0xFF) ^ (S[(tt >>> 8) & 0xFF] & 0xFF) << 8 ^ (S[(tt >>> 16) & 0xFF] & 0xFF) << 16 ^ (S[(tt >>> 24) & 0xFF] & 0xFF) << 24; for (j = KC / 2, i = j + 1; i < KC; ) tk[i++] ^= tk[j++]; } // copy values into round key arrays if (mode == ENCRYPT_MODE) { for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) { Ke[t / BC][t % BC] = tk[j]; } } else if (mode == DECRYPT_MODE) { for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) { Kd[ROUNDS - (t / BC)][t % BC] = tk[j]; } } else { for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) { Ke[t / BC][t % BC] = tk[j]; Kd[ROUNDS - (t / BC)][t % BC] = tk[j]; } } } for (int r = 1; r < ROUNDS; r++) // inverse MixColumn where needed for (j = 0; j < BC; j++) { tt = Kd[r][j]; Kd[r][j] = U1[(tt >>> 24) & 0xFF] ^ U2[(tt >>> 16) & 0xFF] ^ U3[(tt >>> 8) & 0xFF] ^ U4[ tt & 0xFF]; } // assemble the encryption (Ke) and decryption (Kd) round keys into // one sessionKey object Object[] sessionKey = new Object[] {Ke, Kd}; if (DEBUG) trace(OUT, "makeKey()"); return sessionKey; } A SECOND IMPLEMENTATION \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ /** * Convenience method to encrypt exactly one block of plaintext, assuming * Rijndael's default block size (128-bit). * * @param in The plaintext. * @param inOffset Index of in from which to start considering data. * @param sessionKey The session key to use for encryption. * @return The ciphertext generated from a plaintext using the session key. */ public static byte[] blockEncrypt2 (byte[] in, int inOffset, Object sessionKey) { if (DEBUG) trace(IN, "blockEncrypt2("+in+", "+inOffset+", "+sessionKey+")"); int[][] Ke = (int[][]) ((Object[]) sessionKey)[0]; // extract encryption round keys int ROUNDS = Ke.length - 1; int[] Ker = Ke[0]; // plaintext to ints + key int t0 = ((in[inOffset++] & 0xFF) << 24 | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 8 | (in[inOffset++] & 0xFF) ) ^ Ker[0]; int t1 = ((in[inOffset++] & 0xFF) << 24 | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 8 | (in[inOffset++] & 0xFF) ) ^ Ker[1]; int t2 = ((in[inOffset++] & 0xFF) << 24 | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 8 | (in[inOffset++] & 0xFF) ) ^ Ker[2]; int t3 = ((in[inOffset++] & 0xFF) << 24 | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 8 | (in[inOffset++] & 0xFF) ) ^ Ker[3]; int a0, a1, a2, a3; for (int r = 1; r < ROUNDS; r++) { // apply round transforms Ker = Ke[r]; a0 = (T1[(t0 >>> 24) & 0xFF] ^ T2[(t1 >>> 16) & 0xFF] ^ T3[(t2 >>> 8) & 0xFF] ^ T4[ t3 & 0xFF] ) ^ Ker[0]; a1 = (T1[(t1 >>> 24) & 0xFF] ^ T2[(t2 >>> 16) & 0xFF] ^ T3[(t3 >>> 8) & 0xFF] ^ T4[ t0 & 0xFF] ) ^ Ker[1]; a2 = (T1[(t2 >>> 24) & 0xFF] ^ T2[(t3 >>> 16) & 0xFF] ^ T3[(t0 >>> 8) & 0xFF] ^ T4[ t1 & 0xFF] ) ^ Ker[2]; a3 = (T1[(t3 >>> 24) & 0xFF] ^ T2[(t0 >>> 16) & 0xFF] ^ T3[(t1 >>> 8) & 0xFF] ^ T4[ t2 & 0xFF] ) ^ Ker[3]; t0 = a0; t1 = a1; t2 = a2; t3 = a3; if (DEBUG && debuglevel > 6) System.out.println("CT"+r+"="+intToString(t0)+intToString(t1)+intToString(t2)+intToString(t3)); } // last round is special byte[] result = new byte[BLOCK_SIZE]; // the resulting ciphertext Ker = Ke[ROUNDS]; int tt = Ker[0]; result[ 0] = (byte)(S[(t0 >>> 24) & 0xFF] ^ (tt >>> 24)); result[ 1] = (byte)(S[(t1 >>> 16) & 0xFF] ^ (tt >>> 16)); result[ 2] = (byte)(S[(t2 >>> 8) & 0xFF] ^ (tt >>> 8)); result[ 3] = (byte)(S[ t3 & 0xFF] ^ tt ); tt = Ker[1]; result[ 4] = (byte)(S[(t1 >>> 24) & 0xFF] ^ (tt >>> 24)); result[ 5] = (byte)(S[(t2 >>> 16) & 0xFF] ^ (tt >>> 16)); result[ 6] = (byte)(S[(t3 >>> 8) & 0xFF] ^ (tt >>> 8)); result[ 7] = (byte)(S[ t0 & 0xFF] ^ tt ); tt = Ker[2]; result[ 8] = (byte)(S[(t2 >>> 24) & 0xFF] ^ (tt >>> 24)); result[ 9] = (byte)(S[(t3 >>> 16) & 0xFF] ^ (tt >>> 16)); result[10] = (byte)(S[(t0 >>> 8) & 0xFF] ^ (tt >>> 8)); result[11] = (byte)(S[ t1 & 0xFF] ^ tt ); tt = Ker[3]; result[12] = (byte)(S[(t3 >>> 24) & 0xFF] ^ (tt >>> 24)); result[13] = (byte)(S[(t0 >>> 16) & 0xFF] ^ (tt >>> 16)); result[14] = (byte)(S[(t1 >>> 8) & 0xFF] ^ (tt >>> 8)); result[15] = (byte)(S[ t2 & 0xFF] ^ tt ); if (DEBUG && debuglevel > 6) { System.out.println("CT="+toString(result)); System.out.println(); } if (DEBUG) trace(OUT, "blockEncrypt2()"); return result; } /** * Convenience method to decrypt exactly one block of plaintext, assuming * Rijndael's default block size (128-bit). * * @param in The ciphertext. * @param inOffset Index of in from which to start considering data. * @param sessionKey The session key to use for decryption. * @return The plaintext generated from a ciphertext using the session key. */ public static byte[] blockDecrypt2 (byte[] in, int inOffset, Object sessionKey) { if (DEBUG) trace(IN, "blockDecrypt2("+in+", "+inOffset+", "+sessionKey+")"); int[][] Kd = (int[][]) ((Object[]) sessionKey)[1]; // extract decryption round keys int ROUNDS = Kd.length - 1; int[] Kdr = Kd[0]; // ciphertext to ints + key int t0 = ((in[inOffset++] & 0xFF) << 24 | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 8 | (in[inOffset++] & 0xFF) ) ^ Kdr[0]; int t1 = ((in[inOffset++] & 0xFF) << 24 | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 8 | (in[inOffset++] & 0xFF) ) ^ Kdr[1]; int t2 = ((in[inOffset++] & 0xFF) << 24 | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 8 | (in[inOffset++] & 0xFF) ) ^ Kdr[2]; int t3 = ((in[inOffset++] & 0xFF) << 24 | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 8 | (in[inOffset++] & 0xFF) ) ^ Kdr[3]; int a0, a1, a2, a3; for (int r = 1; r < ROUNDS; r++) { // apply round transforms Kdr = Kd[r]; a0 = (T5[(t0 >>> 24) & 0xFF] ^ T6[(t3 >>> 16) & 0xFF] ^ T7[(t2 >>> 8) & 0xFF] ^ T8[ t1 & 0xFF] ) ^ Kdr[0]; a1 = (T5[(t1 >>> 24) & 0xFF] ^ T6[(t0 >>> 16) & 0xFF] ^ T7[(t3 >>> 8) & 0xFF] ^ T8[ t2 & 0xFF] ) ^ Kdr[1]; a2 = (T5[(t2 >>> 24) & 0xFF] ^ T6[(t1 >>> 16) & 0xFF] ^ T7[(t0 >>> 8) & 0xFF] ^ T8[ t3 & 0xFF] ) ^ Kdr[2]; a3 = (T5[(t3 >>> 24) & 0xFF] ^ T6[(t2 >>> 16) & 0xFF] ^ T7[(t1 >>> 8) & 0xFF] ^ T8[ t0 & 0xFF] ) ^ Kdr[3]; t0 = a0; t1 = a1; t2 = a2; t3 = a3; if (DEBUG && debuglevel > 6) System.out.println("PT"+r+"="+intToString(t0)+intToString(t1)+intToString(t2)+intToString(t3)); } // last round is special byte[] result = new byte[16]; // the resulting plaintext Kdr = Kd[ROUNDS]; int tt = Kdr[0]; result[ 0] = (byte)(Si[(t0 >>> 24) & 0xFF] ^ (tt >>> 24)); result[ 1] = (byte)(Si[(t3 >>> 16) & 0xFF] ^ (tt >>> 16)); result[ 2] = (byte)(Si[(t2 >>> 8) & 0xFF] ^ (tt >>> 8)); result[ 3] = (byte)(Si[ t1 & 0xFF] ^ tt ); tt = Kdr[1]; result[ 4] = (byte)(Si[(t1 >>> 24) & 0xFF] ^ (tt >>> 24)); result[ 5] = (byte)(Si[(t0 >>> 16) & 0xFF] ^ (tt >>> 16)); result[ 6] = (byte)(Si[(t3 >>> 8) & 0xFF] ^ (tt >>> 8)); result[ 7] = (byte)(Si[ t2 & 0xFF] ^ tt ); tt = Kdr[2]; result[ 8] = (byte)(Si[(t2 >>> 24) & 0xFF] ^ (tt >>> 24)); result[ 9] = (byte)(Si[(t1 >>> 16) & 0xFF] ^ (tt >>> 16)); result[10] = (byte)(Si[(t0 >>> 8) & 0xFF] ^ (tt >>> 8)); result[11] = (byte)(Si[ t3 & 0xFF] ^ tt ); tt = Kdr[3]; result[12] = (byte)(Si[(t3 >>> 24) & 0xFF] ^ (tt >>> 24)); result[13] = (byte)(Si[(t2 >>> 16) & 0xFF] ^ (tt >>> 16)); result[14] = (byte)(Si[(t1 >>> 8) & 0xFF] ^ (tt >>> 8)); result[15] = (byte)(Si[ t0 & 0xFF] ^ tt ); if (DEBUG && debuglevel > 6) { System.out.println("PT="+toString(result)); System.out.println(); } if (DEBUG) trace(OUT, "blockDecrypt2()"); return result; } OTHER METHODS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ /** A basic symmetric encryption/decryption test. */ public static boolean self_test() { return self_test(BLOCK_SIZE); } ADDITIONAL METHODS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ /** * Encrypt exactly one block of plaintext. * * @param in The plaintext. * @param inOffset Index of in from which to start considering data. * @param sessionKey The session key to use for encryption. * @param blockSize The block size in bytes of this Rijndael. * @return The ciphertext generated from a plaintext using the session key. */ public static byte[] blockEncrypt2 (byte[] in, int inOffset, Object sessionKey, int blockSize) { if (blockSize == BLOCK_SIZE) return blockEncrypt2(in, inOffset, sessionKey); if (DEBUG) trace(IN, "blockEncrypt2("+in+", "+inOffset+", "+sessionKey+", "+blockSize+")"); Object[] sKey = (Object[]) sessionKey; // extract encryption round keys int[][] Ke = (int[][]) sKey[0]; int BC = blockSize / 4; int ROUNDS = Ke.length - 1; int SC = BC == 4 ? 0 : (BC == 6 ? 1 : 2); int s1 = shifts[SC][1][0]; int s2 = shifts[SC][2][0]; int s3 = shifts[SC][3][0]; int[] a = new int[BC]; int[] t = new int[BC]; // temporary work array int i; byte[] result = new byte[blockSize]; // the resulting ciphertext int j = 0, tt; for (i = 0; i < BC; i++) // plaintext to ints + key t[i] = ((in[inOffset++] & 0xFF) << 24 | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 8 | (in[inOffset++] & 0xFF) ) ^ Ke[0][i]; for (int r = 1; r < ROUNDS; r++) { // apply round transforms for (i = 0; i < BC; i++) a[i] = (T1[(t[ i ] >>> 24) & 0xFF] ^ T2[(t[(i + s1) % BC] >>> 16) & 0xFF] ^ T3[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ T4[ t[(i + s3) % BC] & 0xFF] ) ^ Ke[r][i]; System.arraycopy(a, 0, t, 0, BC); if (DEBUG && debuglevel > 6) System.out.println("CT"+r+"="+toString(t)); } for (i = 0; i < BC; i++) { // last round is special tt = Ke[ROUNDS][i]; result[j++] = (byte)(S[(t[ i ] >>> 24) & 0xFF] ^ (tt >>> 24)); result[j++] = (byte)(S[(t[(i + s1) % BC] >>> 16) & 0xFF] ^ (tt >>> 16)); result[j++] = (byte)(S[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ (tt >>> 8)); result[j++] = (byte)(S[ t[(i + s3) % BC] & 0xFF] ^ tt); } if (DEBUG && debuglevel > 6) { System.out.println("CT="+toString(result)); System.out.println(); } if (DEBUG) trace(OUT, "blockEncrypt2()"); return result; } /** * Decrypt exactly one block of ciphertext. * * @param in The ciphertext. * @param inOffset Index of in from which to start considering data. * @param sessionKey The session key to use for decryption. * @param blockSize The block size in bytes of this Rijndael. * @return The plaintext generated from a ciphertext using the session key. */ public static byte[] blockDecrypt2 (byte[] in, int inOffset, Object sessionKey, int blockSize) { if (blockSize == BLOCK_SIZE) return blockDecrypt2 (in, inOffset, sessionKey); if (DEBUG) trace(IN, "blockDecrypt2("+in+", "+inOffset+", "+sessionKey+", "+blockSize+")"); Object[] sKey = (Object[]) sessionKey; // extract decryption round keys int[][] Kd = (int[][]) sKey[1]; int BC = blockSize / 4; int ROUNDS = Kd.length - 1; int SC = BC == 4 ? 0 : (BC == 6 ? 1 : 2); int s1 = shifts[SC][1][1]; int s2 = shifts[SC][2][1]; int s3 = shifts[SC][3][1]; int[] a = new int[BC]; int[] t = new int[BC]; // temporary work array int i; byte[] result = new byte[blockSize]; // the resulting plaintext int j = 0, tt; for (i = 0; i < BC; i++) // ciphertext to ints + key t[i] = ((in[inOffset++] & 0xFF) << 24 | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 8 | (in[inOffset++] & 0xFF) ) ^ Kd[0][i]; for (int r = 1; r < ROUNDS; r++) { // apply round transforms for (i = 0; i < BC; i++) a[i] = (T5[(t[ i ] >>> 24) & 0xFF] ^ T6[(t[(i + s1) % BC] >>> 16) & 0xFF] ^ T7[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ T8[ t[(i + s3) % BC] & 0xFF] ) ^ Kd[r][i]; System.arraycopy(a, 0, t, 0, BC); if (DEBUG && debuglevel > 6) System.out.println("PT"+r+"="+toString(t)); } for (i = 0; i < BC; i++) { // last round is special tt = Kd[ROUNDS][i]; result[j++] = (byte)(Si[(t[ i ] >>> 24) & 0xFF] ^ (tt >>> 24)); result[j++] = (byte)(Si[(t[(i + s1) % BC] >>> 16) & 0xFF] ^ (tt >>> 16)); result[j++] = (byte)(Si[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ (tt >>> 8)); result[j++] = (byte)(Si[ t[(i + s3) % BC] & 0xFF] ^ tt); } if (DEBUG && debuglevel > 6) { System.out.println("PT="+toString(result)); System.out.println(); } if (DEBUG) trace(OUT, "blockDecrypt2()"); return result; } /** A basic symmetric encryption/decryption test for a given key size. */ private static boolean self_test (int keysize) { if (DEBUG) trace(IN, "self_test("+keysize+")"); boolean ok = false; try { byte[] kb = new byte[keysize]; byte[] pt = new byte[BLOCK_SIZE]; int i; for (i = 0; i < keysize; i++) kb[i] = (byte) i; for (i = 0; i < BLOCK_SIZE; i++) pt[i] = (byte) i; if (DEBUG && debuglevel > 6) { System.out.println("=========="); System.out.println(); System.out.println("KEYSIZE="+(8*keysize)); System.out.println("KEY="+toString(kb)); System.out.println(); } Object key = makeKey(BOTH_MODE, kb, BLOCK_SIZE); if (DEBUG && debuglevel > 6) { System.out.println("Intermediate Ciphertext Values (Encryption)"); System.out.println(); System.out.println("PT="+toString(pt)); } byte[] ct = blockEncrypt2(pt, 0, key, BLOCK_SIZE); if (DEBUG && debuglevel > 6) { System.out.println("Intermediate Plaintext Values (Decryption)"); System.out.println(); System.out.println("CT="+toString(ct)); } byte[] cpt = blockDecrypt2(ct, 0, key, BLOCK_SIZE); ok = areEqual(pt, cpt); if (!ok) throw new RuntimeException("Symmetric operation failed"); } catch (Exception x) { if (DEBUG && debuglevel > 0) { debug("Exception encountered during self-test: " + x.getMessage()); x.printStackTrace(); } } if (DEBUG && debuglevel > 0) debug("Self-test OK? " + ok); if (DEBUG) trace(OUT, "self_test()"); return ok; } /** * Return The number of rounds for a given Rijndael's key and block sizes. * * @param keySize The size of the user key material in bytes. * @param blockSize The desired block size in bytes. * @return The number of rounds for a given Rijndael's key and * block sizes. */ public static int getRounds (int keySize, int blockSize) { switch (keySize) { case 16: return blockSize == 16 ? 10 : (blockSize == 24 ? 12 : 14); case 24: return blockSize != 32 ? 12 : 14; default: // 32 bytes = 256 bits return 14; } } UTILITY METHODS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ // // utility static methods (from cryptix.util.core ArrayUtil and Hex classes) //........................................................................... /** * Compares two byte arrays for equality. * * @return true if the arrays have identical contents */ private static boolean areEqual (byte[] a, byte[] b) { int aLength = a.length; if (aLength != b.length) return false; for (int i = 0; i < aLength; i++) if (a[i] != b[i]) return false; return true; } /** * Returns a string of 2 hexadecimal digits (most significant * digit first) corresponding to the lowest 8 bits of <i>n</i>. */ private static String byteToString (int n) { char[] buf = { HEX_DIGITS[(n >>> 4) & 0x0F], HEX_DIGITS[ n & 0x0F] }; return new String(buf); } /** * Returns a string of 8 hexadecimal digits (most significant * digit first) corresponding to the integer <i>n</i>, which is * treated as unsigned. */ private static String intToString (int n) { char[] buf = new char[8]; for (int i = 7; i >= 0; i--) { buf[i] = HEX_DIGITS[n & 0x0F]; n >>>= 4; } return new String(buf); } /** * Returns a string of hexadecimal digits from a byte array. Each * byte is converted to 2 hex symbols. */ private static String toString (byte[] ba) { int length = ba.length; char[] buf = new char[length * 2]; for (int i = 0, j = 0, k; i < length; ) { k = ba[i++]; buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F]; buf[j++] = HEX_DIGITS[ k & 0x0F]; } return new String(buf); } // // Xunhua: We need to add some spaces and line breaks // private static String toString2 (byte[] ba) { int length = ba.length; // char[] buf = new char[length * 2]; char[] buf2 = new char[2]; StringBuffer sb = new StringBuffer (); for (int i = 0; i < length; ) { int k = ba[i++]; buf2[0] = HEX_DIGITS[(k >>> 4) & 0x0F]; buf2[1] = HEX_DIGITS[ k & 0x0F]; sb.append (buf2); if (i%16 == 0) { sb.append (System.getProperty ("line.separator")); } else { sb.append (" "); } } return sb.toString(); } /** * Returns a string of hexadecimal digits from an integer array. Each * int is converted to 4 hex symbols. */ private static String toString (int[] ia) { int length = ia.length; char[] buf = new char[length * 8]; for (int i = 0, j = 0, k; i < length; i++) { k = ia[i]; buf[j++] = HEX_DIGITS[(k >>> 28) & 0x0F]; buf[j++] = HEX_DIGITS[(k >>> 24) & 0x0F]; buf[j++] = HEX_DIGITS[(k >>> 20) & 0x0F]; buf[j++] = HEX_DIGITS[(k >>> 16) & 0x0F]; buf[j++] = HEX_DIGITS[(k >>> 12) & 0x0F]; buf[j++] = HEX_DIGITS[(k >>> 8) & 0x0F]; buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F]; buf[j++] = HEX_DIGITS[ k & 0x0F]; } return new String(buf); } private static String toString2 (int[] ia) { int length = ia.length; // char[] buf = new char[length * 8]; char[] buf2 = new char[8]; StringBuffer sb = new StringBuffer (); for (int i = 0; i < length; i++) { if (i != 0 && i%16 == 0) { sb.append (System.getProperty ("line.separator")); } else if (i != 0) { sb.append (" "); } int k = ia[i]; buf2[0] = HEX_DIGITS[(k >>> 28) & 0x0F]; buf2[1] = HEX_DIGITS[(k >>> 24) & 0x0F]; buf2[2] = HEX_DIGITS[(k >>> 20) & 0x0F]; buf2[3] = HEX_DIGITS[(k >>> 16) & 0x0F]; buf2[4] = HEX_DIGITS[(k >>> 12) & 0x0F]; buf2[5] = HEX_DIGITS[(k >>> 8) & 0x0F]; buf2[6] = HEX_DIGITS[(k >>> 4) & 0x0F]; buf2[7] = HEX_DIGITS[ k & 0x0F]; sb.append (buf2); } return sb.toString(); } // main(): use to generate the Intermediate Values KAT //........................................................................... public static void main (String[] args) { self_test(16); self_test(24); self_test(32); } }
Error: Could not find or load main class AES_NEW// $Id: Rijndael_Properties.java,v 1.1.1.1 2005/10/11 16:49:07 ruthap Exp $ // // $Log: Rijndael_Properties.java,v $ // Revision 1.1.1.1 2005/10/11 16:49:07 ruthap // My Research Source Code // // Revision 1.0 1998/04/07 raif // + original version. // // $Endlog$ /* * Copyright (c) 1997, 1998 Systemics Ltd on behalf of * the Cryptix Development Team. All rights reserved. */ // package Rijndael; //import java.io.FileInputStream; //import java.io.FileNotFoundException; import java.io.InputStream; //import java.io.IOException; import java.io.PrintWriter; import java.io.PrintStream; import java.util.Enumeration; import java.util.Properties; /** * This class acts as a central repository for an algorithm specific * properties. It reads an (algorithm).properties file containing algorithm- * specific properties. When using the AES-Kit, this (algorithm).properties * file is located in the (algorithm).jar file produced by the "jarit" batch/ * script command.<p> * * <b>Copyright</b> © 1997, 1998 * <a href="http://www.systemics.com/">Systemics Ltd</a> on behalf of the * <a href="http://www.systemics.com/docs/cryptix/">Cryptix Development Team</a>. * <br>All rights reserved.<p> * * <b>$Revision: 1.1.1.1 $</b> * @author David Hopwood * @author Jill Baker * @author Raif S. Naffah */ public class Rijndael_Properties // implicit no-argument constructor { // Constants and variables with relevant static code //........................................................................... static final boolean GLOBAL_DEBUG = false; static final String ALGORITHM = "Rijndael"; static final double VERSION = 0.1; static final String FULL_NAME = ALGORITHM + " ver. " + VERSION; static final String NAME = "Rijndael_Properties"; static final Properties properties = new Properties(); /** Default properties in case .properties file was not found. */ private static final String[][] DEFAULT_PROPERTIES = { {"Trace.Rijndael_Algorithm", "true"}, {"Debug.Level.*", "1"}, {"Debug.Level.Rijndael_Algorithm", "9"}, }; static { if (GLOBAL_DEBUG) System.err.println(">>> " + NAME + ": Looking for " + ALGORITHM + " properties"); String it = ALGORITHM + ".properties"; InputStream is = Rijndael_Properties.class.getResourceAsStream(it); boolean ok = is != null; if (ok) try { properties.load(is); is.close(); if (GLOBAL_DEBUG) System.err.println(">>> " + NAME + ": Properties file loaded OK..."); } catch (Exception x) { ok = false; } if (!ok) { if (GLOBAL_DEBUG) System.err.println(">>> " + NAME + ": WARNING: Unable to load \"" + it + "\" from CLASSPATH."); if (GLOBAL_DEBUG) System.err.println(">>> " + NAME + ": Will use default values instead..."); int n = DEFAULT_PROPERTIES.length; for (int i = 0; i < n; i++) properties.put( DEFAULT_PROPERTIES[i][0], DEFAULT_PROPERTIES[i][1]); if (GLOBAL_DEBUG) System.err.println(">>> " + NAME + ": Default properties now set..."); } } // Properties methods (excluding load and save, which are deliberately not // supported). //........................................................................... /** Get the value of a property for this algorithm. */ public static String getProperty (String key) { return properties.getProperty(key); } /** * Get the value of a property for this algorithm, or return * <i>value</i> if the property was not set. */ public static String getProperty (String key, String value) { return properties.getProperty(key, value); } /** List algorithm properties to the PrintStream <i>out</i>. */ public static void list (PrintStream out) { list(new PrintWriter(out, true)); } /** List algorithm properties to the PrintWriter <i>out</i>. */ public static void list (PrintWriter out) { out.println("#"); out.println("# ----- Begin "+ALGORITHM+" properties -----"); out.println("#"); String key, value; Enumeration enum1 = properties.propertyNames(); while (enum1.hasMoreElements()) { key = (String) enum1.nextElement(); value = getProperty(key); out.println(key + " = " + value); } out.println("#"); out.println("# ----- End "+ALGORITHM+" properties -----"); } // public synchronized void load(InputStream in) throws IOException {} public static Enumeration propertyNames() { return properties.propertyNames(); } // public void save (OutputStream os, String comment) {} // Developer support: Tracing and debugging enquiry methods (package-private) //........................................................................... /** * Return true if tracing is requested for a given class.<p> * * User indicates this by setting the tracing <code>boolean</code> * property for <i>label</i> in the <code>(algorithm).properties</code> * file. The property's key is "<code>Trace.<i>label</i></code>".<p> * * @param label The name of a class. * @return True iff a boolean true value is set for a property with * the key <code>Trace.<i>label</i></code>. */ static boolean isTraceable (String label) { String s = getProperty("Trace." + label); if (s == null) return false; return new Boolean(s).booleanValue(); } /** * Return the debug level for a given class.<p> * * User indicates this by setting the numeric property with key * "<code>Debug.Level.<i>label</i></code>".<p> * * If this property is not set, "<code>Debug.Level.*</code>" is looked up * next. If neither property is set, or if the first property found is * not a valid decimal integer, then this method returns 0. * * @param label The name of a class. * @return The required debugging level for the designated class. */ static int getLevel(String label) { String s = getProperty("Debug.Level." + label); if (s == null) { s = getProperty("Debug.Level.*"); if (s == null) return 0; } try { return Integer.parseInt(s); } catch (NumberFormatException e) { return 0; } } /** * Return the PrintWriter to which tracing and debugging output is to * be sent.<p> * * User indicates this by setting the property with key <code>Output</code> * to the literal <code>out</code> or <code>err</code>.<p> * * By default or if the set value is not allowed, <code>System.err</code> * will be used. */ static PrintWriter getOutput() { PrintWriter pw; String name = getProperty("Output"); if (name != null && name.equals("out")) pw = new PrintWriter(System.out, true); else pw = new PrintWriter(System.err, true); return pw; } }
Error: Could not find or load main class AES_NEW.java
Error: Could not find or load main class AES_NEW
Error: Could not find or load main class AES_NEW
Error: Could not find or load main class AES_NEW
Error: Could not find or load main class AES_NEW
Error: Could not find or load main class AES_NEW
Error: Could not find or load main class AES_NEW
Where to start?
Exception in thread "main" java.util.NoSuchElementException
at java.util.Scanner.throwFor(Scanner.java:907)
at java.util.Scanner.next(Scanner.java:1530)
at java.util.Scanner.nextInt(Scanner.java:2160)
at java.util.Scanner.nextInt(Scanner.java:2119)
at AES_NEW.main(AES_NEW.java:26)
Where to start?
Exception in thread "main" java.util.NoSuchElementException
at java.util.Scanner.throwFor(Scanner.java:907)
at java.util.Scanner.next(Scanner.java:1530)
at java.util.Scanner.nextInt(Scanner.java:2160)
at java.util.Scanner.nextInt(Scanner.java:2119)
at AES_NEW.main(AES_NEW.java:26)
Where to start?
Exception in thread "main" java.util.NoSuchElementException
at java.util.Scanner.throwFor(Scanner.java:907)
at java.util.Scanner.next(Scanner.java:1530)
at java.util.Scanner.nextInt(Scanner.java:2160)
at java.util.Scanner.nextInt(Scanner.java:2119)
at AES_NEW.main(AES_NEW.java:26)
Where to start?
Exception in thread "main" java.util.NoSuchElementException
at java.util.Scanner.throwFor(Scanner.java:907)
at java.util.Scanner.next(Scanner.java:1530)
at java.util.Scanner.nextInt(Scanner.java:2160)
at java.util.Scanner.nextInt(Scanner.java:2119)
at AES_NEW.main(AES_NEW.java:26)
AES128实习
最新推荐文章于 2023-03-30 20:20:35 发布