📄 rijndael_algorithm.java
字号:
// 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; }// 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 (byte[] k) throws InvalidKeyException { return makeKey(k, BLOCK_SIZE); } /** * 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]; // 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, "blockEncrypt()"); 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[] 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]; // 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, "blockDecrypt()"); return result; } /** A basic symmetric encryption/decryption test. */ public static boolean self_test() { return self_test(BLOCK_SIZE); }// 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 (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; 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 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];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -