Скачиваний:
22
Добавлен:
01.05.2014
Размер:
43.49 Кб
Скачать
// $Id: $
//
// $Log: $
// Revision 1.1.1 1998/04/10 raif
// + added code to generate Intermediate Values KAT.
// + cosmetics.
//
// Revision 1.1 1998/04/07 Serpent authors
// + revised slightly (endianness, and key schedule for variable lengths)
//
// Revision 1.0 1998/04/06 raif
// + original version.
//
// $Endlog$
/*
* Copyright (c) 1997, 1998 Systemics Ltd on behalf of
* the Cryptix Development Team. All rights reserved.
*/
package Serpent;

import java.io.PrintWriter;
import java.security.InvalidKeyException;

//...........................................................................
/**
* A standard implementation in Java of the Serpent cipher.<p>
*
* Serpent is a 128-bit 32-round block cipher with variable key lengths,
* including 128-, 192- and 256-bit keys conjectured to be at least as
* secure as three-key triple-DES.<p>
*
* Serpent was designed by Ross Anderson, Eli Biham and Lars Knudsen as a
* candidate algorithm for the NIST AES Quest.<p>
*
* References:<ol>
* <li>Serpent: A New Block Cipher Proposal. This paper was published in the
* proceedings of the "Fast Software Encryption Workshop No. 5" held in
* Paris in March 1998. LNCS, Springer Verlag.<p>
* <li>Reference implementation of the standard Serpent cipher written in C
* by <a href="http://www.cl.cam.ac.uk/~fms/"> Frank Stajano</a>.</ol><p>
*
* <b>Copyright</b> &copy; 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 Serpent authors (Ross Anderson, Eli Biham and Lars Knudsen)
*/
public final class Serpent_Standard // implicit no-argument constructor
{
// Debugging methods and variables
//...........................................................................

static final String NAME = "Serpent_Standard";
static final boolean IN = true, OUT = false;

static final boolean DEBUG = Serpent_Properties.GLOBAL_DEBUG;

/**
* Depending on the value assigned to debuglevel, the following sensitive
* information is displayed:
*
* 9 all intermediary key computation
* 8 final session key values
* 7 all block encryption/decryption intermediary values
* 6 final block encryption/decryption values before final permutation
*/
static final int debuglevel =
DEBUG ? Serpent_Properties.getLevel("Serpent_Algorithm") : 0;
static final PrintWriter err =
DEBUG ? Serpent_Properties.getOutput() : null;

static final boolean TRACE =
Serpent_Properties.isTraceable("Serpent_Algorithm");

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; // bytes in a data-block

static final int ROUNDS = 32; // nbr of rounds
static final int PHI = 0x9E3779B9; // (sqrt(5) - 1) * 2**31

/**
* An array of 32 (number of rounds) S boxes.<p>
*
* An S box is an array of 16 distinct quantities, each in the range 0-15.
* A value v at position p for a given S box, implies that if this S box
* is given on input a value p, it will return the value v.
*/


static final byte[][] Sbox = new byte[][] {
{ 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 },/* S0: */
{15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 },/* S1: */
{ 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 },/* S2: */
{ 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 },/* S3: */
{ 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 },/* S4: */
{15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 },/* S5: */
{ 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 },/* S6: */
{ 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 },/* S7: */
{ 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 },/* S0: */
{15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 },/* S1: */
{ 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 },/* S2: */
{ 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 },/* S3: */
{ 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 },/* S4: */
{15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 },/* S5: */
{ 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 },/* S6: */
{ 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 },/* S7: */
{ 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 },/* S0: */
{15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 },/* S1: */
{ 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 },/* S2: */
{ 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 },/* S3: */
{ 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 },/* S4: */
{15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 },/* S5: */
{ 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 },/* S6: */
{ 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 },/* S7: */
{ 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 },/* S0: */
{15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 },/* S1: */
{ 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 },/* S2: */
{ 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 },/* S3: */
{ 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 },/* S4: */
{15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 },/* S5: */
{ 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 },/* S6: */
{ 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 } /* S7: */
};

static final byte[][] SboxInverse = new byte[][] {
{13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 },/* InvS0: */
{ 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 },/* InvS1: */
{12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 },/* InvS2: */
{ 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 },/* InvS3: */
{ 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 },/* InvS4: */
{ 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 },/* InvS5: */
{15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 },/* InvS6: */
{ 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 },/* InvS7: */
{13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 },/* InvS0: */
{ 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 },/* InvS1: */
{12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 },/* InvS2: */
{ 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 },/* InvS3: */
{ 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 },/* InvS4: */
{ 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 },/* InvS5: */
{15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 },/* InvS6: */
{ 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 },/* InvS7: */
{13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 },/* InvS0: */
{ 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 },/* InvS1: */
{12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 },/* InvS2: */
{ 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 },/* InvS3: */
{ 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 },/* InvS4: */
{ 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 },/* InvS5: */
{15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 },/* InvS6: */
{ 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 },/* InvS7: */
{13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 },/* InvS0: */
{ 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 },/* InvS1: */
{12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 },/* InvS2: */
{ 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 },/* InvS3: */
{ 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 },/* InvS4: */
{ 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 },/* InvS5: */
{15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 },/* InvS6: */
{ 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 } /* InvS7: */
};

static final byte[] IPtable = new byte[] {
0, 32, 64, 96, 1, 33, 65, 97, 2, 34, 66, 98, 3, 35, 67, 99,
4, 36, 68, 100, 5, 37, 69, 101, 6, 38, 70, 102, 7, 39, 71, 103,
8, 40, 72, 104, 9, 41, 73, 105, 10, 42, 74, 106, 11, 43, 75, 107,
12, 44, 76, 108, 13, 45, 77, 109, 14, 46, 78, 110, 15, 47, 79, 111,
16, 48, 80, 112, 17, 49, 81, 113, 18, 50, 82, 114, 19, 51, 83, 115,
20, 52, 84, 116, 21, 53, 85, 117, 22, 54, 86, 118, 23, 55, 87, 119,
24, 56, 88, 120, 25, 57, 89, 121, 26, 58, 90, 122, 27, 59, 91, 123,
28, 60, 92, 124, 29, 61, 93, 125, 30, 62, 94, 126, 31, 63, 95, 127
};

static final byte[] FPtable = new byte[] {
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60,
64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124,
1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61,
65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125,
2, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62,
66, 70, 74, 78, 82, 86, 90, 94, 98, 102, 106, 110, 114, 118, 122, 126,
3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63,
67, 71, 75, 79, 83, 87, 91, 95, 99, 103, 107, 111, 115, 119, 123, 127
};

static final byte xFF = (byte) 0xFF;

/**
* The Linear Transformation is represented as an array of 128 rows,
* one for each output bit. Each one of the 128 rows, terminated by a
* marker (xFF) which isn't part of the data, is composed of up to 7
* quantities in the range 0-127 specifying the positions of the input
* bits that must be XORed together (say, 72, 144 and 125) to yield the
* output bit corresponding to the position of that list (say, 1).
*/
static final byte[][] LTtable = new byte[][] {
{16, 52, 56, 70, 83, 94, 105, xFF},
{72, 114, 125, xFF, xFF, xFF, xFF, xFF},
{ 2, 9, 15, 30, 76, 84, 126, xFF},
{36, 90, 103, xFF, xFF, xFF, xFF, xFF},
{20, 56, 60, 74, 87, 98, 109, xFF},
{ 1, 76, 118, xFF, xFF, xFF, xFF, xFF},
{ 2, 6, 13, 19, 34, 80, 88, xFF},
{40, 94, 107, xFF, xFF, xFF, xFF, xFF},
{24, 60, 64, 78, 91, 102, 113, xFF},
{ 5, 80, 122, xFF, xFF, xFF, xFF, xFF},
{ 6, 10, 17, 23, 38, 84, 92, xFF},
{44, 98, 111, xFF, xFF, xFF, xFF, xFF},
{28, 64, 68, 82, 95, 106, 117, xFF},
{ 9, 84, 126, xFF, xFF, xFF, xFF, xFF},
{10, 14, 21, 27, 42, 88, 96, xFF},
{48, 102, 115, xFF, xFF, xFF, xFF, xFF},
{32, 68, 72, 86, 99, 110, 121, xFF},
{ 2, 13, 88, xFF, xFF, xFF, xFF, xFF},
{14, 18, 25, 31, 46, 92, 100, xFF},
{52, 106, 119, xFF, xFF, xFF, xFF, xFF},
{36, 72, 76, 90, 103, 114, 125, xFF},
{ 6, 17, 92, xFF, xFF, xFF, xFF, xFF},
{18, 22, 29, 35, 50, 96, 104, xFF},
{56, 110, 123, xFF, xFF, xFF, xFF, xFF},
{ 1, 40, 76, 80, 94, 107, 118, xFF},
{10, 21, 96, xFF, xFF, xFF, xFF, xFF},
{22, 26, 33, 39, 54, 100, 108, xFF},
{60, 114, 127, xFF, xFF, xFF, xFF, xFF},
{ 5, 44, 80, 84, 98, 111, 122, xFF},
{14, 25, 100, xFF, xFF, xFF, xFF, xFF},
{26, 30, 37, 43, 58, 104, 112, xFF},
{ 3, 118, xFF, xFF, xFF, xFF, xFF, xFF},
{ 9, 48, 84, 88, 102, 115, 126, xFF},
{18, 29, 104, xFF, xFF, xFF, xFF, xFF},
{30, 34, 41, 47, 62, 108, 116, xFF},
{ 7, 122, xFF, xFF, xFF, xFF, xFF, xFF},
{ 2, 13, 52, 88, 92, 106, 119, xFF},
{22, 33, 108, xFF, xFF, xFF, xFF, xFF},
{34, 38, 45, 51, 66, 112, 120, xFF},
{11, 126, xFF, xFF, xFF, xFF, xFF, xFF},
{ 6, 17, 56, 92, 96, 110, 123, xFF},
{26, 37, 112, xFF, xFF, xFF, xFF, xFF},
{38, 42, 49, 55, 70, 116, 124, xFF},
{ 2, 15, 76, xFF, xFF, xFF, xFF, xFF},
{10, 21, 60, 96, 100, 114, 127, xFF},
{30, 41, 116, xFF, xFF, xFF, xFF, xFF},
{ 0, 42, 46, 53, 59, 74, 120, xFF},
{ 6, 19, 80, xFF, xFF, xFF, xFF, xFF},
{ 3, 14, 25, 100, 104, 118, xFF, xFF},
{34, 45, 120, xFF, xFF, xFF, xFF, xFF},
{ 4, 46, 50, 57, 63, 78, 124, xFF},
{10, 23, 84, xFF, xFF, xFF, xFF, xFF},
{ 7, 18, 29, 104, 108, 122, xFF, xFF},
{38, 49, 124, xFF, xFF, xFF, xFF, xFF},
{ 0, 8, 50, 54, 61, 67, 82, xFF},
{14, 27, 88, xFF, xFF, xFF, xFF, xFF},
{11, 22, 33, 108, 112, 126, xFF, xFF},
{ 0, 42, 53, xFF, xFF, xFF, xFF, xFF},
{ 4, 12, 54, 58, 65, 71, 86, xFF},
{18, 31, 92, xFF, xFF, xFF, xFF, xFF},
{ 2, 15, 26, 37, 76, 112, 116, xFF},
{ 4, 46, 57, xFF, xFF, xFF, xFF, xFF},
{ 8, 16, 58, 62, 69, 75, 90, xFF},
{22, 35, 96, xFF, xFF, xFF, xFF, xFF},
{ 6, 19, 30, 41, 80, 116, 120, xFF},
{ 8, 50, 61, xFF, xFF, xFF, xFF, xFF},
{12, 20, 62, 66, 73, 79, 94, xFF},
{26, 39, 100, xFF, xFF, xFF, xFF, xFF},
{10, 23, 34, 45, 84, 120, 124, xFF},
{12, 54, 65, xFF, xFF, xFF, xFF, xFF},
{16, 24, 66, 70, 77, 83, 98, xFF},
{30, 43, 104, xFF, xFF, xFF, xFF, xFF},
{ 0, 14, 27, 38, 49, 88, 124, xFF},
{16, 58, 69, xFF, xFF, xFF, xFF, xFF},
{20, 28, 70, 74, 81, 87, 102, xFF},
{34, 47, 108, xFF, xFF, xFF, xFF, xFF},
{ 0, 4, 18, 31, 42, 53, 92, xFF},
{20, 62, 73, xFF, xFF, xFF, xFF, xFF},
{24, 32, 74, 78, 85, 91, 106, xFF},
{38, 51, 112, xFF, xFF, xFF, xFF, xFF},
{ 4, 8, 22, 35, 46, 57, 96, xFF},
{24, 66, 77, xFF, xFF, xFF, xFF, xFF},
{28, 36, 78, 82, 89, 95, 110, xFF},
{42, 55, 116, xFF, xFF, xFF, xFF, xFF},
{ 8, 12, 26, 39, 50, 61, 100, xFF},
{28, 70, 81, xFF, xFF, xFF, xFF, xFF},
{32, 40, 82, 86, 93, 99, 114, xFF},
{46, 59, 120, xFF, xFF, xFF, xFF, xFF},
{12, 16, 30, 43, 54, 65, 104, xFF},
{32, 74, 85, xFF, xFF, xFF, xFF, xFF},
{36, 90, 103, 118, xFF, xFF, xFF, xFF},
{50, 63, 124, xFF, xFF, xFF, xFF, xFF},
{16, 20, 34, 47, 58, 69, 108, xFF},
{36, 78, 89, xFF, xFF, xFF, xFF, xFF},
{40, 94, 107, 122, xFF, xFF, xFF, xFF},
{ 0, 54, 67, xFF, xFF, xFF, xFF, xFF},
{20, 24, 38, 51, 62, 73, 112, xFF},
{40, 82, 93, xFF, xFF, xFF, xFF, xFF},
{44, 98, 111, 126, xFF, xFF, xFF, xFF},
{ 4, 58, 71, xFF, xFF, xFF, xFF, xFF},
{24, 28, 42, 55, 66, 77, 116, xFF},
{44, 86, 97, xFF, xFF, xFF, xFF, xFF},
{ 2, 48, 102, 115, xFF, xFF, xFF, xFF},
{ 8, 62, 75, xFF, xFF, xFF, xFF, xFF},
{28, 32, 46, 59, 70, 81, 120, xFF},
{48, 90, 101, xFF, xFF, xFF, xFF, xFF},
{ 6, 52, 106, 119, xFF, xFF, xFF, xFF},
{12, 66, 79, xFF, xFF, xFF, xFF, xFF},
{32, 36, 50, 63, 74, 85, 124, xFF},
{52, 94, 105, xFF, xFF, xFF, xFF, xFF},
{10, 56, 110, 123, xFF, xFF, xFF, xFF},
{16, 70, 83, xFF, xFF, xFF, xFF, xFF},
{ 0, 36, 40, 54, 67, 78, 89, xFF},
{56, 98, 109, xFF, xFF, xFF, xFF, xFF},
{14, 60, 114, 127, xFF, xFF, xFF, xFF},
{20, 74, 87, xFF, xFF, xFF, xFF, xFF},
{ 4, 40, 44, 58, 71, 82, 93, xFF},
{60, 102, 113, xFF, xFF, xFF, xFF, xFF},
{ 3, 18, 72, 114, 118, 125, xFF, xFF},
{24, 78, 91, xFF, xFF, xFF, xFF, xFF},
{ 8, 44, 48, 62, 75, 86, 97, xFF},
{64, 106, 117, xFF, xFF, xFF, xFF, xFF},
{ 1, 7, 22, 76, 118, 122, xFF, xFF},
{28, 82, 95, xFF, xFF, xFF, xFF, xFF},
{12, 48, 52, 66, 79, 90, 101, xFF},
{68, 110, 121, xFF, xFF, xFF, xFF, xFF},
{ 5, 11, 26, 80, 122, 126, xFF, xFF},
{32, 86, 99, xFF, xFF, xFF, xFF, xFF}
};

static final byte[][] LTtableInverse = new byte[][] {
{ 53, 55, 72, xFF, xFF, xFF, xFF, xFF},
{ 1, 5, 20, 90, xFF, xFF, xFF, xFF},
{ 15, 102, xFF, xFF, xFF, xFF, xFF, xFF},
{ 3, 31, 90, xFF, xFF, xFF, xFF, xFF},
{ 57, 59, 76, xFF, xFF, xFF, xFF, xFF},
{ 5, 9, 24, 94, xFF, xFF, xFF, xFF},
{ 19, 106, xFF, xFF, xFF, xFF, xFF, xFF},
{ 7, 35, 94, xFF, xFF, xFF, xFF, xFF},
{ 61, 63, 80, xFF, xFF, xFF, xFF, xFF},
{ 9, 13, 28, 98, xFF, xFF, xFF, xFF},
{ 23, 110, xFF, xFF, xFF, xFF, xFF, xFF},
{ 11, 39, 98, xFF, xFF, xFF, xFF, xFF},
{ 65, 67, 84, xFF, xFF, xFF, xFF, xFF},
{ 13, 17, 32, 102, xFF, xFF, xFF, xFF},
{ 27, 114, xFF, xFF, xFF, xFF, xFF, xFF},
{ 1, 3, 15, 20, 43, 102, xFF, xFF},
{ 69, 71, 88, xFF, xFF, xFF, xFF, xFF},
{ 17, 21, 36, 106, xFF, xFF, xFF, xFF},
{ 1, 31, 118, xFF, xFF, xFF, xFF, xFF},
{ 5, 7, 19, 24, 47, 106, xFF, xFF},
{ 73, 75, 92, xFF, xFF, xFF, xFF, xFF},
{ 21, 25, 40, 110, xFF, xFF, xFF, xFF},
{ 5, 35, 122, xFF, xFF, xFF, xFF, xFF},
{ 9, 11, 23, 28, 51, 110, xFF, xFF},
{ 77, 79, 96, xFF, xFF, xFF, xFF, xFF},
{ 25, 29, 44, 114, xFF, xFF, xFF, xFF},
{ 9, 39, 126, xFF, xFF, xFF, xFF, xFF},
{ 13, 15, 27, 32, 55, 114, xFF, xFF},
{ 81, 83, 100, xFF, xFF, xFF, xFF, xFF},
{ 1, 29, 33, 48, 118, xFF, xFF, xFF},
{ 2, 13, 43, xFF, xFF, xFF, xFF, xFF},
{ 1, 17, 19, 31, 36, 59, 118, xFF},
{ 85, 87, 104, xFF, xFF, xFF, xFF, xFF},
{ 5, 33, 37, 52, 122, xFF, xFF, xFF},
{ 6, 17, 47, xFF, xFF, xFF, xFF, xFF},
{ 5, 21, 23, 35, 40, 63, 122, xFF},
{ 89, 91, 108, xFF, xFF, xFF, xFF, xFF},
{ 9, 37, 41, 56, 126, xFF, xFF, xFF},
{ 10, 21, 51, xFF, xFF, xFF, xFF, xFF},
{ 9, 25, 27, 39, 44, 67, 126, xFF},
{ 93, 95, 112, xFF, xFF, xFF, xFF, xFF},
{ 2, 13, 41, 45, 60, xFF, xFF, xFF},
{ 14, 25, 55, xFF, xFF, xFF, xFF, xFF},
{ 2, 13, 29, 31, 43, 48, 71, xFF},
{ 97, 99, 116, xFF, xFF, xFF, xFF, xFF},
{ 6, 17, 45, 49, 64, xFF, xFF, xFF},
{ 18, 29, 59, xFF, xFF, xFF, xFF, xFF},
{ 6, 17, 33, 35, 47, 52, 75, xFF},
{101, 103, 120, xFF, xFF, xFF, xFF, xFF},
{ 10, 21, 49, 53, 68, xFF, xFF, xFF},
{ 22, 33, 63, xFF, xFF, xFF, xFF, xFF},
{ 10, 21, 37, 39, 51, 56, 79, xFF},
{105, 107, 124, xFF, xFF, xFF, xFF, xFF},
{ 14, 25, 53, 57, 72, xFF, xFF, xFF},
{ 26, 37, 67, xFF, xFF, xFF, xFF, xFF},
{ 14, 25, 41, 43, 55, 60, 83, xFF},
{ 0, 109, 111, xFF, xFF, xFF, xFF, xFF},
{ 18, 29, 57, 61, 76, xFF, xFF, xFF},
{ 30, 41, 71, xFF, xFF, xFF, xFF, xFF},
{ 18, 29, 45, 47, 59, 64, 87, xFF},
{ 4, 113, 115, xFF, xFF, xFF, xFF, xFF},
{ 22, 33, 61, 65, 80, xFF, xFF, xFF},
{ 34, 45, 75, xFF, xFF, xFF, xFF, xFF},
{ 22, 33, 49, 51, 63, 68, 91, xFF},
{ 8, 117, 119, xFF, xFF, xFF, xFF, xFF},
{ 26, 37, 65, 69, 84, xFF, xFF, xFF},
{ 38, 49, 79, xFF, xFF, xFF, xFF, xFF},
{ 26, 37, 53, 55, 67, 72, 95, xFF},
{ 12, 121, 123, xFF, xFF, xFF, xFF, xFF},
{ 30, 41, 69, 73, 88, xFF, xFF, xFF},
{ 42, 53, 83, xFF, xFF, xFF, xFF, xFF},
{ 30, 41, 57, 59, 71, 76, 99, xFF},
{ 16, 125, 127, xFF, xFF, xFF, xFF, xFF},
{ 34, 45, 73, 77, 92, xFF, xFF, xFF},
{ 46, 57, 87, xFF, xFF, xFF, xFF, xFF},
{ 34, 45, 61, 63, 75, 80, 103, xFF},
{ 1, 3, 20, xFF, xFF, xFF, xFF, xFF},
{ 38, 49, 77, 81, 96, xFF, xFF, xFF},
{ 50, 61, 91, xFF, xFF, xFF, xFF, xFF},
{ 38, 49, 65, 67, 79, 84, 107, xFF},
{ 5, 7, 24, xFF, xFF, xFF, xFF, xFF},
{ 42, 53, 81, 85, 100, xFF, xFF, xFF},
{ 54, 65, 95, xFF, xFF, xFF, xFF, xFF},
{ 42, 53, 69, 71, 83, 88, 111, xFF},
{ 9, 11, 28, xFF, xFF, xFF, xFF, xFF},
{ 46, 57, 85, 89, 104, xFF, xFF, xFF},
{ 58, 69, 99, xFF, xFF, xFF, xFF, xFF},
{ 46, 57, 73, 75, 87, 92, 115, xFF},
{ 13, 15, 32, xFF, xFF, xFF, xFF, xFF},
{ 50, 61, 89, 93, 108, xFF, xFF, xFF},
{ 62, 73, 103, xFF, xFF, xFF, xFF, xFF},
{ 50, 61, 77, 79, 91, 96, 119, xFF},
{ 17, 19, 36, xFF, xFF, xFF, xFF, xFF},
{ 54, 65, 93, 97, 112, xFF, xFF, xFF},
{ 66, 77, 107, xFF, xFF, xFF, xFF, xFF},
{ 54, 65, 81, 83, 95, 100, 123, xFF},
{ 21, 23, 40, xFF, xFF, xFF, xFF, xFF},
{ 58, 69, 97, 101, 116, xFF, xFF, xFF},
{ 70, 81, 111, xFF, xFF, xFF, xFF, xFF},
{ 58, 69, 85, 87, 99, 104, 127, xFF},
{ 25, 27, 44, xFF, xFF, xFF, xFF, xFF},
{ 62, 73, 101, 105, 120, xFF, xFF, xFF},
{ 74, 85, 115, xFF, xFF, xFF, xFF, xFF},
{ 3, 62, 73, 89, 91, 103, 108, xFF},
{ 29, 31, 48, xFF, xFF, xFF, xFF, xFF},
{ 66, 77, 105, 109, 124, xFF, xFF, xFF},
{ 78, 89, 119, xFF, xFF, xFF, xFF, xFF},
{ 7, 66, 77, 93, 95, 107, 112, xFF},
{ 33, 35, 52, xFF, xFF, xFF, xFF, xFF},
{ 0, 70, 81, 109, 113, xFF, xFF, xFF},
{ 82, 93, 123, xFF, xFF, xFF, xFF, xFF},
{ 11, 70, 81, 97, 99, 111, 116, xFF},
{ 37, 39, 56, xFF, xFF, xFF, xFF, xFF},
{ 4, 74, 85, 113, 117, xFF, xFF, xFF},
{ 86, 97, 127, xFF, xFF, xFF, xFF, xFF},
{ 15, 74, 85, 101, 103, 115, 120, xFF},
{ 41, 43, 60, xFF, xFF, xFF, xFF, xFF},
{ 8, 78, 89, 117, 121, xFF, xFF, xFF},
{ 3, 90, xFF, xFF, xFF, xFF, xFF, xFF},
{ 19, 78, 89, 105, 107, 119, 124, xFF},
{ 45, 47, 64, xFF, xFF, xFF, xFF, xFF},
{ 12, 82, 93, 121, 125, xFF, xFF, xFF},
{ 7, 94, xFF, xFF, xFF, xFF, xFF, xFF},
{ 0, 23, 82, 93, 109, 111, 123, xFF},
{ 49, 51, 68, xFF, xFF, xFF, xFF, xFF},
{ 1, 16, 86, 97, 125, xFF, xFF, xFF},
{ 11, 98, xFF, xFF, xFF, xFF, xFF, xFF},
{ 4, 27, 86, 97, 113, 115, 127, xFF}
};

private static final char[] HEX_DIGITS = {
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
};


// Basic API methods
//...........................................................................

/**
* Expand a user-supplied key material into a session key.
*
* @param key The user-key bytes (multiples of 4) to use.
* @exception InvalidKeyException If the key is invalid.
*/
public static synchronized Object makeKey (byte[] key)
throws InvalidKeyException {
if (DEBUG) trace(IN, "makeKey("+key+")");
if (DEBUG && debuglevel > 7) {
System.out.println("Intermediate Standard Session Key Values");
System.out.println();
System.out.println("Raw="+toString(key));
}
// compute prekeys w[]:
// (a) from user key material
int[] w = new int[4 * (ROUNDS + 1)];
int offset = 0;
int limit = key.length / 4;
int i, j;
for (i = 0; i < limit; i++)
w[i] = (key[offset++] & 0xFF) |
(key[offset++] & 0xFF) << 8 |
(key[offset++] & 0xFF) << 16 |
(key[offset++] & 0xFF) << 24;

if (i < 8)
w[i++] = 1;
// for (; i < 8; i++)
// w[i] = 0;

// (b) and expanding them to full 132 x 32-bit material
// this is a literal implementation of the Serpent paper
// (section 4 The Key Schedule, p.226)
int t;
// start by computing the first 8 values using the second
// lot of 8 values as an intermediary buffer
for (i = 8, j = 0; i < 16; i++) {
t = w[j] ^ w[i-5] ^ w[i-3] ^ w[i-1] ^ PHI ^ j++;
w[i] = t << 11 | t >>> 21;
}
// translate the buffer by -8
for (i = 0, j = 8; i < 8; ) w[i++] = w[j++];
limit = 4 * (ROUNDS + 1); // 132 for a 32-round Serpent
// finish computing the remaining intermediary subkeys
for ( ; i < limit; i++) {
t = w[i-8] ^ w[i-5] ^ w[i-3] ^ w[i-1] ^ PHI ^ i;
w[i] = t << 11 | t >>> 21;
}
if (DEBUG && debuglevel > 8) for(i=0;i<limit;i++) debug("w["+i+"]: "+intToString(w[i]));
// compute intermediary key into k[]
int[] k = new int[limit];
int box, a, b, c, d, in, out;
for (i = 0; i < ROUNDS + 1; i++) {
box = (ROUNDS + 3 - i) % ROUNDS;
a = w[4*i ];
b = w[4*i + 1];
c = w[4*i + 2];
d = w[4*i + 3];
for (j = 0; j < 32; j++) {
in = getBit(a, j) |
getBit(b, j) << 1 |
getBit(c, j) << 2 |
getBit(d, j) << 3;
out = S(box, in);
k[4*i ] |= getBit(out, 0) << j;
k[4*i + 1] |= getBit(out, 1) << j;
k[4*i + 2] |= getBit(out, 2) << j;
k[4*i + 3] |= getBit(out, 3) << j;
}
}
// renumber the 32-bit values k[] as 128-bit subkeys K[][]
int[][] K = new int[ROUNDS + 1][4];
for (i = 0, offset = 0; i < ROUNDS + 1; i++) {
K[i][0] = k[offset++];
K[i][1] = k[offset++];
K[i][2] = k[offset++];
K[i][3] = k[offset++];
if (DEBUG && debuglevel > 8) debug("K["+i+"]: "+toReversedString(K[i]));
}
// we now apply IP to the round key in order to place the key bits
// in the correct column; ie. Khat[i] = IP(K[i]) --we use same K
for (i = 0; i < ROUNDS + 1; i++) {
K[i] = IP(K[i]);
if (DEBUG && debuglevel > 7) debug("Khat["+i+"]: "+toReversedString(K[i]));
}
if (DEBUG && debuglevel > 7) {
for (i=0;i<ROUNDS+1;i++) System.out.println("K"+i+"="+toString(K[i]));
System.out.println();
}
if (DEBUG) trace(OUT, "makeKey()");
return K;
}

/**
* 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.
* @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("+toString(in)+", "+inOffset+", "+sessionKey+")");
int[][] Khat = (int[][]) sessionKey;
int[] x = {
(in[inOffset++] & 0xFF) | (in[inOffset++] & 0xFF) << 8 |
(in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 24,
(in[inOffset++] & 0xFF) | (in[inOffset++] & 0xFF) << 8 |
(in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 24,
(in[inOffset++] & 0xFF) | (in[inOffset++] & 0xFF) << 8 |
(in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 24,
(in[inOffset++] & 0xFF) | (in[inOffset++] & 0xFF) << 8 |
(in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 24
};
int[] Bhat = IP(x);
if (DEBUG && debuglevel > 6) System.out.println("IP(PT)="+toString(Bhat));
for (int i = 0; i < ROUNDS; i++) {
Bhat = R(i, Bhat, Khat);
if (DEBUG && debuglevel > 6) System.out.println("CT"+i+"="+toString(Bhat));
}
if (DEBUG && debuglevel > 5) debug("Bhat[32]: "+toReversedString(Bhat));
x = FP(Bhat);

int a = x[0], b = x[1], c = x[2], d = x[3];
byte[] result = new byte[] {
(byte)(a), (byte)(a >>> 8), (byte)(a >>> 16), (byte)(a >>> 24),
(byte)(b), (byte)(b >>> 8), (byte)(b >>> 16), (byte)(b >>> 24),
(byte)(c), (byte)(c >>> 8), (byte)(c >>> 16), (byte)(c >>> 24),
(byte)(d), (byte)(d >>> 8), (byte)(d >>> 16), (byte)(d >>> 24)
};
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.
* @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("+toString(in)+", "+inOffset+", "+sessionKey+")");
int[][] Khat = (int[][]) sessionKey;
int[] x = {
(in[inOffset++] & 0xFF) | (in[inOffset++] & 0xFF) << 8 |
(in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 24,
(in[inOffset++] & 0xFF) | (in[inOffset++] & 0xFF) << 8 |
(in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 24,
(in[inOffset++] & 0xFF) | (in[inOffset++] & 0xFF) << 8 |
(in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 24,
(in[inOffset++] & 0xFF) | (in[inOffset++] & 0xFF) << 8 |
(in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 24
};
int[] Bhat = FPinverse(x);
if (DEBUG && debuglevel > 6) System.out.println("FP'(CT)="+toString(Bhat));
for (int i = ROUNDS - 1; i >= 0; i--) {
Bhat = Rinverse(i, Bhat, Khat);
if (DEBUG && debuglevel > 6) System.out.println("PT"+i+"="+toString(Bhat));
}
if (DEBUG && debuglevel > 5) debug("Bhat[0]: "+toReversedString(Bhat));
x = IPinverse(Bhat);

int a = x[0], b = x[1], c = x[2], d = x[3];
byte[] result = new byte[] {
(byte)(a), (byte)(a >>> 8), (byte)(a >>> 16), (byte)(a >>> 24),
(byte)(b), (byte)(b >>> 8), (byte)(b >>> 16), (byte)(b >>> 24),
(byte)(c), (byte)(c >>> 8), (byte)(c >>> 16), (byte)(c >>> 24),
(byte)(d), (byte)(d >>> 8), (byte)(d >>> 16), (byte)(d >>> 24)
};
if (DEBUG && debuglevel > 6) {
System.out.println("PT="+toString(result));
System.out.println();
}
if (DEBUG) trace(OUT, "blockDecrypt()");
return result;
}



public static byte[]
blockDecryptGetP (int in, int val, int inOffset, Object sessionKey) {
int[][] Khat = (int[][]) sessionKey;
int[] x = {0, 0, 0, 0};
int[] Bhat = FPinverse(x);
for (int i = ROUNDS - 1; i >= 0; i--) {
Bhat = Rinverse(i, Bhat, Khat, in, val);
}
x = IPinverse(Bhat);

int a = x[0], b = x[1], c = x[2], d = x[3];
byte[] result = new byte[] {
(byte)(a), (byte)(a >>> 8), (byte)(a >>> 16), (byte)(a >>> 24),
(byte)(b), (byte)(b >>> 8), (byte)(b >>> 16), (byte)(b >>> 24),
(byte)(c), (byte)(c >>> 8), (byte)(c >>> 16), (byte)(c >>> 24),
(byte)(d), (byte)(d >>> 8), (byte)(d >>> 16), (byte)(d >>> 24)
};
if (DEBUG && debuglevel > 6) {
System.out.println("PT="+toString(result));
System.out.println();
}
if (DEBUG) trace(OUT, "blockDecrypt()");
return result;
}


// own methods
//...........................................................................

/**
* @return The bit value at position <code>i</code> in a 32-bit entity,
* where the least significant bit (the rightmost one) is at
* position 0.
*/
private static int getBit (int x, int i) { return (x >>> i) & 0x01; }

/**
* @return The bit value at position <code>i</code> in an array of 32-bit
* entities, where the least significant 32-bit entity is at index
* position 0 and the least significant bit (the rightmost one) in
* any 32-bit entity is at position 0.
*/
private static int getBit (int[] x, int i) {
return (x[i / 32] >>> (i % 32)) & 0x01;
}

/**
* Set the bit at position <code>i</code> in an array of 32-bit entities
* to a given value <code>v</code>, where the least significant 32-bit
* entity is at index position 0 and the least significant bit (the
* rightmost one) in any 32-bit entity is at position 0.
*/
private static void setBit (int[] x, int i, int v) {
if ((v & 0x01) == 1)
x[i / 32] |= 1 << (i % 32); // set it
else
x[i / 32] &= ~(1 << (i % 32)); // clear it
}

/**
* @return The nibble --a 4-bit entity-- in <code>x</code> given its
* position <code>i</code>, where the least significant nibble
* (the rightmost one) is at position 0.
*/
private static int getNibble (int x, int i) { return (x >>> (4 * i)) & 0x0F; }

/**
* @return A 128-bit entity which is the result of applying the Initial
* Permutation (IP) to a 128-bit entity <code>x</code>.
*/
private static int[] IP (int[] x) { return permutate(IPtable, x); }

/**
* @return A 128-bit entity which is the result of applying the inverse of
* the Initial Permutation to a 128-bit entity <code>x</code>.
*/
private static int[] IPinverse (int[] x) { return permutate(FPtable, x); }

/**
* @return A 128-bit entity which is the result of applying the Final
* Permutation (FP) to a 128-bit entity <code>x</code>.
*/
private static int[] FP (int[] x) { return permutate(FPtable, x); }

/**
* @return A 128-bit entity which is the result of applying the inverse of
* the Final Permutation to a 128-bit entity <code>x</code>.
*/
private static int[] FPinverse (int[] x) { return permutate(IPtable, x); }

/**
* @return A 128-bit entity which is the result of applying a permutation
* coded in a given table <code>T</code> to a 128-bit entity
* <code>x</code>.
*/
private static int[] permutate (byte[] T, int[] x) {
int[] result = new int[4];
for (int i = 0; i < 128; i++)
setBit(result, i, getBit(x, T[i] & 0x7F));
return result;
}

/**
* @return A 128-bit entity as the result of XORing, bit-by-bit, two given
* 128-bit entities <code>x</code> and <code>y</code>.
*/
private static int[] xor128 (int[] x, int[] y) {
return new int[] {x[0] ^ y[0], x[1] ^ y[1], x[2] ^ y[2], x[3] ^ y[3]};
}

/**
* @return The nibble --a 4-bit entity-- obtained by applying a given
* S-box to a 32-bit entity <code>x</code>.
*/
private static int S (int box, int x) { return Sbox[box][x] & 0x0F; }

/**
* @return The nibble --a 4-bit entity-- obtained byapplying the inverse
* of a given S-box to a 32-bit entity <code>x</code>.
*/
private static int Sinverse (int box, int x) { return SboxInverse[box][x] & 0x0F; }

/**
* @return A 128-bit entity being the result of applying, in parallel,
* 32 copies of a given S-box to a 128-bit entity <code>x</code>.
*/
private static int[] Shat (int box, int[] x) {
int[] result = new int[4];
for (int i = 0; i < 4; i++)
for (int nibble = 0; nibble < 8; nibble++)
result[i] |= S(box, getNibble(x[i], nibble)) << (nibble * 4);
return result;
}

/**
* @return A 128-bit entity being the result of applying, in parallel,
* 32 copies of the inverse of a given S-box to a 128-bit entity
* <code>x</code>.
*/
private static int[] ShatInverse (int box, int[] x) {
int[] result = new int[4];
for (int i = 0; i < 4; i++)
for (int nibble = 0; nibble < 8; nibble++)
result[i] |= Sinverse(box, getNibble(x[i], nibble)) << (nibble * 4);
return result;
}

/**
* @return A 128-bit entity being the result of applying the linear
* transformation to a 128-bit entity <code>x</code>.
*/
private static int[] LT (int[] x) { return transform(LTtable, x); }

/**
* @return A 128-bit entity being the result of applying the inverse of
* the linear transformation to a 128-bit entity <code>x</code>.
*/
private static int[] LTinverse (int[] x) {
return transform(LTtableInverse, x);
}

/**
* @return A 128-bit entity being the result of applying a transformation
* coded in a table <code>T</code> to a 128-bit entity <code>x</code>.
* Each row, of say index <code>i</code>, in <code>T</code> indicates
* the bits from <code>x</code> to be XORed together in order to
* produce the resulting bit at position <code>i</code>.
*/
private static int[] transform (byte[][] T, int[] x) {
int j, b;
int[] result = new int[4];
for (int i = 0; i < 128; i++) {
b = 0;
j = 0;
while (T[i][j] != xFF) {
b ^= getBit(x, T[i][j] & 0x7F);
j++;
}
setBit(result, i, b);
}
return result;
}

/**
* @return the 128-bit entity as the result of applying the round function
* R at round <code>i</code> to the 128-bit entity <code>Bhati</code>,
* using the appropriate subkeys from <code>Khat</code>.
*/
private static int[] R (int i, int[] Bhati, int[][] Khat) {
if (DEBUG && debuglevel > 6) debug("Bhat["+i+"]: "+toReversedString(Bhati));
int[] xored = xor128(Bhati, Khat[i]);
if (DEBUG && debuglevel > 6) debug("xored["+i+"]: "+toReversedString(xored));
int[] Shati = Shat(i, xored);
if (DEBUG && debuglevel > 6) debug("Shat["+i+"]: "+toReversedString(Shati));
int[] BhatiPlus1;
if ((0 <= i) && (i <= ROUNDS - 2))
BhatiPlus1 = LT(Shati);
else if (i == ROUNDS - 1)
BhatiPlus1 = xor128(Shati, Khat[ROUNDS]);
else
throw new RuntimeException(
"Round "+i+" is out of 0.."+(ROUNDS-1)+" range");
return BhatiPlus1;
}

/**
* @return the 128-bit entity as the result of applying the inverse of
* the round function R at round <code>i</code> to the 128-bit
* entity <code>Bhati</code>, using the appropriate subkeys from
* <code>Khat</code>.
*/
private static int[] Rinverse (int i, int[] BhatiPlus1, int[][] Khat) {
if (DEBUG && debuglevel > 6) debug("Bhat["+i+"+1]: "+toReversedString(BhatiPlus1));
int[] Shati = new int[4];
if ((0 <= i) && (i <= ROUNDS - 2))
Shati = LTinverse(BhatiPlus1);
else if (i == ROUNDS - 1)
Shati = xor128(BhatiPlus1, Khat[ROUNDS]);
else
throw new RuntimeException(
"Round "+i+" is out of 0.."+(ROUNDS-1)+" range");
if (DEBUG && debuglevel > 6) debug("Shat["+i+"]: "+toReversedString(Shati));
int[] xored = ShatInverse(i, Shati);
if (DEBUG && debuglevel > 6) debug("xored["+i+"]: "+toReversedString(xored));
int[] Bhati = xor128(xored, Khat[i]);
return Bhati;
}

private static int[] Rinverse (int i, int[] BhatiPlus1, int[][] Khat, int in, int val) {
int[] Shati = new int[4];
if ((0 <= i) && (i <= ROUNDS - 2))
Shati = LTinverse(BhatiPlus1);
else if (i == ROUNDS - 1)
Shati = xor128(BhatiPlus1, Khat[ROUNDS]);
else
throw new RuntimeException(
"Round "+i+" is out of 0.."+(ROUNDS-1)+" range");
int[] xored = ShatInverse(i, Shati);
if(i==in) {
xored[0] = val | (val<<4);
xored[0] |= (xored[0]<<8);
xored[0] |= (xored[0]<<16);
xored[1] = xored[2] = xored[3] = xored[0];
}
int[] Bhati = xor128(xored, Khat[i]);
return Bhati;
}


// utility static methods (from cryptix.util.core.Hex class)
//...........................................................................

/**
* Returns a string of 8 hexadecimal digits (most significant
* digit first) corresponding to the integer <i>n</i>, which is
* treated as unsigned.
*/
public 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);
}


// other utility static methods
//...........................................................................

/**
* Returns an hexadecimal number (respresented as a string of hexadecimal
* digits from a byte array). Each byte is converted to 2 hex symbols.
* The order is however, as of printing a number from a little-endian
* internal representation (i.e., reverse order).
*/
public static String toReversedString (byte[] ba) {
int length = ba.length;
char[] buf = new char[length * 2];
for (int i = length-1, j = 0, k; i >=0; ) {
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 toReversedString (int[] ia) {
int length = ia.length;
char[] buf = new char[length * 8];
for (int i = length-1, j = 0, k; i >= 0; 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);
}
}
Соседние файлы в папке Serpent