// $Id: $
//
// $Log: $
// 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: $</b>
* @author Raif S. Naffah
* @author Paulo S. L. M. Barreto
*/
public final class Rijndael_Algorithm // implicit no-argument constructor
{
// Debugging methods and variables
//...........................................................................
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 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(
- 1
- 2
- 3
前往页