what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

serpref.c

serpref.c
Posted Dec 21, 1999

serpref.c

tags | encryption
SHA-256 | eff1120440904f6c33d7554e3b24a00b0032e4e8446b67a521f24af0618c4d98

serpref.c

Change Mirror Download
serpref.c

/*
$RCSfile: Serpref.c,v $
$Id: Serpref.c,v 1.15 1998/03/06 18:48:10 fms Exp $
written by Frank Stajano, http://www.cl.cam.ac.uk/~fms/
Cambridge University Computer Laboratory
Original (Python) Serpent reference development started on 1998 02 12
C implementation development started on 1998 03 04

Serpent cipher invented by Eli Biham, Ross Anderson, Lars Knudsen.

This is a reference implementation of the Serpent cipher invented by Eli
Biham, Ross Anderson, Lars Knudsen. It is written for the human reader more
than for the machine and, as such, it is optimised for clarity rather than
speed. ("Premature optimisation is the root of all evil.")

It can selectively print out all the intermediate results (such as the
subkeys) for a given input so that implementers debugging erroneous code
can quickly verify which one of the building blocks is giving the wrong
answers. */

/* -------------------------------------------------- */
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned long word;
/* This must be at least 32 bits, but the code has been made safe to use on
machines with longer word size (the top bits will just be ignored). */

/* C's weak type checking won't help us much with the following
pseudo-types: I use them mostly to make it clear to the human reader
what the parameters to the functions are _meant_ to be, not to expect
help from the compiler. */
typedef unsigned char byte;
typedef unsigned char nibble; /* convention: only the bottom 4 bits are used */
typedef unsigned char bit; /* convention: only the bottom bit is used */

typedef int permutationTable[128];
typedef byte xorTable[128][8];
/* -------------------------------------------------- */

#define r 32
#define phi 0x9e3779b9


/* Each row of this array corresponds to one S-box. Each S-box in turn is
an array of 16 integers in the range 0..15, without repetitions. Having
the value v (say, 14) in position p (say, 0) means that if the input to
that S-box is the pattern p (0, or 0x0) then the output will be the
pattern v (14, or 0xe). */
nibble SBox[][16] = {
{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
{0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
{4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
{15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13},
{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
{3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
{0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
{13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9},
{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
{13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
{13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
{1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12},
{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
{13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
{10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
{3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14},
{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
{14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
{4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
{11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3},
{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
{10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
{9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
{4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13},
{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
{13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
{1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
{6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12},
{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
{1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
{7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
{2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}
};

nibble SBoxInverse[][16] = {
{14, 3, 4, 8, 1, 12, 10, 15, 7, 13, 9, 6, 11, 2, 0, 5},
{0, 7, 5, 14, 3, 13, 9, 2, 15, 12, 8, 11, 10, 6, 4, 1},
{15, 1, 6, 12, 0, 14, 5, 11, 3, 10, 13, 7, 9, 4, 2, 8},
{13, 6, 3, 10, 4, 8, 14, 7, 2, 5, 12, 9, 1, 15, 11, 0},
{13, 1, 10, 6, 7, 14, 4, 9, 2, 8, 15, 5, 12, 11, 3, 0},
{9, 10, 5, 0, 2, 15, 12, 3, 6, 13, 11, 14, 8, 1, 7, 4},
{0, 7, 14, 13, 5, 8, 11, 2, 9, 12, 4, 3, 10, 6, 1, 15},
{12, 3, 7, 4, 6, 13, 9, 10, 1, 15, 2, 8, 11, 0, 14, 5},
{1, 8, 14, 5, 13, 7, 4, 11, 15, 2, 0, 12, 10, 9, 3, 6},
{2, 15, 8, 4, 5, 10, 6, 1, 9, 3, 7, 13, 12, 0, 11, 14},
{7, 9, 10, 6, 2, 12, 1, 15, 4, 3, 13, 8, 11, 0, 14, 5},
{3, 0, 14, 11, 8, 13, 4, 7, 6, 5, 1, 12, 15, 2, 10, 9},
{4, 8, 9, 3, 14, 11, 5, 0, 10, 6, 7, 12, 13, 1, 2, 15},
{6, 12, 10, 7, 8, 3, 4, 9, 1, 15, 13, 2, 11, 0, 14, 5},
{3, 9, 13, 10, 15, 12, 1, 6, 14, 2, 0, 5, 4, 7, 11, 8},
{2, 5, 14, 0, 9, 10, 3, 13, 7, 8, 4, 11, 12, 6, 15, 1},
{13, 3, 0, 10, 2, 9, 7, 4, 8, 15, 5, 6, 1, 12, 14, 11},
{9, 7, 2, 12, 4, 8, 15, 5, 14, 13, 11, 1, 3, 6, 0, 10},
{14, 2, 1, 13, 0, 11, 12, 6, 7, 9, 4, 3, 10, 5, 15, 8},
{10, 4, 6, 15, 13, 14, 8, 3, 1, 11, 12, 0, 2, 7, 5, 9},
{8, 1, 5, 10, 11, 14, 6, 13, 7, 4, 2, 15, 0, 9, 12, 3},
{12, 9, 3, 14, 2, 7, 8, 4, 15, 6, 0, 13, 5, 10, 11, 1},
{9, 12, 4, 7, 10, 3, 15, 8, 5, 0, 11, 14, 6, 13, 1, 2},
{13, 10, 2, 1, 0, 5, 12, 11, 14, 4, 7, 8, 3, 15, 9, 6},
{5, 15, 2, 8, 0, 12, 14, 11, 6, 10, 13, 1, 9, 7, 3, 4},
{1, 6, 12, 9, 4, 10, 15, 3, 14, 5, 7, 2, 11, 0, 8, 13},
{12, 0, 15, 5, 1, 13, 10, 6, 11, 14, 8, 2, 4, 3, 7, 9},
{10, 4, 13, 14, 5, 9, 0, 7, 3, 8, 6, 1, 15, 2, 12, 11},
{13, 7, 1, 10, 3, 12, 4, 15, 2, 9, 8, 6, 14, 0, 11, 5},
{12, 0, 15, 5, 7, 9, 10, 6, 3, 14, 4, 11, 8, 2, 13, 1},
{8, 3, 7, 13, 2, 14, 9, 0, 15, 4, 10, 1, 5, 11, 6, 12},
{11, 1, 0, 12, 4, 13, 14, 3, 6, 10, 5, 15, 9, 7, 2, 8}
};

/* The Initial and Final permutations are each represented by an array
containing the integers in 0..127 without repetitions. Having value v
(say, 32) at position p (say, 1) means that the output bit at position p
(1) comes from the input bit at position v (32). Note that the two
tables are the inverse of each other (IPTableInverse == FPTable).*/
permutationTable IPTable = {
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
};
permutationTable FPTable = {
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
};

/* 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
which isn't part of the data, is composed of up to 7 integers 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). */
#define MARKER 0xff
xorTable LTTable = {
{16, 52, 56, 70, 83, 94, 105, MARKER},
{72, 114, 125, MARKER},
{2, 9, 15, 30, 76, 84, 126, MARKER},
{36, 90, 103, MARKER},
{20, 56, 60, 74, 87, 98, 109, MARKER},
{1, 76, 118, MARKER},
{2, 6, 13, 19, 34, 80, 88, MARKER},
{40, 94, 107, MARKER},
{24, 60, 64, 78, 91, 102, 113, MARKER},
{5, 80, 122, MARKER},
{6, 10, 17, 23, 38, 84, 92, MARKER},
{44, 98, 111, MARKER},
{28, 64, 68, 82, 95, 106, 117, MARKER},
{9, 84, 126, MARKER},
{10, 14, 21, 27, 42, 88, 96, MARKER},
{48, 102, 115, MARKER},
{32, 68, 72, 86, 99, 110, 121, MARKER},
{2, 13, 88, MARKER},
{14, 18, 25, 31, 46, 92, 100, MARKER},
{52, 106, 119, MARKER},
{36, 72, 76, 90, 103, 114, 125, MARKER},
{6, 17, 92, MARKER},
{18, 22, 29, 35, 50, 96, 104, MARKER},
{56, 110, 123, MARKER},
{1, 40, 76, 80, 94, 107, 118, MARKER},
{10, 21, 96, MARKER},
{22, 26, 33, 39, 54, 100, 108, MARKER},
{60, 114, 127, MARKER},
{5, 44, 80, 84, 98, 111, 122, MARKER},
{14, 25, 100, MARKER},
{26, 30, 37, 43, 58, 104, 112, MARKER},
{3, 118, MARKER},
{9, 48, 84, 88, 102, 115, 126, MARKER},
{18, 29, 104, MARKER},
{30, 34, 41, 47, 62, 108, 116, MARKER},
{7, 122, MARKER},
{2, 13, 52, 88, 92, 106, 119, MARKER},
{22, 33, 108, MARKER},
{34, 38, 45, 51, 66, 112, 120, MARKER},
{11, 126, MARKER},
{6, 17, 56, 92, 96, 110, 123, MARKER},
{26, 37, 112, MARKER},
{38, 42, 49, 55, 70, 116, 124, MARKER},
{2, 15, 76, MARKER},
{10, 21, 60, 96, 100, 114, 127, MARKER},
{30, 41, 116, MARKER},
{0, 42, 46, 53, 59, 74, 120, MARKER},
{6, 19, 80, MARKER},
{3, 14, 25, 100, 104, 118, MARKER},
{34, 45, 120, MARKER},
{4, 46, 50, 57, 63, 78, 124, MARKER},
{10, 23, 84, MARKER},
{7, 18, 29, 104, 108, 122, MARKER},
{38, 49, 124, MARKER},
{0, 8, 50, 54, 61, 67, 82, MARKER},
{14, 27, 88, MARKER},
{11, 22, 33, 108, 112, 126, MARKER},
{0, 42, 53, MARKER},
{4, 12, 54, 58, 65, 71, 86, MARKER},
{18, 31, 92, MARKER},
{2, 15, 26, 37, 76, 112, 116, MARKER},
{4, 46, 57, MARKER},
{8, 16, 58, 62, 69, 75, 90, MARKER},
{22, 35, 96, MARKER},
{6, 19, 30, 41, 80, 116, 120, MARKER},
{8, 50, 61, MARKER},
{12, 20, 62, 66, 73, 79, 94, MARKER},
{26, 39, 100, MARKER},
{10, 23, 34, 45, 84, 120, 124, MARKER},
{12, 54, 65, MARKER},
{16, 24, 66, 70, 77, 83, 98, MARKER},
{30, 43, 104, MARKER},
{0, 14, 27, 38, 49, 88, 124, MARKER},
{16, 58, 69, MARKER},
{20, 28, 70, 74, 81, 87, 102, MARKER},
{34, 47, 108, MARKER},
{0, 4, 18, 31, 42, 53, 92, MARKER},
{20, 62, 73, MARKER},
{24, 32, 74, 78, 85, 91, 106, MARKER},
{38, 51, 112, MARKER},
{4, 8, 22, 35, 46, 57, 96, MARKER},
{24, 66, 77, MARKER},
{28, 36, 78, 82, 89, 95, 110, MARKER},
{42, 55, 116, MARKER},
{8, 12, 26, 39, 50, 61, 100, MARKER},
{28, 70, 81, MARKER},
{32, 40, 82, 86, 93, 99, 114, MARKER},
{46, 59, 120, MARKER},
{12, 16, 30, 43, 54, 65, 104, MARKER},
{32, 74, 85, MARKER},
{36, 90, 103, 118, MARKER},
{50, 63, 124, MARKER},
{16, 20, 34, 47, 58, 69, 108, MARKER},
{36, 78, 89, MARKER},
{40, 94, 107, 122, MARKER},
{0, 54, 67, MARKER},
{20, 24, 38, 51, 62, 73, 112, MARKER},
{40, 82, 93, MARKER},
{44, 98, 111, 126, MARKER},
{4, 58, 71, MARKER},
{24, 28, 42, 55, 66, 77, 116, MARKER},
{44, 86, 97, MARKER},
{2, 48, 102, 115, MARKER},
{8, 62, 75, MARKER},
{28, 32, 46, 59, 70, 81, 120, MARKER},
{48, 90, 101, MARKER},
{6, 52, 106, 119, MARKER},
{12, 66, 79, MARKER},
{32, 36, 50, 63, 74, 85, 124, MARKER},
{52, 94, 105, MARKER},
{10, 56, 110, 123, MARKER},
{16, 70, 83, MARKER},
{0, 36, 40, 54, 67, 78, 89, MARKER},
{56, 98, 109, MARKER},
{14, 60, 114, 127, MARKER},
{20, 74, 87, MARKER},
{4, 40, 44, 58, 71, 82, 93, MARKER},
{60, 102, 113, MARKER},
{3, 18, 72, 114, 118, 125, MARKER},
{24, 78, 91, MARKER},
{8, 44, 48, 62, 75, 86, 97, MARKER},
{64, 106, 117, MARKER},
{1, 7, 22, 76, 118, 122, MARKER},
{28, 82, 95, MARKER},
{12, 48, 52, 66, 79, 90, 101, MARKER},
{68, 110, 121, MARKER},
{5, 11, 26, 80, 122, 126, MARKER},
{32, 86, 99, MARKER}
};

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

/* To aid debugging, the listing is peppered with show* statements that
will conditionally print the intermediate values of various quantities. You
request what you want to be printed by specifying its tag with the -t
command line flag. */

char** tagv; /* actually a subset of argv */
int tagAll = 0; /* true iff the overriding 'ALL' tag is present */

int requiredTag(char* label) {
/* Return true iff "show statements" (q.v.) marked by 'label' ought to be
printed. WARNING: this accesses the global variables 'tag*'. */
int i = 0;

if (tagAll) {
return 1;
}
while (tagv[i]) {
if (strcmp(label, tagv[i]) == 0) {
return 1;
} else {
i++;
}
}
return 0;
}

void show(char* label, char* value, int i) {
/* If 'label' isn't among the required tags, ignore the call. Otherwise
print out a line with the current value of 'i', the 'label' and the
'value'. */

if (!requiredTag(label)) {
return;
}
printf("[i=%3d] %s = %s\n", i, label, value);
}

void show128(char* label, word value[], int i) {
/* Show (q.v.) a 128-bit value. */

char buffer[(2+8+1)*4];

sprintf(buffer, "0x%08lx 0x%08lx 0x%08lx 0x%08lx",
value[0], value[1], value[2], value[3]);
show(label, buffer, i);
}

void show32(char* label, word value, int i) {
/* Show (q.v.) a 32-bit value. */

char buffer[2+8+1];

sprintf(buffer, "0x%08lx", value);
show(label, buffer, i);
}

/* -------------------------------------------------- */
/* Auxiliary stuff */

void setBit(word x[], int p, bit v) {
/* Set the bit at position 'p' of little-endian word array 'x' to 'v'. */

if (v) {
x[p/32] |= ((word) 0x1 << p%32);
} else {
x[p/32] &= ~((word) 0x1 << p%32);
}
}

bit getBit(word x[], int p) {
/* Return the value of the bit at position 'p' in little-endian word
array 'x'. */

return (bit) ((x[p/32] & ((word) 0x1 << p%32)) >> p%32);
}

/* They should all be just getBit, but no overloading in C... */
bit getBitFromWord(word x, int p) {
return (bit) ((x & ((word) 0x1 << p)) >> p);
}
bit getBitFromNibble(nibble x, int p) {
return (bit) ((x & (0x1 << p)) >> p);
}

nibble getNibble(word x, int p) {
/* Return the nibble at position 'p' (in 0..7) in 'x'. */

return (nibble) (0xf & (x >> (p*4)));
}

nibble makeNibble(bit b0, bit b1, bit b2, bit b3) {
/* Return a nibble made of the given bits (b0 being the least significant). */

return (nibble) (b0 | (b1 << 1) | (b2 << 2) | (b3 << 3));
}

void xor128(word in1[4], word in2[4], word out[4]) {
/* Xor 'in1' and 'in2', yielding 'out'. */
int i;
for (i = 0; i < 4; i++) {
out[i] = in1[i] ^ in2[i];
}
}

void applyPermutation(permutationTable t, word input[4], word output[4]) {
/* Apply the permutation defined by 't' to 'input' and return the result
in 'output'. */

int p;
for (p=0; p<4; p++) {
output[p] = 0;
}
for (p=0; p<128; p++) {
setBit(output, p, getBit(input, t[p]));
}
}

void applyXorTable(xorTable t, word input[4], word output[4]) {
/* Apply the linear transformation defined by 't' to 'input', yielding
'output'. Each bit in 'output' is the xor of the bits from 'input'
given in the corresponding row of 't'. */

int i, j;
bit b;
for (i = 0; i < 128; i++) {
b = 0;
j = 0;
while (t[i][j] != MARKER) {
b ^= getBit(input, t[i][j]);
j++;
}
setBit(output, i, b);
}
}

nibble S(int box, nibble input) {
/* Apply S-box number 'box' (0..31) to 'input', returning its output. */

return SBox[box][input];
}

nibble SInverse(int box, nibble output) {
/* Apply S-box number 'box' (0..31) in reverse to 'output', returning its
input. */

return SBoxInverse[box][output];
}

word rotateLeft(word x, int p) {
/* Return word 'x' rotated left by 'p' places. The leftmost (i.e. most
significant) 'p' bits fall off the edge and come back in from the
other side. */
return ((x << p) | (x >> (32-p))) & 0xffffffff;
}


/* -------------------------------------------------- */
/* Functions used in the formal description of the cipher */

void IP(word input[4], word output[4]) {
/* Apply the Initial Permutation to 'input', yielding 'output'. */
applyPermutation(IPTable, input, output);
}

void FP(word input[4], word output[4]) {
/* Apply the Final Permutation to 'input', yielding 'output'. */
applyPermutation(FPTable, input, output);
}

void IPInverse(word output[4], word input[4]) {
/* Apply the Initial Permutation in reverse to 'output', yielding 'input'. */
applyPermutation(FPTable, output, input);
}

void FPInverse(word output[4], word input[4]) {
/* Apply the Final Permutation in reverse to 'output', yielding 'input'. */
applyPermutation(IPTable, output, input);
}

void SHat(int box, word input[4], word output[4]) {
/* Apply a parallel array of 32 copies of S-box number 'box' to 'input',
yielding 'output'. */
int iWord, iNibble;
for (iWord = 0; iWord < 4; iWord++) {
output[iWord] = 0;
for (iNibble = 0; iNibble < 8; iNibble++) {
output[iWord] |= ((word) S(box, getNibble(input[iWord], iNibble)))
<< (iNibble*4);
}
}
}

void SHatInverse(int box, word output[4], word input[4]) {
/* Apply, in reverse, a parallel array of 32 copies of S-box number 'box'
to 'output', yielding 'input'. */
int iWord, iNibble;
for (iWord = 0; iWord < 4; iWord++) {
input[iWord] = 0;
for (iNibble = 0; iNibble < 8; iNibble++) {
input[iWord] |= ((word) SInverse(box, getNibble(output[iWord], iNibble)))
<< (iNibble*4);
}
}
}

void LT(word input[4], word output[4]) {
/* Apply the table-based version of the linear transformation to 'input',
yielding 'output'. */

applyXorTable(LTTable, input, output);
}

void LTInverse(word output[4], word input[4]) {
/* Apply, in reverse, the table-based version of the linear
transformation to 'output', yielding 'input'. */

applyXorTable(LTTableInverse, output, input);
}

void R(int i, word BHati[4], word KHat[33][4], word BHatiPlus1[4]) {
/* Apply round 'i' to 'BHati', yielding 'BHatiPlus1'. Do this using the
appropriately numbered subkey(s) from 'KHat'. NB: it is allowed for
BHatiPlus1 to point to the same memory as BHati. */

word xored[4], SHati[4];

show128("BHati", BHati, i);
xor128(BHati, KHat[i], xored);
show128("xored", xored, i);
SHat(i, xored, SHati);
show128("SHati", SHati, i);
if ( (0 <= i) && (i <= r-2) ) {
LT(SHati, BHatiPlus1);
} else if (i == r-1) {
xor128(SHati, KHat[r], BHatiPlus1);
} else {
printf("ERROR: round %d is out of 0..%d range", i, r-1);
exit(1);
}
show128("BHatiPlus1", BHatiPlus1, i);
}

void RInverse(int i, word BHatiPlus1[4], word KHat[33][4], word BHati[4]) {
/* Apply round 'i' in reverse to 'BHatiPlus1', yielding 'BHati'. Do this
using the appropriately numbered subkey(s) from 'KHat'. NB: it is
allowed for BHati to point to the same memory as BHatiPlus1. */

word xored[4], SHati[4];

show128("BHatiPlus1", BHatiPlus1, i);
if ( (0 <= i) && (i <= r-2) ) {
LTInverse(BHatiPlus1, SHati);
} else if (i == r-1) {
xor128(BHatiPlus1, KHat[r], SHati);
} else {
printf("ERROR: round %d is out of 0..%d range", i, r-1);
exit(1);
}
show128("SHati", SHati, i);
SHatInverse(i, SHati, xored);
show128("xored", xored, i);
xor128(xored, KHat[i], BHati);
show128("BHati", BHati, i);
}



void makeSubkeysBitslice(word userKey[8], word K[33][4]) {
/* Given 'userKey' (shown as K in the paper, but we can't use that name
because of a collision with K[i] used later for something else),
produce the array 'K' of 33 128-bit subkeys. */

int i, j, l, whichS;
nibble input, output;
word k[132], raw_w[140];
/* The w array, in the notation of the paper, is supposed to span the
range -8..131. But we can't have negative array indices in C. NOTE
that this is a typical place where one can make trivial mistakes in
the implementation when setting j = i+8 and so on (I know -- I did
too). So what do I do here? My little hack (all for the sake of
readability) is to define a raw_w array in the range 0..139 and to
make a "proper" w alias on top of that by starting from the 8th
element, so that w[i] is redirected to raw_w[i+8], which works for i
in -8..131. */
word* w = &raw_w[8];

/* "We write the key as 8 32-bit words w-8 ... w-1" */
for (i = -8; i < 0; i++) {
w[i] = userKey[i+8];
show32("wi", w[i], i);
}

/* "We expand these to a prekey w0 ... w131 with the affine recurrence" */
for (i = 0; i < 132; i++) {
w[i] = rotateLeft(w[i-8] ^ w[i-5] ^ w[i-3] ^ w[i-1] ^ phi ^ i, 11);
show32("wi", w[i], i);
}

/* The round keys are now calculated from the prekeys using the S-boxes
in bitslice mode. */
for (i = 0; i < r+1; i++) {
whichS = (r + 3 - i) % r;
k[0+i] = k[33+i] = k[66+i] = k[99+i] = 0;
for (j = 0; j < 32; j++) {
input = makeNibble(getBitFromWord(w[0+i], j),
getBitFromWord(w[33+i], j),
getBitFromWord(w[66+i], j),
getBitFromWord(w[99+i], j));
output = S(whichS, input);
for (l = 0; l < 4; l++) {
k[33*l+i] |= ((word) getBitFromNibble(output, l)) << j;
}
}
}

/* We then renumber the 32 bit values k_j as 128 bit subkeys K_i. */
for (i = 0; i < 33; i++) {
for (j = 0; j < 4; j++) {
K[i][j] = k[4*i+j];
show32("ki", k[4*i+j], 4*i+j);
}
show128("Ki", K[i], i);
}
}


void makeSubkeys(word userKey[8], word KHat[33][4]) {
/* Given 'userKey' (shown as K in the paper, but we can't use that name
because of a collision with K[i] used later for something else),
produce the array 'KHat' of 33 128-bit subkeys. */

int i;
word K[33][4];
makeSubkeysBitslice(userKey, K);

/* We now apply IP to the round key in order to place the key bits in the
correct column. */
for (i = 0; i < 33; i++) {
IP(K[i], KHat[i]);
show128("KHati", KHat[i], i);
}
}


void encrypt(word plainText[4], word userKey[8], word cipherText[4]) {
/* Encrypt 'plainText' with 'userKey', using the normal (non-bitslice)
algorithm, yielding 'cipherText'. */

word KHat[33][4];
word BHat[4];
int i;

makeSubkeys(userKey, KHat);

IP(plainText, BHat);
for (i = 0; i < r; i++) {
R(i, BHat, KHat, BHat);
}
FP(BHat, cipherText);
}

void decrypt(word cipherText[4], word userKey[8], word plainText[4]) {
/* Decrypt 'cipherText' with 'userKey', using the normal (non-bitslice)
algorithm, yielding 'plainText'. */

word KHat[33][ 4];
word BHat[4];
int i;

makeSubkeys(userKey, KHat);

FPInverse(cipherText, BHat);
for (i = r-1; i >=0; i--) {
RInverse(i, BHat, KHat, BHat);
}
IPInverse(BHat, plainText);
}

/* -------------------------------------------------- */
/* WARNING: No clever crypto stuff below this line. Just boring command
line option parsing. It's a dirty job, but someone must do it if we want
a program YOU can use straight away, without having to edit main() to
poke in your own values. */

void help(void) {
printf(
"Serpent Reference Implementation\n"
"written by Frank Stajano http://www.cl.cam.ac.uk/~fms27/\n"
"Cambridge University Computer Laboratory\n"
"$Id: Serpref.c,v 1.15 1998/03/06 18:48:10 fms Exp $\n"
"Serpent cipher by Eli Biham, Ross Anderson, Lars Knudsen\n"
"\n"
"Encrypts or decrypts one block of data using the Serpent cipher.\n"
"\n"
"\n"
"SYNTAX: serpref mode [options]\n"
"\n"
"MODE is one of the following:\n"
"-e -> encrypt\n"
"-d -> decrypt\n"
"-h -> help (the text you're reading right now)\n"
"\n"
"OPTIONS are:\n"
"-p plainText -> The 128-bit value to be encrypted.\n"
" Required in mode -e. Ignored otherwise.\n"
"-c cipherText -> The 128-bit value to be decrypted.\n"
" Required in mode -d. Ignored otherwise.\n"
"-k key -> The 256-bit value of the key. Required in modes\n"
" -e and -d.\n"
"-t tagName -> Turn on the observer tag with that name. \n"
" This means that any observer messages associated\n"
" with this tag will now be displayed. This option\n"
" may be specified several times to add multiple\n"
" tags. The special tag ALL turns on all the\n"
" messages.\n"
"\n"
"I/O FORMAT:\n"
"The little-endian hex word sequence is adopted. Quantities are\n"
"split into 32-bit words and these words are listed one after\n"
"another in C's hex notation, starting with the least significant\n"
"one. The word in position 'i' (with position 0 being the leftmost)\n"
"has weight (2^32)^i. Note that, within the word, the C notation\n"
"dictates that the hex digits be represented in big-endian, i.e.\n"
"with the leftmost being the most significant one.\n"
"\n"
"As an example, the number ten extended to 64 bits is expressed\n"
"like this:\n"
" \"0x0000000a 0x00000000\"\n"
"and is equivalent to what you might write (in big-endian) as\n"
" \"0x000000000000000a\"\n"
"\n"
"NOTE: be sure to quote hex word sequences on the command line\n"
"(see examples below) so that serpref receives the entire value\n"
"as one argument.\n"
"\n"
"TAGS:\n"
"These are the tags of the quantities you can observe with\n"
"-t. Names are modelled on the paper's notation.\n"
"\n"
" BHati xored SHati BHatiPlus1 wi ki Ki KHati ALL\n"
"\n"
"USAGE EXAMPLES:\n"
"\n"
" serpref -e -k \"0x32158636 0x0da0aa51 0x97db1144 0x44cf2c28\n"
" 0x7c3fb76d 0x987257da 0xdafd0f29 0x7bf6334d\" -p \"0x650cba82\n"
" 0xffd10f30 0xf645ba29 0x6f195106\"\n"
"\n"
" (Imagine all of the above on a single line.)\n"
" Encrypt the specified 128 bit plaintext under the specified\n"
" 256 bit key.\n"
"\n"
" serpref -e -p 0x00000003 -k \"0xf 0x1\" -t wi -t BHati\n"
"\n"
" A typical test run during debugging. Encrypt the plaintext\n"
" \"3\" (which serpref will extend to 128 bits) under the key\n"
" \"15 + 2^32\" (which will be extended to 256 bits) and show\n"
" me the intermediate results of all the wi (from -8 to 131)\n"
" and all the BHati (from 0 to 31).\n"
);
}

void exitMentioningHelp(void) {
printf("Try 'serpref -h | more' for help.\n");
exit(1);
}


void assignStringToUniqueOption(char** p, char* target, char* key) {
/* The idea is to make a string variable (say, plainTextString) point to
a value inside argv[]. 'p' points to that string variable; 'target'
points to the relevant argv entry; 'key' (say, -p) is the name of the
option whose value is held in 'target'.

If 'target' is null, complain and exit (it should never be, because
the 'key' option is supposed to have a value). If the char* pointed by
'p' is null, make 's' point to 'target'; otherwise, complain that the
option 'key' has already been seen, and exit. */
if (!target) {
printf("Option without value: %s\n", key);
exitMentioningHelp();
}
if (*p) {
printf("Multiple occurrences of %s\n", key);
exitMentioningHelp();
} else {
*p = target;
}
}


int checkHexWordSequence(char* s) {
/* Check if 's' contains a valid hex word sequence (defined below) and,
if so, return the number of words it contains. Otherwise print out an
error and exit. A hex word is "0x" followed by up to 8 lowercase hex
digits. Hex words in the sequence are separated by spaces
and there are no leading or trailing spaces. */

int words = 0, digits = 0, i = 0;
char* error = 0;

while (s[i]) {
/* skip leading blanks if any */
while (isspace((int) s[i])) {
i++;
}

if (!s[i]) {
/* legitimate end of string */
break;
}

if (s[i++] != '0') {
error = "Missing 0: hex word does not start with 0x\n";
break;
}
if (!s[i]) {
error = "Premature end of string (got 0, expecting 0x...)\n";
break;
}
if (s[i++] != 'x') {
error = "Missing x: hex word does not start with 0x\n";
break;
}
if (!s[i]) {
error = "Premature end of string (got 0x, expecting hex digit)\n";
break;
}

digits = 0;
while (isxdigit((int) s[i])) {
digits++;
i++;
}
if (s[i] && !isspace((int) s[i])) {
error = "Hex word not terminated by a space or end of string\n";
break;
}
if (digits > 8) {
error = "Hex word contains more than 8 digits\n";
break;
}

words++;
}
if (!error && words == 0) {
error = "No hex words found\n";
}

if (error) {
printf("Error while parsing argument '%s':\n", s);
printf(error);
exitMentioningHelp();
}
return words;
}

void stringToWords(char* s, word w[], int words) {
/* Convert the hex word sequence contained in 's' (error if there isn't a
well-formed one) into numeric format and put it into 'w'. Take 'w' to
be 'words' words long and zero-fill it where appropriate if 's'
contains fewer words than that. */

int n, i, offset=0;

n = checkHexWordSequence(s);

if (n > words) {
printf("Hex word sequence '%s' contains %d words, but max is %d.\n",
s, n, words);
exitMentioningHelp();
}

for (i = 0; i < n; i++) {
sscanf(&s[offset++], "%lx", &w[i]);
while (!isspace((int) s[offset])) {
offset++;
}
}

/* If the sequence contains fewer words than 'w', zero-fill the most
significant remaining ones. */
for (i = n; i < words; i++) {
w[i] = 0;
}
}


void render(char* label, word x[], int size) {
/* Print 'x', which is made of 'size' words, on stdout, prefixing it with
'label'. */
int i;
printf("%s =", label);
for (i = 0; i < size; i++) {
printf(" 0x%08lx", x[i]);
}
printf("\n");
}


int main(int argc, char* argv[]) {
/* Process the command line options, point out the errors if they're
badly formed and obey them if they're ok. WARNING: this accesses, and
even writes to, the global variables 'tag*'. */

int i;
char* userKeyString = 0;
char* plainTextString = 0;
char* cipherTextString = 0;
char* formatString = 0;
char* mode = 0;

word plainText[4], cipherText[4], userKey[8];

int tagc = 0;
tagv = (char**) malloc((argc+1)*sizeof(char*));
/* This will surely be enough: there definitely can't be more requested
tags than there are command line arguments, because every tag must
come from a command line argument (and in fact it will consume
two). */
tagv[tagc] = 0;


if (sizeof(word) < 4) {
printf("ERROR: on this architecture 'word' is %d bits (need at least 32)\n",
(int) (sizeof(word)*8));
exit(1);
}

i = 1;
while (argv[i]) {
if (strcmp(argv[i], "-k") == 0) {
assignStringToUniqueOption(&userKeyString, argv[++i], "-k");
} else if (strcmp(argv[i], "-p") == 0) {
assignStringToUniqueOption(&plainTextString, argv[++i], "-p");
} else if (strcmp(argv[i], "-c") == 0) {
assignStringToUniqueOption(&cipherTextString, argv[++i], "-c");
} else if (strcmp(argv[i], "-f") == 0) {
assignStringToUniqueOption(&formatString, argv[++i], "-f");
} else if (strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "-d") == 0
|| strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "-h") == 0) {
if (mode) {
printf("You can only specify one mode\n");
exitMentioningHelp();
} else {
mode = argv[i];
}
} else if (strcmp(argv[i], "-t") == 0) {
if (!argv[++i]) {
printf("Option without value\n");
exitMentioningHelp();
}
tagv[tagc++] = argv[i];
tagv[tagc] = 0;
if (strcmp((argv[i]), "ALL") == 0) {
tagAll = 1;
}
} else {
printf("Unrecognised option: '%s'\n", argv[i]);
exitMentioningHelp();
}

i++;
}

if (!mode) {
printf("Mode required.\n");
exitMentioningHelp();
}

if (strcmp(mode, "-h") == 0) {
help();
exit(0);
}
if ((strcmp(mode, "-e") == 0) || (strcmp(mode, "-d") == 0)) {
if (userKeyString) {
stringToWords(userKeyString, userKey, 8);
} else {
printf("-k (key) required when doing -e (encrypt) or -d (decrypt)\n");
exitMentioningHelp();
}
}
if (strcmp(mode, "-e") == 0) {
if (plainTextString) {
stringToWords(plainTextString, plainText, 4);
} else {
printf("-p (plaintext) required when doing -e (encrypt)\n");
exitMentioningHelp();
}
}
if (strcmp(mode, "-d") == 0) {
if (cipherTextString) {
stringToWords(cipherTextString, cipherText, 4);
} else {
printf("-c (ciphertext) required when doing -d (decrypt)\n");
exitMentioningHelp();
}
}


/* At last we're ready to DO the thing! */

fprintf(stderr,
"REMINDER: All I/O is done using little-endian hex word sequences.\n"
"Example: decimal 10 in 64 bits is 0x0000000a 0x00000000.\n"
"See 'serpref -h' for more details.\n\n");
/* I want interactive users not to miss this reminder, but I don't want
it to appear in batch test runs. So I send it to stderr instead of
stdout, to ensure that it can be redirected away. */

if (strcmp(mode, "-e") == 0) {
render("plainText", plainText, 4);
render("userKey", userKey, 8);
encrypt(plainText, userKey, cipherText);
render("cipherText", cipherText, 4);
} else if (strcmp(mode, "-d") == 0) {
render("cipherText", cipherText, 4);
render("userKey", userKey, 8);
decrypt(cipherText, userKey, plainText);
render("plainText", plainText, 4);
}
return 0;
}
Login or Register to add favorites

File Archive:

March 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Mar 1st
    16 Files
  • 2
    Mar 2nd
    0 Files
  • 3
    Mar 3rd
    0 Files
  • 4
    Mar 4th
    32 Files
  • 5
    Mar 5th
    28 Files
  • 6
    Mar 6th
    42 Files
  • 7
    Mar 7th
    17 Files
  • 8
    Mar 8th
    13 Files
  • 9
    Mar 9th
    0 Files
  • 10
    Mar 10th
    0 Files
  • 11
    Mar 11th
    15 Files
  • 12
    Mar 12th
    19 Files
  • 13
    Mar 13th
    21 Files
  • 14
    Mar 14th
    38 Files
  • 15
    Mar 15th
    15 Files
  • 16
    Mar 16th
    0 Files
  • 17
    Mar 17th
    0 Files
  • 18
    Mar 18th
    10 Files
  • 19
    Mar 19th
    32 Files
  • 20
    Mar 20th
    46 Files
  • 21
    Mar 21st
    16 Files
  • 22
    Mar 22nd
    13 Files
  • 23
    Mar 23rd
    0 Files
  • 24
    Mar 24th
    0 Files
  • 25
    Mar 25th
    12 Files
  • 26
    Mar 26th
    31 Files
  • 27
    Mar 27th
    19 Files
  • 28
    Mar 28th
    42 Files
  • 29
    Mar 29th
    0 Files
  • 30
    Mar 30th
    0 Files
  • 31
    Mar 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close