www.pudn.com > serpent.rar > Serpent_Standard.java


// $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.

* * 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.

* * Serpent was designed by Ross Anderson, Eli Biham and Lars Knudsen as a * candidate algorithm for the NIST AES Quest.

* * References:

    *
  1. 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.

    *

  2. Reference implementation of the standard Serpent cipher written in C * by Frank Stajano.

* * Copyright © 1997, 1998 * Systemics Ltd on behalf of the * Cryptix Development Team. *
All rights reserved.

* * $Revision: $ * @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.

* * 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 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 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 i 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 i 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 i in an array of 32-bit entities * to a given value v, 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 x given its * position i, 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 x. */ 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 x. */ 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 x. */ 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 x. */ 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 T to a 128-bit entity * x. */ 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 x and y. */ 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 x. */ 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 x. */ 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 x. */ 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 * x. */ 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 x. */ 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 x. */ 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 T to a 128-bit entity x. * Each row, of say index i, in T indicates * the bits from x to be XORed together in order to * produce the resulting bit at position i. */ 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 i to the 128-bit entity Bhati, * using the appropriate subkeys from Khat. */ 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 i to the 128-bit * entity Bhati, using the appropriate subkeys from * Khat. */ 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 n, 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); } }