Добавил:
Studfiles2
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Лабораторная работа №21 / serpent.tar / serpent-as-submitted / floppy1 / serpent-reference
.c/*
$Id: serpent-reference.c,v 1.42 1998/06/10 13:50:31 fms Exp $
This is a reference implementation of the Serpent cipher invented by Ross
Anderson, Eli Biham, 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.")
# This file is part of the C reference implementation of Serpent.
#
# Written by Frank Stajano,
# Olivetti Oracle Research Laboratory <http://www.orl.co.uk/~fms/> and
# Cambridge University Computer Laboratory <http://www.cl.cam.ac.uk/~fms27/>.
#
# (c) 1998 Olivetti Oracle Research Laboratory (ORL)
#
# Original (Python) Serpent reference development started on 1998 02 12.
# C implementation development started on 1998 03 04.
#
# Serpent cipher invented by Ross Anderson, Eli Biham, Lars Knudsen.
# Serpent is a candidate for the Advanced Encryption Standard.
*/
/* -------------------------------------------------- */
#include "serpent-api.h"
#include "serpent-tables.h"
#include "serpent-reference.h"
#include "serpent-aux.h"
/* -------------------------------------------------- */
EMBED_RCS(serpent_reference_c,
"$Id: serpent-reference.c,v 1.42 1998/06/10 13:50:31 fms Exp $")
/* NIST API functions */
int makeKey(keyInstance *key, BYTE direction, int keyLen,
char *keyMaterial) {
/*
Initializes a keyInstance with the following information. The
fields followed by (*) get their value copied verbatim from the input
parameters to this function. The others are calculated from them.
direction (*): DIR_ENCRYPT or DIR_DECRYPT
keyLen (*): The key length (in bits) of the key
keyMaterial (*): a string with the raw key information
(BITS_PER_BLOCK/4 ASCII characters representing the hex values for
the key).
userKey: the long (256 bit) form of the key in little-endian binary format.
KHat: a series of subkeys generated from the user key.
Parameters:
key: a structure that holds the keyInstance information
direction: the key is being setup for encryption or decryption
keyLen: an integer value that indicates the length of the key in bits.
keyMaterial: the raw key information (keyLen/4 ASCII characters
representing the hex values for the key). For example,
"0123456789abcdef0123456789abcdef" is the string for a key with the
binary value:
0000000100100011010001010110011110001001101010111100...
Returns:
TRUE - on success
BAD_KEY_DIR - direction is invalid (e.g., unknown value)
BAD_KEY_MAT - keyMaterial is invalid (e.g., wrong length)
*/
int result;
if ((keyLen%BITS_PER_WORD)
|| (keyLen > BITS_PER_KEY)
|| (keyLen < BITS_PER_SHORTEST_KEY)) {
return BAD_KEY_MAT;
}
key->direction = direction;
key->keyLen = keyLen;
if (keyMaterial) {
strncpy(key->keyMaterial, keyMaterial, HEX_DIGITS_PER_KEY + 1);
}
result = stringToWords(key->keyMaterial, key->userKey, WORDS_PER_KEY);
if (result != TRUE) {
return BAD_KEY_MAT;
}
if (keyLen < BITS_PER_KEY) {
shortToLongKey(key->userKey, keyLen);
}
makeSubkeys(key->userKey, key->KHat);
return TRUE;
}
int cipherInit(cipherInstance* cipher, BYTE mode, char* IV) {
/*
Initializes the cipher with the mode and, if present, sets the
Initialization Vector. If any algorithm specific setup is necessary,
cipherInit() must take care of that as well. The IV parameter passed to
cipherInit() is an ASCII hex string representation of the IV, i.e. the
IV passed as a parameter will typically be 32 bytes long. The IV field
of the cipherInstance structure is the binary value of the IV, i.e. it
will typically be 16 bytes long. Algorithm specific parameters must be
loaded into the cipherInstance structure before calling
cipherInit(). For example, if the algorithm can use other block sizes
than 128-bits, a field should be added to the cipherInstance structure
and the value being used should be loaded into the cipher parameter
before calling cipherInit().
Parameters:
cipher - the cipherInstance being loaded
mode - the operation mode of this cipher (this is one of
MODE_ECB, MODE_CBC, or MODE_CFB1)
IV - the cipher initialization vector, necessary for some modes
Returns:
TRUE - on success
BAD_CIPHER_MODE - the mode passed is unknown.
*/
int result;
cipher->mode = mode;
switch (mode) {
case MODE_ECB:
return TRUE;
case MODE_CFB1:
case MODE_CBC:
/* Convert the initialisation vector from ascii to bin and store it
in cipher. */
result = stringToWords(IV, (WORD*) cipher->IV, WORDS_PER_IV);
if (result != TRUE) {
return BAD_IV;
}
return TRUE;
default:
return BAD_CIPHER_MODE;
}
}
int blockEncrypt(cipherInstance* cipher, keyInstance* key, BYTE* input, int
inputLen, BYTE* outBuffer) {
/* Uses the cipherInstance object and the keyInstance object to encrypt
one block of data in the input buffer. The output (the encrypted data)
is returned in outBuffer, which is the same size as inputLen. The
routine returns the number of bits enciphered. inputLen will typically
be 128 bits, but some algorithms may handle additional block
sizes. Additionally, it is acceptable to use this routine to encrypt
multiple "blocks" of data with one call. For example, if your algorithm
has a block size of 128 bits, it is acceptable to pass n*128 bits to
blockEncrypt().
Parameters:
cipher - the cipherInstance to be used
key - the ciphering key
input - the input buffer
inputLen - the input length, in bits
outBuffer - contains the encrypted data
Returns:
The number of bits ciphered, or
BAD_CIPHER_STATE - cipher in bad state (e.g., not initialized)
BAD_KEY_MAT - direction not set for DIR_ENCRYPT
*/
/* Why does NIST insist on having both a key->direction indicator and
separate encrypt and decrypt calls? This redundancy just opens the
door to inconsistency and confusion, which would be avoided if the
caller only had one way to specify the desired direction.
Note also that, in case of inconsistency, we return BAD_KEY_MAT as
requested, though it would make more sense to return BAD_KEY_DIR.
*/
if (key->direction != DIR_ENCRYPT) {
return BAD_KEY_MAT;
}
return blockEncryptOrDecrypt(cipher, key, input, inputLen, outBuffer);
}
int blockDecrypt(cipherInstance* cipher, keyInstance* key, BYTE* input, int
inputLen, BYTE* outBuffer) {
/* Uses the cipherInstance object and the keyInstance object to decrypt
one block of data in the input buffer. The output (the decrypted data)
is returned in outBuffer, which is the same size as inputLen. The
routine returns the number of bits deciphered. inputLen will typically
be 128 bits, but some algorithms may handle additional block
sizes. Additionally, it is acceptable to use this routine to decrypt
multiple "blocks" of data with one call. For example, if your
algorithm has a block size of 128 bits, it is acceptable to pass n*128
bits to blockDecrypt().
Parameters:
cipher - the cipherInstance to be used
key - the ciphering key
input - the input buffer
inputLen - the input length, in bits
outBuffer - contains the decrypted data
Returns:
The number of bits deciphered, or
BAD_CIPHER_STATE - cipher in bad state (e.g., not initialized)
BAD_KEY_MAT - direction not set for DIR_DECRYPT
*/
if (key->direction != DIR_DECRYPT) {
return BAD_KEY_MAT; /* see comments in blockEncrypt */
}
return blockEncryptOrDecrypt(cipher, key, input, inputLen, outBuffer);
}
/* -------------------------------------------------- */
/* Stuff called by the NIST API */
int blockEncryptOrDecrypt(cipherInstance* cipher, keyInstance* key, BYTE*
input, int inputLen, BYTE* outBuffer) {
int i, numBlocks, bytesLeftOver, result;
numBlocks = inputLen / BITS_PER_BLOCK;
bytesLeftOver = inputLen % BITS_PER_BLOCK;
/* I'd like to return an error if this is != 0, but it's not clear to me
from the NIST spec whether I'm allowed to or not. So I'll settle for
just not processing the leftover bits (and the caller will have to
check for himself whether the nmber of bytes processed is or isn't the
same as inputLen). */
for (i=0; i<numBlocks; i++) {
result = doOneBlock((WORD*)(input + i*WORDS_PER_BLOCK),
(WORD*)(outBuffer + i*WORDS_PER_BLOCK), cipher, key);
if (result != TRUE) {
return BAD_CIPHER_STATE;
}
}
return numBlocks*BITS_PER_BLOCK;
}
int doOneBlock(BLOCK input, BLOCK output,
cipherInstance* cipher, keyInstance* key) {
/* Encrypt or decrypt one block, given by 'input', and put the result in
'output'. 'cipher' points to the cipher instance to be used
(containing among other things the initialisation vector for CBC) and
'key' points to the key instance to be used. Return TRUE if all goes
well, BAD_CIPHER_MODE if the required encryption or decryption mode is
not supported, */
int i;
BIT plainTextBit, cipherTextBit;
BLOCK temp;
switch (key->direction) {
case DIR_ENCRYPT:
switch (cipher->mode) {
case MODE_ECB:
encryptGivenKHat(input, key->KHat, output);
break;
case MODE_CBC:
for (i=0; i < WORDS_PER_BLOCK; i++) {
temp[i] = input[i] ^ ((WORD*) cipher->IV)[i];
}
encryptGivenKHat(temp, key->KHat, output);
for (i=0; i < WORDS_PER_BLOCK; i++) {
((WORD*) (cipher->IV))[i] = output[i];
}
break;
case MODE_CFB1:
/* We use cipher->IV as the shift register. New data comes in at
the LSB end and old data is dropped out of the MSB end. This
is what is traditionally called a "left shift", though in our
case we are actually shifting towards the right (MSB end)
since we store multiword quantities in little-endian
format.
The first bit of the plaintext to be encrypted is bit 0
(LSB). This is stored in bit 0 of the output ciphertext
block. Similarly, every bit of the plaintext is stored, after
encryption, in the corresponding bit of the output block.
Note that, due to the way it's called, this routine will
always encrypt an entire block, though in theory MODE_CFB1
could also encrypt a non-round number of bits. */
for (i=0; i<BITS_PER_BLOCK; i++) {
encryptGivenKHat((WORD*)(cipher->IV), key->KHat, temp);
plainTextBit = getBit(input, i);
cipherTextBit = getBit(temp, BITS_PER_BLOCK-1) ^ plainTextBit;
setBit(output, i, cipherTextBit);
shiftBlockLeft((WORD*)(cipher->IV), cipherTextBit);
}
break;
default:
return BAD_CIPHER_MODE;
}
break;
case DIR_DECRYPT:
switch (cipher->mode) {
case MODE_ECB:
decryptGivenKHat(input, key->KHat, output);
break;
case MODE_CBC:
decryptGivenKHat(input, key->KHat, temp);
for (i=0; i < WORDS_PER_BLOCK; i++) {
output[i] = temp[i] ^ ((WORD*) cipher->IV)[i];
}
for (i=0; i < WORDS_PER_BLOCK; i++) {
((WORD*) cipher->IV)[i] = input[i];
}
break;
case MODE_CFB1:
/* The comments on the encryption side apply. See above. */
for (i=0; i<BITS_PER_BLOCK; i++) {
encryptGivenKHat((WORD*)(cipher->IV), key->KHat, temp);
/* NB: yes, in CFB the cipher is used in encryption mode even
when decrypting. */
cipherTextBit = getBit(input, i);
plainTextBit = getBit(temp, BITS_PER_BLOCK-1) ^ cipherTextBit;
setBit(output, i, plainTextBit);
shiftBlockLeft((WORD*)(cipher->IV), cipherTextBit);
}
break;
default:
return BAD_CIPHER_MODE;
}
break;
default:
return BAD_KEY_DIR;
}
return TRUE;
}
/* -------------------------------------------------- */
/* Auxiliary bit-twiddling 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/BITS_PER_WORD] |= ((WORD) 0x1 << p%BITS_PER_WORD);
} else {
x[p/BITS_PER_WORD] &= ~((WORD) 0x1 << p%BITS_PER_WORD);
}
}
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/BITS_PER_WORD]
& ((WORD) 0x1 << p%BITS_PER_WORD)) >> p%BITS_PER_WORD);
}
/* 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*BITS_PER_NIBBLE)));
}
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 xorBlock(BLOCK in1, BLOCK in2, BLOCK out) {
/* Xor 'in1' and 'in2', yielding 'out'. */
int i;
for (i = 0; i < WORDS_PER_BLOCK; i++) {
out[i] = in1[i] ^ in2[i];
}
}
void applyPermutation(permutationTable t, BLOCK input, BLOCK output) {
/* Apply the permutation defined by 't' to 'input' and return the result
in 'output'. */
int p;
for (p=0; p<WORDS_PER_BLOCK; p++) {
output[p] = 0;
}
for (p=0; p<BITS_PER_BLOCK; p++) {
setBit(output, p, getBit(input, t[p]));
}
}
void applyXorTable(xorTable t, BLOCK input, BLOCK output) {
/* 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 < BITS_PER_BLOCK; 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 >> (BITS_PER_WORD-p))) & 0xffffffff;
}
void shiftBlockLeft(BLOCK b, BIT in) {
/* Return block 'b' shifted left by one place. The leftmost (i.e. most
significant) bit falls off the edge and is lost, while bit 'in' is
inserted at the rightmost (least significant) position to make up for
it. */
int i;
for (i=WORDS_PER_BLOCK-1; i>0; i--) {
b[i] <<= 1;
setBit(&b[i], 0, getBit(&b[i-1], BITS_PER_WORD-1));
}
b[0] <<= 1;
setBit(&b[0], 0, in);
}
/* -------------------------------------------------- */
/* Short key support */
void shortToLongKey(KEY key, int bitsInShortKey) {
/* Take a short key (stored in key) and transform it (in place) into its
long form (and write it to longKey). The number of significant bits in
the supplied short key is given by bitsInShortKey. The caller is
responsible for ensuring that all the remaining (most significant)
bits in key from position bitsInShortKey upwards are 0 (as they should
be anyway since key is declared to be WORDS_PER_KEY words long). */
key[bitsInShortKey/BITS_PER_WORD] |=
((WORD) 1) << (bitsInShortKey%BITS_PER_WORD);
}
/* -------------------------------------------------- */
/* Functions used in the formal description of the cipher */
void IP(BLOCK input, BLOCK output) {
/* Apply the Initial Permutation to 'input', yielding 'output'. */
applyPermutation(IPTable, input, output);
}
void FP(BLOCK input, BLOCK output) {
/* Apply the Final Permutation to 'input', yielding 'output'. */
applyPermutation(FPTable, input, output);
}
void IPInverse(BLOCK output, BLOCK input) {
/* Apply the Initial Permutation in reverse to 'output', yielding 'input'. */
applyPermutation(FPTable, output, input);
}
void FPInverse(BLOCK output, BLOCK input) {
/* Apply the Final Permutation in reverse to 'output', yielding 'input'. */
applyPermutation(IPTable, output, input);
}
void SHat(int box, BLOCK input, BLOCK output) {
/* Apply a parallel array of 32 copies of S-box number 'box' to 'input',
yielding 'output'. */
int iWord, iNibble;
for (iWord = 0; iWord < WORDS_PER_BLOCK; iWord++) {
output[iWord] = 0;
for (iNibble = 0; iNibble < NIBBLES_PER_WORD; iNibble++) {
output[iWord] |= ((WORD) S(box, getNibble(input[iWord], iNibble)))
<< (iNibble*BITS_PER_NIBBLE);
}
}
}
void SHatInverse(int box, BLOCK output, BLOCK input) {
/* 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 < WORDS_PER_BLOCK; iWord++) {
input[iWord] = 0;
for (iNibble = 0; iNibble < NIBBLES_PER_WORD; iNibble++) {
input[iWord] |= ((WORD) SInverse(box, getNibble(output[iWord], iNibble)))
<< (iNibble*BITS_PER_NIBBLE);
}
}
}
void LT(BLOCK input, BLOCK output) {
/* Apply the table-based version of the linear transformation to 'input',
yielding 'output'. */
applyXorTable(LTTable, input, output);
}
void LTInverse(BLOCK output, BLOCK input) {
/* Apply, in reverse, the table-based version of the linear
transformation to 'output', yielding 'input'. */
applyXorTable(LTTableInverse, output, input);
}
void R(int i, BLOCK BHati, keySchedule KHat, BLOCK BHatiPlus1) {
/* 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. */
BLOCK xored, SHati;
xorBlock(BHati, KHat[i], xored);
SHat(i, xored, SHati);
if ( (0 <= i) && (i <= r-2) ) {
LT(SHati, BHatiPlus1);
} else if (i == r-1) {
xorBlock(SHati, KHat[r], BHatiPlus1);
} else {
printf("ERROR: round %d is out of 0..%d range", i, r-1);
exit(1);
/* Printf and exit is disgusting--if we were programming in a sensible
language, we'd have exceptions. Shall I make the code less readable
with ugly return codes that no caller ever checks anyway?
Naaah... */
}
#ifdef SHOW_INTERNALS
printf("R[%d]", i);
render("=", BHatiPlus1, WORDS_PER_BLOCK);
#endif
}
void RInverse(int i, BLOCK BHatiPlus1, keySchedule KHat, BLOCK BHati) {
/* 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. */
BLOCK xored, SHati;
if ( (0 <= i) && (i <= r-2) ) {
LTInverse(BHatiPlus1, SHati);
} else if (i == r-1) {
xorBlock(BHatiPlus1, KHat[r], SHati);
} else {
printf("ERROR: round %d is out of 0..%d range", i, r-1);
exit(1);
}
SHatInverse(i, SHati, xored);
xorBlock(xored, KHat[i], BHati);
#ifdef SHOW_INTERNALS
printf("Rinv[%d]", i);
render("=", BHati, WORDS_PER_BLOCK);
#endif
}
void makeSubkeysBitslice(KEY userKey, keySchedule K) {
/* 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];
}
/* "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);
}
/* 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+4*i] = k[1+4*i] = k[2+4*i] = k[3+4*i] = 0;
for (j = 0; j < 32; j++) {
input = makeNibble(getBitFromWord(w[0+4*i], j),
getBitFromWord(w[1+4*i], j),
getBitFromWord(w[2+4*i], j),
getBitFromWord(w[3+4*i], j));
output = S(whichS, input);
for (l = 0; l < 4; l++) {
k[l+4*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];
}
#ifdef SHOW_INTERNALS
printf("SK[%d]", i);
render("=", K[i], WORDS_PER_BLOCK);
#endif
}
}
void makeSubkeys(KEY userKey, keySchedule KHat) {
/* 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;
keySchedule K;
#ifdef SHOW_INTERNALS
render("LONG_KEY=", userKey, WORDS_PER_KEY);
#endif
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]);
#ifdef SHOW_INTERNALS
printf("SK^[%d]", i);
render("=", KHat[i], WORDS_PER_BLOCK);
#endif
}
}
void encryptGivenKHat(BLOCK plainText, keySchedule KHat, BLOCK cipherText) {
/* Encrypt 'plainText' with 'KHat', using the normal (non-bitslice)
algorithm, yielding 'cipherText'. */
BLOCK BHat;
int i;
IP(plainText, BHat);
for (i = 0; i < r; i++) {
R(i, BHat, KHat, BHat);
}
FP(BHat, cipherText);
}
void decryptGivenKHat(BLOCK cipherText, keySchedule KHat, BLOCK plainText) {
/* Decrypt 'cipherText' with 'KHat', using the normal (non-bitslice)
algorithm, yielding 'plainText'. */
BLOCK BHat;
int i;
FPInverse(cipherText, BHat);
for (i = r-1; i >=0; i--) {
RInverse(i, BHat, KHat, BHat);
}
IPInverse(BHat, plainText);
}
Соседние файлы в папке floppy1