📄 rijndael_algorithm.java
字号:
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];
}
// 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;
}
/**
* 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[] blockEncrypt(byte[] in, int inOffset,
Object sessionKey, int blockSize) {
if (blockSize == BLOCK_SIZE)
return blockEncrypt(in, inOffset, sessionKey);
if (DEBUG)
trace(IN, "blockEncrypt(" + 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, "blockEncrypt()");
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[] blockDecrypt(byte[] in, int inOffset,
Object sessionKey, int blockSize) {
if (blockSize == BLOCK_SIZE)
return blockDecrypt(in, inOffset, sessionKey);
if (DEBUG)
trace(IN, "blockDecrypt(" + 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, "blockDecrypt()");
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(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 = blockEncrypt(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 = blockDecrypt(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 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);
}
/**
* 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);
}
// main(): use to generate the Intermediate Values KAT
// ...........................................................................
public static void main(String[] args) {
self_test(16);
self_test(24);
self_test(32);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -