Re: /dev/random blocks forever ...

From: Sandy Harris (sandy@sandy.storm.ca)
Date: Tue Aug 15 2000 - 00:30:14 EST


Ted T'so wrote:
 
| My recommendation has always been that applications use /dev/random
| for long-term public key generation, and to seed a pseudo-RNG for
| session keys. ... it's better to periodically get randomness from
| /dev/random, and then use that as seeds for a cryptographically
| secure, pseudo-random number generator.

I'm inclined to think the pseudo-random generator should be in
the kernel, driving /dev/urandom to prevent heavy use of that
device from draining the pool and causing /dev/random to block.

However, I've written one as a user-space library, using
Rijndael as the block cipher, based on Brian Gladman's code.
It is below. Comment solicited.

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2c).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 2000-08-15 01:05 EDT by <sandy@sandy>.
# Source directory was `/home/sandy'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 206 -rw-r--r-- rrandom/Makefile
# 23278 -rw-r--r-- rrandom/rrandom.c
# 658 -rw-r--r-- rrandom/rrandom.h
# 13868 -rw-r--r-- rrandom/rijndael.c
# 3111 -rw-r--r-- rrandom/aes_defs.h
# 644 -rw-r--r-- rrandom/rantest.c
# 1025 -rw-r--r-- rrandom/rijndael.h
# 688 -rw-r--r-- rrandom/README
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    set `$dir/gettext --version 2>&1`
    if test "$3" = GNU
    then
      gettext_dir=$dir
    fi
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
    shar_n= shar_c='
'
  else
    shar_n=-n shar_c=
  fi
else
  shar_n= shar_c='\c'
fi
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo
  $echo 'WARNING: not restoring timestamps. Consider getting and'
  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 1231235999 $$.touch
#
$echo $shar_n 'x -' 'lock directory' "\`_sh02109': "$shar_c
if mkdir _sh02109; then
  $echo 'created'
else
  $echo 'failed to create'
  exit 1
fi
# ============= rrandom/Makefile ==============
if test ! -d 'rrandom'; then
  $echo $echo_n 'x -' 'rrandom: '$echo_c
  if mkdir 'rrandom'; then $echo 'created'; else $echo 'failed to create'; fi
fi
if test -f 'rrandom/Makefile' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'rrandom/Makefile' '(file already exists)'
else
  $echo 'x -' extracting 'rrandom/Makefile' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'rrandom/Makefile' &&
CFLAGS=-Wall -O2
X
OB=rrandom.o rantest.o
X
test: rantest
X rantest
X
rantest: $(OB)
X $(CC) -o rantest $(OB)
X
$(OB): rrandom.h
X
rijndael.o: rijndael.c rijndael.h aes_defs.h
X
clean:
X rm rantest $(OB) rijndael.o
SHAR_EOF
  $shar_touch -am 08150100100 'rrandom/Makefile' &&
  chmod 0644 'rrandom/Makefile' ||
  $echo 'restore of' 'rrandom/Makefile' 'failed'
  if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'rrandom/Makefile:' 'MD5 check failed'
577eb669b4551aa21be75bc605e1ae49 rrandom/Makefile
SHAR_EOF
  else
    shar_count="`LC_ALL=C wc -c < 'rrandom/Makefile'`"
    test 206 -eq "$shar_count" ||
    $echo 'rrandom/Makefile:' 'original size' '206,' 'current size' "$shar_count!"
  fi
fi
# ============= rrandom/rrandom.c ==============
if test -f 'rrandom/rrandom.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'rrandom/rrandom.c' '(file already exists)'
else
  $echo 'x -' extracting 'rrandom/rrandom.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'rrandom/rrandom.c' &&
/* Code to generate random numbers using Rijndael
X * by Sandy Harris, <sandy@storm.ca>
X *
X * Calls a modified version of Brian Gladman's
X * Rijndael code, included at end of file. His
X * copyright notice is also included there.
X *
X * Bug reports or other comments to sandy@storm.ca.
X * Neither the designers of the Rijndael cipher
X * http://www.esat.kuleuven.ac.be/~rijmen/rijndael/index.html
X * nor Brian Gladman, whose code I use below,
X * http://www.btinternet.com/~brian.gladman
X * are to blame for any problems here.
X *
X * This is new code, neither heavily tested nor well
X * analyzed. Use with caution.
X */
X
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
X
/*
X * rrandom.h declares the public interface, everything
X * that should be visible to our caller.
X */
#include "rrandom.h"
X
/*
X * Various things from two of Gladman's files, aes_def.h
X * and rijndael.h, are included here because in this
X * application they need not be public.
X */
X
/*
X * Gladman used a different syntax for these,
X * had more functions, and had a flag argument
X * on the set_key function for encrypt/decrypt
X */
void rr_set_key(const u1byte key[], const u4byte key_len);
void rr_encrypt_buffer(u4byte in_blk[], u4byte out_blk[]);
X
// Circular rotate of 32 bit values
X
#define rotr(x,n) (((x) >> ((int)((n) & 0x1f))) | ((x) << ((int)((32 - ((n) & 0x1f))))))
#define rotl(x,n) (((x) << ((int)((n) & 0x1f))) | ((x) >> ((int)((32 - ((n) & 0x1f))))))
X
/*
X * My static functions are also declared here
X */
static int getrandom( FILE *, char *, unsigned) ;
static void increment() ;
/*
X * these call the lower level
X * rr_set_key() annd rr_encrypt_buffer()
X */
static void rr_keysched() ;
static int rr_encrypt() ;
X
/*
X * We use the block cipher in counter mode to generate output
X * along lines suggested in the Yarrow papers:
X *
X * http://www.counterpane.com/yarrow.html
X *
X * Yarrow is a two-stage generator. Linux and *BSD /dev/random
X * are somewhat akin to its first stage.
X *
X * This code is a second stage for /dev/random, intended to reduce
X * the load on /dev/random without reducing security. Without the
X * underlying /dev/random, this code would make no sense.
X *
X * The /dev/random code presents two interfaces, both character
X * devices:
X * /dev/random high-quality, blocks when there is not
X * enough entropy available
X * /dev/urandom never blocks, may be lower quality
X *
X * The problem I am trying to solve is that both devices use the
X * same entropy pool so heavy use of /dev/urandom may cause
X * /dev/random to block.
X *
X * I think this is a bug in the driver. This code is intended
X * to eventually be a second stage that drives urandom without
X * causing random to block.
X *
X * If I understand correctly, Ted Ts'o (driver author/maintainer)
X * does not think this needs to be fixed in kernel space. All we
X * need is a user-level library for use in processes that need
X * lots of random numbers.
X *
X * This is my attempt at writing that library. I think it
X * should become part of the driver, but we can argue that
X * out later.
X *
X * A design criterion was never losing state. When this code
X * re-keys, it does not overwrite existing round keys. Instead
X * it calculates a new set, then mixes them into the old set.
X * Thus if either the current round key state or the key used
X * to create the new set is unknown to an enemy, he is blocked.
X *
X * Nor does it zero the counter when it re-keys. Instead it
X * encrypts the old counter with old key and uses the result
X * to re-initialize the counter. An enemy who does not know
X * the old state then does not know the new counter.
X */
X
#ifdef DEBUG /* use cheaper source for testing */
#define RANDOM "/dev/urandom"
#else
#define RANDOM "/dev/random"
#endif
X
/*
X * A large block size makes this code considerably more efficient,
X * e.g. 14 rounds for 256-bit blocks vs 10 for 128-bit.
X * Analysis of Rijndael has focused on the 128-bit block size used
X * in AES, so that would arguably be the safest choice.
X *
X * Keysize is a more arbitrary choice. 128 is convenient, seems enough.
X */
X
#define KEYSIZE 128
#define BLOCKSIZE 256
X
#define KEYBYTES (KEYSIZE/8)
#define KEYWORDS (KEYSIZE/32)
#define BLOCKBYTES (BLOCKSIZE/8)
#define BLOCKWORDS (BLOCKSIZE/32)
X
/*
X * Rounds in Rijndael depend on key and block size.
X */
#define MINSIZE ( (BLOCKWORDS<KEYWORDS) ? BLOCKWORDS : KEYWORDS)
#define ROUNDS (MINSIZE+6)
X
/*
X * All our allocations are as unsigned 32-bit quantities
X */
u4byte key[KEYWORDS] ;
X
/*
X * the counter and a set of values to add
X * when incrementing it
X */
u4byte counter[BLOCKWORDS];
u4byte addme[BLOCKWORDS] ;
X
/*
X * results of encryption
X * and pointers into the results[] array
X */
u4byte results[BLOCKWORDS] ;
u4byte *start, *end, *current ;
/*
X * how many words of results[] to use
X * for feedback into roundkeys[]
X *
X * If this code ever goes into the kernel
X * driver, it should likely also feed a
X * word back into the /dev/random pool
X */
#define FEEDBACK 2
X
/*
X * size of roundkey array in 32-bit words
X * I cannot see why
X * (maxrounds+1) * 4 = 60
X * isn't enough, but Gladman reports
X * the change from 60 to 64 as a
X * bug fix. Safer to believe him!
X */
#define RK_SIZE 64
/*
X * roundkeys[] array and some pointers
X * into it
X * roundkeys was rijndael_e_key in the
X * original Gladman code
X */
u4byte roundkeys[RK_SIZE] ;
u4byte *endroundkeys, *nextroundkey ;
/*
X * temporary round key array
X * so we can use Gladman's code
X * to calculate new keys there
X * then add them into roundkeys[]
X * so we do not lose state
X */
u4byte trk[RK_SIZE];
X
static int init_done = 0 ;
static u4byte count ;
static FILE *fp_input ;
X
#ifdef DEBUG
/*
X * include declarations for Gladman's original code
X * and related data structures
X * so we can link to it for testing
X */
void rijndael_set_key(const u1byte key[], const u4byte key_len, int mode);
void rijndael_encrypt(const u1byte in_blk[], u1byte out_blk[]);
extern u4byte rijndael_e_key[] ;
u4byte rijndael_results[BLOCKSIZE] ;
enum dir_flag { enc = 1, dec = 2, both = 3 };
enum dir_flag mode = enc ;
#endif
X
#ifdef DEBUG
#include <unistd.h> /* for sleep() */
void BLURT( char *string )
{
X fflush(stderr);
X printf("%s\n", string);
X fflush(stdout);
X sleep(1) ;
}
void DUMP(char * string)
{
X int i ;
X fflush(stderr);
X printf("%s\n", string) ;
X printf("Our round keys:\n") ;
X for( i = 0 ; i < RK_SIZE ; i++ )
X printf("%8x%c", roundkeys[i],
X ((i%8)==7) ? '\n' : ' ') ;
X if( BLOCKWORDS == 4 ) {
X printf("Gladman round keys:\n") ;
X for( i = 0 ; i < RK_SIZE ; i++ )
X printf("%8x%c", rijndael_e_key[i],
X ((i%8)==7) ? '\n' : ' ') ;
X }
X printf("Our results[]:\n") ;
X for( i = 0 ; i < BLOCKWORDS ; i++ )
X printf("%8x ", results[i] ) ;
X printf("\n") ;
X if( BLOCKWORDS == 4 ) {
X printf("Gladman results[]:\n") ;
X for( i = 0 ; i < BLOCKWORDS ; i++ )
X printf("%8x ", rijndael_results[i] ) ;
X printf("\n") ;
X }
}
#else
#define BLURT(string)
#define DUMP(string)
#endif
X
/*
X * the following functions are our caller's interface
X *
X * these return 0 on failure, 1 on success
X * rrandom_init()
X * rrandom_close()
X * rr_self_rekey()
X * rr_full_rekey()
X * this fiils a buffer with 32-bit random numbers
X * returning a pointer to the buffer on success
X * amd NULL on failure
X * rrandom_buffer()
X */
X
/*
X * arbitrary constants
X * change to any non-zero value
X * to make your version slightly than anyone
X * else's
X */
#define ARB1 0x053f7621
#define ARB2 0x1237fd45
#define ARB3 0x29ce6873
/*
X * initialise the random number generator
X * churn is how much to churn initially
X * non-paranoids can use zero
X */
int rrandom_init(u4byte churn)
{
X int i, r ;
#ifdef DEBUG
X int flag ;
#endif ;
X u4byte temp, c ;
X char *p ;
#ifdef DEBUG
X u4byte *x, *y ;
#endif ;
X if( init_done == 0 ) {
X if( (fp_input=fopen(RANDOM,"r")) == NULL )
X return 0 ;
X }
X /*
X initialize both key and counter randomly
X Yarrow start their counter at one and reset on each rekey
X I start at a random value and never reset
X */
X if( (r=getrandom(fp_input,(char*)key,KEYBYTES)) == -1 )
X return 0 ;
X if( (r=getrandom(fp_input,(char*)counter,BLOCKBYTES)) == -1 )
X return 0 ;
X /*
X We increment the counter by an odd number other than 1
X stored in the addme[] array
X This changes more bits on each increment, costs little
X and gives one more thing for the enemy to guess
X The low 128 bits of addme[] are initialised from a
X 32-bit random number in a moderately klugey way
X It seemed worth doing something here, but not using
X much expensive randomness or complex code
X */
X p = (char *) &temp ;
X if( (r=getrandom(fp_input,p,4)) == -1 )
X return 0 ;
X for( i = 0 ; i < 4 ; i++, p++ ) {
X c = *p ;
X c = c*c ; /* expand to 16 bits */
X c += ARB1 ; /* arbitrary constant */
X addme[i] = c | 1 ; /* always odd */
X }
X for( c += ARB2 ; i < BLOCKWORDS ; i++, c += ARB3 )
X addme[i] = c | 1 ;
X /*
X set up pointers to output data
X skipping past words used as feedback
X */
X start = results + FEEDBACK ;
X current = start ;
X end = results + BLOCKWORDS ;
X /*
X pointers into key schedule, roundkeys[] array
X beginning, end, current
X */
X nextroundkey = (u4byte *) roundkeys ;
X endroundkeys = nextroundkey + RK_SIZE ;
X /*
X bookeeping variables
X */
X init_done = 1 ;
X count = 0 ;
X /*
X do initial key scheduling
X */
X rr_keysched() ;
#ifdef DEBUG
X /*
X check if we match AES size hard-wired in Gladman's code
X if so, check if we get the same roundkeys
X and if so set a flag so encryption will be tested
X */
X if( BLOCKWORDS == 4 ) {
X printf("Testing against Gladman code\n") ;
X rijndael_set_key((char *)key, KEYSIZE, mode) ;
X x = trk ;
X y = rijndael_e_key ;
X for( i = 0 ; i < RK_SIZE ; i++, x++, y++ )
X if( *x != *y ) {
X printf("failed at %d\n", i) ;
X DUMP("key setup failure in trk[]") ;
X exit(1) ;
X }
X x = roundkeys ;
X y = rijndael_e_key ;
X for( i = 0 ; i < RK_SIZE ; i++, x++, y++ )
X if( *x != *y ) {
X printf("failed at %d\n", i) ;
X DUMP("error in roundkeys[]") ;
X exit(1) ;
X }
X printf("Round keys compare OK\n") ;
X flag = 1 ;
X }
X else flag = 0 ;
X /*
X if we're going to test encryption
X call Gladman's version first because ours
X changes the roundkeys[]
X */
X if( flag )
X rijndael_encrypt((u1byte *)counter,
X (u1byte *)rijndael_results) ;
#endif
X /*
X do one encryption to set up output buffer
X with valid random data
X */
X rr_encrypt() ;
#ifdef DEBUG
X if( flag ) {
X x = results ;
X y = rijndael_results ;
X for( i = 0 ; i < BLOCKWORDS ; i++, x++, y++)
X if( *x != *y ) {
X DUMP("encryption test fails");
X exit(1) ;
X }
X printf("Encryption test OK\n") ;
X }
X printf("done schedule, churning %d times\n", churn) ;
X fflush(stdout) ;
#endif
X /*
X our one argument says how much we will churn things
X as part of initialisation
X paranoid users set it non-zero
X */
X while( churn-- )
X rr_self_rekey() ;
X return 1 ;
}
X
int rrandom_close()
{
X BLURT("close()");
X if( init_done == 0 )
X return 0 ;
X fclose(fp_input) ;
X init_done = 0 ;
X return 1 ;
}
X
/*
X * rekey using output of our encryption
X */
int rr_self_rekey()
{
X int i ;
X u4byte *p, *q ;
X BLURT("self_rekey()");
X rr_encrypt() ;
X p = results ;
X q = key ;
X for( i = 0 ; i < KEYWORDS ; i++ ) {
X *q++ = *p++ ;
X if( p >= end ) {
X rr_encrypt() ;
X p = start ;
X } }
X rr_keysched() ;
X rr_encrypt() ;
X current = start ;
X return 1 ;
}
X
/*
X * complete rekey from random source
X */
int rr_full_rekey()
{
X int i, r ;
X u4byte *p, *q ;
X BLURT("full_rekey()") ;
X /*
X first change the counter using encryption output
X Yarrow just zeroes it, but it seems better to
X keep the state somewhere.
X If the enemy knows that state, we're no worse off.
X If not, we make his problem harder.
X */
X rr_encrypt() ;
X p = counter ;
X q = results ;
X for( i = 0 ; i < BLOCKWORDS ; i++ )
X *p++ += *q++ ;
X /*
X then change the key using random inputs
X */
X if( (r=getrandom(fp_input, (u1byte *)key, KEYWORDS)) == -1)
X return 0 ;
X rr_keysched() ;
X rr_encrypt() ;
X count = 0 ;
X current = start ;
X return 1 ;
}
X
/*
X * The Yarrow paper suggests two parameters for two types of
X * rekeying:
X *
X * Pg is some small value (they use 10) after which you use
X * the generator's output to rekey.
X *
X * We are feeding material back into the roundkeys[] array
X * on every round, which should have similar effects.
X *
X * We change FEEDBACK*32 bits of the round key array after
X * every encryption, so we feed KEYSIZE bits of output back
X * every KEYWORDS/FEEDBACK encryptions. Even with maximum
X * keysize (256 bits) and minumum FEEDBACK (1 word), this
X * works out to 8 rounds.
X *
X * We change very bit of the array in RK_SIZE/FEEDBACK
X * encryptions, at most 64.
X *
X * Also, since we do not output all our results, any attack
X * based on inferring state from output is much harder.
X *
X * So we can likely safely set PG somewhat higher.
X * I considered not using it at all, but that seemed rash.
X *
X * XY is an arbitrary constant to compare PG to.
X */
#define PG 37
#define XY 17
/*
X * Ps is a larger value, they suggest less than Pg times the
X * cube root of 2^keysize, used to control full rekeying with
X * fresh random inputs. Our keysize is always >= 128 so we
X * could go up to 2^42, but we want to be conservative and
X * to have a value that fits in a 32-bit integer.
X */
X
#define PS (1<<19) /* 2 ^ 19 */
X
/*
X * fill a buffer with random output
X * checking whether we need to re-key
X */
u4byte *rrandom(u4byte *buffer, u4byte words)
{
X u4byte *p ;
X BLURT("rrandom()");
X if( buffer == NULL || words == 0)
X return NULL ;
X if ( !init_done )
X return NULL ;
X for( p = buffer ; words ; words-- ) {
X if( count >= PS ) {
X if( !rr_full_rekey() )
X return NULL ;
X }
X else if( (count%PG) == XY)
X rr_self_rekey() ;
X *p++ = *current++ ;
X if( current >= end ) {
X rr_encrypt() ;
X current = start ;
X count++ ;
X } }
X return buffer ;
}
X
/*
X * the functions below are all static, called by those above
X */
X
/*
X * call rr_encrypt_buffer(), with appropriate casts
X * then feed some of results into roundkeys[]
X */
static int rr_encrypt()
{
X int i, r ;
X BLURT("rr_encrypt()") ;
X /* encrypt counter into the results buffer */
X rr_encrypt_buffer( counter, results) ;
X /* increment the counter */
X increment() ;
X /*
X feed 32-bit words back into roundkeys[] array
X */
X for( i = 0 ; i < FEEDBACK ; i++ ) {
X r = results[i] ;
X (*nextroundkey) += r ;
X if( ++nextroundkey >= endroundkeys )
X nextroundkey = (u4byte *) roundkeys ;
X }
X current = start ;
X return 1 ;
}
X
static void rr_keysched()
{
X u4byte *p, *q ;
X int i ;
X BLURT("rr_keysched()") ;
X /*
X create new set of roundkeys in trk[]
X */
X rr_set_key( (u1byte *) key, KEYWORDS ) ;
X /*
X update roundkeys[] from trk[]
X using += since Rijndael uses ^= a lot
X and a different algebraic group seems safer
X */
X p = roundkeys ;
X q = trk ;
X for( i = 0 ; i < RK_SIZE ; i++, p++, q++ ) {
X *p += *q ;
X }
}
X
/*
X * increment the counter[]
X * by adding the contents of addme[]
X *
X */
static void increment()
{
X int i ;
X u4byte *p, *q, carry, result ;
X p = counter ;
X q = addme ;
X BLURT("increment()") ;
X for( i = carry = 0 ; i < BLOCKWORDS ; i++, p++, q++ ) {
X assert( *q & 1 ) ;
X result = *p + *q + carry ;
X if( result < *p )
X carry = 1 ;
X else carry = 0 ;
X *p = result ;
X }
}
X
/*
X * get random data into a buffer
X * return number of words got or -1 on failure
X */
static int getrandom( FILE *fp, char *buffer, unsigned n)
{
X int i, c ;
X /*
X check that size makes sense in this application
X all buffers are <= 256 bits
X so we handle 0 < bytes <= 32
X */
X if( n == 0 || n > 32 )
X return -1 ;
X BLURT("getting buffer") ;
X for( i = 0 ; i < n ; i++ )
X if( (c = getc(fp)) == EOF )
X return -1 ;
X else
X buffer[i] = c ;
X return i ;
}
X
/*
X * Code below is from Brian Gladman's implementation of
X * Rijndael, part of his set of AES candidate implementations.
X * http://www.btinternet.com/~brian.gladman
X *
X * I (Sandy Harris) have made some trivial changes:
X * reformatted
X * removed #ifdefs intended for C++ compilers
X * removed decryption, since random number generation
X * does not use it
X * replaced some macros (STATIC and RIJNDAEL)
X * removed an #if 0 ... #else block
X * used the constant KEYWORDS where he used a global
X * and some larger changes
X * rewritten to do variable block size
X * (defined in Rijndael spec, not used in AES)
X * removed his #ifdef LARGE_TABLES stuff so I'd have
X * less to rewrite
X * NOTE:
X * I have not done the extensive testing required to verify
X * that I got this right.
X *
X * However, if you define DEBUG and set BLOCKSIZE to
X * the 128 AES ciphers always use, then there are tests to
X * see if my versions work the same as Gladman's. These
X * do succeed.
X */
X
// Copyright in this code is held by Dr B.R. Gladman but free direct or
// derivative use is permitted subject to acknowledgement of its origin
// and subject to any constraints placed on the use of the algorithm by
// its designers (if such constraints may exist, this will be indicated
// below).
//
// Dr. B. R. Gladman (brian.gladman@btinternet.com). 25th January 2000.
//
// This is an implementation of Rijndael, an encryption algorithm designed
// by Daemen and Rijmen and submitted as a candidate algorithm for the
// Advanced Encryption Standard programme of the US National Institute of
// Standards and Technology.
//
// The designers of Rijndael have not placed any constraints on the use of
// this algorithm.
X
/*
X * these data, macro and function defintions
X * are unchanged from Gladman's code
X */
X
static u1byte pow_tab[256];
static u1byte log_tab[256];
static u1byte sbx_tab[256];
static u1byte isb_tab[256];
static u4byte rco_tab[ 10];
static u4byte ft_tab[4][256];
static u4byte it_tab[4][256];
X
static u4byte tab_gen = 0;
X
static inline u1byte f_mult(u1byte a, u1byte b)
{
X u1byte aa = log_tab[a], cc = aa + log_tab[b];
X
X return pow_tab[cc + (cc < aa ? 1 : 0)];
}
X
// Extract byte from a 32 bit quantity (little endian notation)
X
#define byte(x,n) ((u1byte)((x) >> (8 * (n))))
X
#define ff_mult(a,b) (a && b ? f_mult(a, b) : 0)
X
#define f_rn(bo, bi, n, k) \
X bo[n] = ft_tab[0][byte(bi[n],0)] ^ \
X ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
X ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
X ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
X
#define f_rl(bo, bi, n, k) \
X bo[n] = (u4byte)sbx_tab[byte(bi[n],0)] ^ \
X rotl(((u4byte)sbx_tab[byte(bi[(n + 1) & 3],1)]), 8) ^ \
X rotl(((u4byte)sbx_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
X rotl(((u4byte)sbx_tab[byte(bi[(n + 3) & 3],3)]), 24) ^ *(k + n)
X
#define f_nround(bo, bi, k) \
X f_rn(bo, bi, 0, k); \
X f_rn(bo, bi, 1, k); \
X f_rn(bo, bi, 2, k); \
X f_rn(bo, bi, 3, k); \
X k += 4
X
#define f_lround(bo, bi, k) \
X f_rl(bo, bi, 0, k); \
X f_rl(bo, bi, 1, k); \
X f_rl(bo, bi, 2, k); \
X f_rl(bo, bi, 3, k)
X
#define ls_box(x) \
X ((u4byte)sbx_tab[byte(x, 0)] << 0) ^ \
X ((u4byte)sbx_tab[byte(x, 1)] << 8) ^ \
X ((u4byte)sbx_tab[byte(x, 2)] << 16) ^ \
X ((u4byte)sbx_tab[byte(x, 3)] << 24)
X
static void gen_tabs(void)
{
X u4byte i, t;
X u1byte p, q;
X
X // log and power tables for GF(2**8) finite field with
X // 0x011b as modular polynomial - the simplest prmitive
X // root is 0x03, used here to generate the tables
X
X for(i = 0, p = 1; i < 256; ++i) {
X pow_tab[i] = (u1byte)p; log_tab[p] = (u1byte)i;
X p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0);
X }
X
X log_tab[1] = 0;
X
X for(i = 0, p = 1; i < 10; ++i) {
X rco_tab[i] = p;
X p = (p << 1) ^ (p & 0x80 ? 0x01b : 0);
X }
X
X for(i = 0; i < 256; ++i) {
X p = (i ? pow_tab[255 - log_tab[i]] : 0);
X q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2));
X p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2));
X sbx_tab[i] = p; isb_tab[p] = (u1byte)i;
X }
X
X for(i = 0; i < 256; ++i) {
X p = sbx_tab[i];
X
X t = ((u4byte)ff_mult(2, p)) |
X ((u4byte)p << 8) |
X ((u4byte)p << 16) |
X ((u4byte)ff_mult(3, p) << 24);
X
X ft_tab[0][i] = t;
X ft_tab[1][i] = rotl(t, 8);
X ft_tab[2][i] = rotl(t, 16);
X ft_tab[3][i] = rotl(t, 24);
X
X p = isb_tab[i];
X
X t = ((u4byte)ff_mult(14, p)) |
X ((u4byte)ff_mult( 9, p) << 8) |
X ((u4byte)ff_mult(13, p) << 16) |
X ((u4byte)ff_mult(11, p) << 24);
X
X it_tab[0][i] = t;
X it_tab[1][i] = rotl(t, 8);
X it_tab[2][i] = rotl(t, 16);
X it_tab[3][i] = rotl(t, 24);
X }
X tab_gen = 1;
}
X
// initialise the key schedule from the user supplied key
X
#define loop4(i) \
{ t = rotr(t, 8); t = ls_box(t) ^ rco_tab[i]; \
X t ^= trk[4 * i]; trk[4 * i + 4] = t; \
X t ^= trk[4 * i + 1]; trk[4 * i + 5] = t; \
X t ^= trk[4 * i + 2]; trk[4 * i + 6] = t; \
X t ^= trk[4 * i + 3]; trk[4 * i + 7] = t; \
}
X
#define loop6(i) \
{ t = rotr(t, 8); t = ls_box(t) ^ rco_tab[i]; \
X t ^= trk[6 * i]; trk[6 * i + 6] = t; \
X t ^= trk[6 * i + 1]; trk[6 * i + 7] = t; \
X t ^= trk[6 * i + 2]; trk[6 * i + 8] = t; \
X t ^= trk[6 * i + 3]; trk[6 * i + 9] = t; \
X t ^= trk[6 * i + 4]; trk[6 * i + 10] = t; \
X t ^= trk[6 * i + 5]; trk[6 * i + 11] = t; \
}
X
#define loop8(i) \
{ t = rotr(t, 8); ; t = ls_box(t) ^ rco_tab[i]; \
X t ^= trk[8 * i]; trk[8 * i + 8] = t; \
X t ^= trk[8 * i + 1]; trk[8 * i + 9] = t; \
X t ^= trk[8 * i + 2]; trk[8 * i + 10] = t; \
X t ^= trk[8 * i + 3]; trk[8 * i + 11] = t; \
X t = trk[8 * i + 4] ^ ls_box(t); \
X trk[8 * i + 12] = t; \
X t ^= trk[8 * i + 5]; trk[8 * i + 13] = t; \
X t ^= trk[8 * i + 6]; trk[8 * i + 14] = t; \
X t ^= trk[8 * i + 7]; trk[8 * i + 15] = t; \
}
/*
X * end of unchanged Gladman code
X */
X
#ifdef DEBUG
/*
X * some Gladman macros needed only for testing
X */
X
// Invert byte order in a 32 bit variable
X
#define bswap(x) (rotl(x, 8) & 0x00ff00ff | rotr(x, 8) & 0xff00ff00)
X
// Put or get a 32 bit word (v) in machine order from a byte address in (x)
X
#ifdef LITTLE_ENDIAN
#define u4byte_in(x) (*(u4byte*)(x))
#define u4byte_out(x, v) (*(u4byte*)(x) = (v))
#else
#define u4byte_in(x) bswap(*(u4byte)(x))
#define u4byte_out(x, v) (*(u4byte*)(x) = bswap(v))
#endif
X
#endif /* DEBUG */
X
/*
X * My version of Gladman's rijndael_set_key()
X *
X * Gladman's code had this putting results in
X * rijndael_e_key if flag said encryption
X * rijndael_d_key if flag said decryption
X * Then encrypt() and decrypt used those keys.
X *
X * I've removed the flag, have it always use
X * trk[], temporary round key array
X * Then rr_keysched() mixes that into roundkeys[]
X * which is what encryption uses.
X */
void rr_set_key(const u1byte in_key[], const u4byte key_len)
{
X u4byte i, t, *z;
X
X if(!tab_gen)
X gen_tabs();
X
X z = (u4byte *) in_key ;
X for( i = 0 ; i < KEYWORDS ; i++ )
X trk[i] = z[i] ;
X
X t = trk[KEYWORDS-1];
X
X switch(KEYWORDS)
X {
X case 4:
X for(i = 0; i < 10; ++i)
X loop4(i);
X break;
X
X case 6:
X for(i = 0; i < 8; ++i)
X loop6(i);
X break;
X
X case 8:
X for(i = 0; i < 7; ++i)
X loop8(i);
X break;
X default:
X assert(0); /* can't happen */
X }
X return;
}
X
/*
X * my version of Gladman's rijndaelEncrypt
X */
void rr_encrypt_buffer(u4byte in_blk[BLOCKWORDS], u4byte out_blk[BLOCKWORDS])
{
X u4byte b0[BLOCKWORDS], b1[BLOCKWORDS], *kp, *z;
X int i ;
X
X z = in_blk ;
X for( i = 0 ; i < BLOCKWORDS ; i++, z++ )
#ifdef DEBUG
X b0[i] = u4byte_in(z)^roundkeys[i] ;
#else
X b0[i] = *z^roundkeys[i] ;
#endif
X
X kp = roundkeys + BLOCKWORDS;
X for( i = 0 ; i < ROUNDS-1 ; i++ )
X if( i & 1 ) {
X f_nround(b0, b1, kp);
X }
X else {
X f_nround(b1, b0, kp);
X }
X f_lround(b0, b1, kp) ;
X
X z = out_blk ;
X for( i = 0 ; i < BLOCKWORDS ; i++, z++ )
#ifdef DEBUG
X u4byte_out(z,b0[i]) ;
#else
X *z = b0[i] ;
#endif
}
SHAR_EOF
  $shar_touch -am 08150051100 'rrandom/rrandom.c' &&
  chmod 0644 'rrandom/rrandom.c' ||
  $echo 'restore of' 'rrandom/rrandom.c' 'failed'
  if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'rrandom/rrandom.c:' 'MD5 check failed'
34fbec94e0a38ed268d4391546fc7b66 rrandom/rrandom.c
SHAR_EOF
  else
    shar_count="`LC_ALL=C wc -c < 'rrandom/rrandom.c'`"
    test 23278 -eq "$shar_count" ||
    $echo 'rrandom/rrandom.c:' 'original size' '23278,' 'current size' "$shar_count!"
  fi
fi
# ============= rrandom/rrandom.h ==============
if test -f 'rrandom/rrandom.h' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'rrandom/rrandom.h' '(file already exists)'
else
  $echo 'x -' extracting 'rrandom/rrandom.h' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'rrandom/rrandom.h' &&
/*
X * header file for using Rijndael in a random number
X * generator. Sandy Harris <sandy@storm.ca>
X */
X
/*
X * adjust if required for your machine
X */
typedef unsigned char u1byte ; /* 8-bit unsigned */
typedef unsigned int u4byte ; /* 32-bit unsigned */
X
/*
X * public interface to the random generator
X *
X * all functions return a value which should be
X * checked by the caller
X *
X * these give
X * 0 for failure
X * 1 for success
X */
int rrandom_init(u4byte) ;
int rrandom_close() ;
int rr_full_rekey() ;
int rr_self_rekey() ;
/*
X * this returns a pointer to the buffer on success
X * or NULL on failure
X */
u4byte *rrandom(u4byte *buffer, u4byte words) ;
SHAR_EOF
  $shar_touch -am 08150104100 'rrandom/rrandom.h' &&
  chmod 0644 'rrandom/rrandom.h' ||
  $echo 'restore of' 'rrandom/rrandom.h' 'failed'
  if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'rrandom/rrandom.h:' 'MD5 check failed'
873685dad611a3608be63d3734f12ff6 rrandom/rrandom.h
SHAR_EOF
  else
    shar_count="`LC_ALL=C wc -c < 'rrandom/rrandom.h'`"
    test 658 -eq "$shar_count" ||
    $echo 'rrandom/rrandom.h:' 'original size' '658,' 'current size' "$shar_count!"
  fi
fi
# ============= rrandom/rijndael.c ==============
if test -f 'rrandom/rijndael.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'rrandom/rijndael.c' '(file already exists)'
else
  $echo 'x -' extracting 'rrandom/rijndael.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'rrandom/rijndael.c' &&
X
// Copyright in this code is held by Dr B.R. Gladman but free direct or
// derivative use is permitted subject to acknowledgement of its origin
// and subject to any constraints placed on the use of the algorithm by
// its designers (if such constraints may exist, this will be indicated
// below).
//
// Dr. B. R. Gladman (brian.gladman@btinternet.com). 25th January 2000.
//
// This is an implementation of Rijndael, an encryption algorithm designed
// by Daemen and Rijmen and submitted as a candidate algorithm for the
// Advanced Encryption Standard programme of the US National Institute of
// Standards and Technology.
//
// The designers of Rijndael have not placed any constraints on the use of
// this algorithm.
X
#include "aes_defs.h"
#include "rijndael.h"
X
#define LARGE_TABLES
X
#ifdef __cplusplus
X namespace
X {
#endif
X
STATIC u1byte pow_tab[256];
STATIC u1byte log_tab[256];
STATIC u1byte sbx_tab[256];
STATIC u1byte isb_tab[256];
STATIC u4byte rco_tab[ 10];
STATIC u4byte ft_tab[4][256];
STATIC u4byte it_tab[4][256];
X
#ifdef LARGE_TABLES
X STATIC u4byte fl_tab[4][256];
X STATIC u4byte il_tab[4][256];
#endif
X
STATIC u4byte tab_gen = 0;
X
inline u1byte f_mult(u1byte a, u1byte b)
{ u1byte aa = log_tab[a], cc = aa + log_tab[b];
X
X return pow_tab[cc + (cc < aa ? 1 : 0)];
X
}
X
// Extract byte from a 32 bit quantity (little endian notation)
X
#define byte(x,n) ((u1byte)((x) >> (8 * (n))))
X
#define ff_mult(a,b) (a && b ? f_mult(a, b) : 0)
X
#define f_rn(bo, bi, n, k) \
X bo[n] = ft_tab[0][byte(bi[n],0)] ^ \
X ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
X ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
X ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
X
#define i_rn(bo, bi, n, k) \
X bo[n] = it_tab[0][byte(bi[n],0)] ^ \
X it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
X it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
X it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
X
#ifdef LARGE_TABLES
X
#define ls_box(x) \
X ( fl_tab[0][byte(x, 0)] ^ \
X fl_tab[1][byte(x, 1)] ^ \
X fl_tab[2][byte(x, 2)] ^ \
X fl_tab[3][byte(x, 3)] )
X
#define f_rl(bo, bi, n, k) \
X bo[n] = fl_tab[0][byte(bi[n],0)] ^ \
X fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
X fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
X fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
X
#define i_rl(bo, bi, n, k) \
X bo[n] = il_tab[0][byte(bi[n],0)] ^ \
X il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
X il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
X il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
X
#else
X
#define ls_box(x) \
X ((u4byte)sbx_tab[byte(x, 0)] << 0) ^ \
X ((u4byte)sbx_tab[byte(x, 1)] << 8) ^ \
X ((u4byte)sbx_tab[byte(x, 2)] << 16) ^ \
X ((u4byte)sbx_tab[byte(x, 3)] << 24)
X
#define f_rl(bo, bi, n, k) \
X bo[n] = (u4byte)sbx_tab[byte(bi[n],0)] ^ \
X rotl(((u4byte)sbx_tab[byte(bi[(n + 1) & 3],1)]), 8) ^ \
X rotl(((u4byte)sbx_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
X rotl(((u4byte)sbx_tab[byte(bi[(n + 3) & 3],3)]), 24) ^ *(k + n)
X
#define i_rl(bo, bi, n, k) \
X bo[n] = (u4byte)isb_tab[byte(bi[n],0)] ^ \
X rotl(((u4byte)isb_tab[byte(bi[(n + 3) & 3],1)]), 8) ^ \
X rotl(((u4byte)isb_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
X rotl(((u4byte)isb_tab[byte(bi[(n + 1) & 3],3)]), 24) ^ *(k + n)
X
#endif
X
STATIC void gen_tabs(void)
{ u4byte i, t;
X u1byte p, q;
X
X // log and power tables for GF(2**8) finite field with
X // 0x011b as modular polynomial - the simplest prmitive
X // root is 0x03, used here to generate the tables
X
X for(i = 0,p = 1; i < 256; ++i)
X {
X pow_tab[i] = (u1byte)p; log_tab[p] = (u1byte)i;
X
X p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0);
X }
X
X log_tab[1] = 0;
X
X for(i = 0,p = 1; i < 10; ++i)
X {
X rco_tab[i] = p;
X
X p = (p << 1) ^ (p & 0x80 ? 0x01b : 0);
X }
X
X for(i = 0; i < 256; ++i)
X {
X p = (i ? pow_tab[255 - log_tab[i]] : 0);
X q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2));
X p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2));
X sbx_tab[i] = p; isb_tab[p] = (u1byte)i;
X }
X
X for(i = 0; i < 256; ++i)
X {
X p = sbx_tab[i];
X
#ifdef LARGE_TABLES
X
X t = p; fl_tab[0][i] = t;
X fl_tab[1][i] = rotl(t, 8);
X fl_tab[2][i] = rotl(t, 16);
X fl_tab[3][i] = rotl(t, 24);
#endif
X t = ((u4byte)ff_mult(2, p)) |
X ((u4byte)p << 8) |
X ((u4byte)p << 16) |
X ((u4byte)ff_mult(3, p) << 24);
X
X ft_tab[0][i] = t;
X ft_tab[1][i] = rotl(t, 8);
X ft_tab[2][i] = rotl(t, 16);
X ft_tab[3][i] = rotl(t, 24);
X
X p = isb_tab[i];
X
#ifdef LARGE_TABLES
X
X t = p; il_tab[0][i] = t;
X il_tab[1][i] = rotl(t, 8);
X il_tab[2][i] = rotl(t, 16);
X il_tab[3][i] = rotl(t, 24);
#endif
X t = ((u4byte)ff_mult(14, p)) |
X ((u4byte)ff_mult( 9, p) << 8) |
X ((u4byte)ff_mult(13, p) << 16) |
X ((u4byte)ff_mult(11, p) << 24);
X
X it_tab[0][i] = t;
X it_tab[1][i] = rotl(t, 8);
X it_tab[2][i] = rotl(t, 16);
X it_tab[3][i] = rotl(t, 24);
X }
X
X tab_gen = 1;
}
X
#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
X
#define imix_col(y,x) \
X u = star_x(x); \
X v = star_x(u); \
X w = star_x(v); \
X t = w ^ (x); \
X (y) = u ^ v ^ w; \
X (y) ^= rotr(u ^ t, 8) ^ \
X rotr(v ^ t, 16) ^ \
X rotr(t,24)
X
#ifdef __cplusplus
X } // end of anonymous namespace
#endif
X
char* RIJNDAEL(name(void))
{
X return "rijndael";
}
X
// initialise the key schedule from the user supplied key
X
#define loop4(i) \
{ t = rotr(t, 8); t = ls_box(t) ^ rco_tab[i]; \
X t ^= RIJNDAEL(e_key)[4 * i]; RIJNDAEL(e_key)[4 * i + 4] = t; \
X t ^= RIJNDAEL(e_key)[4 * i + 1]; RIJNDAEL(e_key)[4 * i + 5] = t; \
X t ^= RIJNDAEL(e_key)[4 * i + 2]; RIJNDAEL(e_key)[4 * i + 6] = t; \
X t ^= RIJNDAEL(e_key)[4 * i + 3]; RIJNDAEL(e_key)[4 * i + 7] = t; \
}
X
#define loop6(i) \
{ t = rotr(t, 8); t = ls_box(t) ^ rco_tab[i]; \
X t ^= RIJNDAEL(e_key)[6 * i]; RIJNDAEL(e_key)[6 * i + 6] = t; \
X t ^= RIJNDAEL(e_key)[6 * i + 1]; RIJNDAEL(e_key)[6 * i + 7] = t; \
X t ^= RIJNDAEL(e_key)[6 * i + 2]; RIJNDAEL(e_key)[6 * i + 8] = t; \
X t ^= RIJNDAEL(e_key)[6 * i + 3]; RIJNDAEL(e_key)[6 * i + 9] = t; \
X t ^= RIJNDAEL(e_key)[6 * i + 4]; RIJNDAEL(e_key)[6 * i + 10] = t; \
X t ^= RIJNDAEL(e_key)[6 * i + 5]; RIJNDAEL(e_key)[6 * i + 11] = t; \
}
X
#define loop8(i) \
{ t = rotr(t, 8); ; t = ls_box(t) ^ rco_tab[i]; \
X t ^= RIJNDAEL(e_key)[8 * i]; RIJNDAEL(e_key)[8 * i + 8] = t; \
X t ^= RIJNDAEL(e_key)[8 * i + 1]; RIJNDAEL(e_key)[8 * i + 9] = t; \
X t ^= RIJNDAEL(e_key)[8 * i + 2]; RIJNDAEL(e_key)[8 * i + 10] = t; \
X t ^= RIJNDAEL(e_key)[8 * i + 3]; RIJNDAEL(e_key)[8 * i + 11] = t; \
X t = RIJNDAEL(e_key)[8 * i + 4] ^ ls_box(t); \
X RIJNDAEL(e_key)[8 * i + 12] = t; \
X t ^= RIJNDAEL(e_key)[8 * i + 5]; RIJNDAEL(e_key)[8 * i + 13] = t; \
X t ^= RIJNDAEL(e_key)[8 * i + 6]; RIJNDAEL(e_key)[8 * i + 14] = t; \
X t ^= RIJNDAEL(e_key)[8 * i + 7]; RIJNDAEL(e_key)[8 * i + 15] = t; \
}
X
void RIJNDAEL(set_key(const u1byte in_key[], const u4byte key_len, const enum dir_flag f))
{ u4byte i, t, u, v, w;
X
X if(!tab_gen)
X
X gen_tabs();
X
X mode = f;
X
X RIJNDAEL(k_len) = (key_len + 31) / 32;
X
X RIJNDAEL(e_key)[0] = u4byte_in(in_key );
X RIJNDAEL(e_key)[1] = u4byte_in(in_key + 4);
X RIJNDAEL(e_key)[2] = u4byte_in(in_key + 8);
X RIJNDAEL(e_key)[3] = u4byte_in(in_key + 12);
X
#if(0)
X
X { u4byte *k1, *k2, *km, *rcp;
X if(RIJNDAEL(k_len) > 4)
X {
X RIJNDAEL(e_key)[4] = u4byte_in(in_key + 16);
X RIJNDAEL(e_key)[5] = u4byte_in(in_key + 20);
X }
X
X if(RIJNDAEL(k_len) > 6)
X {
X RIJNDAEL(e_key)[6] = u4byte_in(in_key + 24);
X RIJNDAEL(e_key)[7] = u4byte_in(in_key + 28);
X }
X
X rcp = rco_tab; k1 = RIJNDAEL(e_key);
X k2 = k1 + RIJNDAEL(k_len);
X km = k1 + 5 * RIJNDAEL(k_len) + 24;
X t = *(k2 - 1);
X
X switch(RIJNDAEL(k_len))
X {
X case 4: while(k2 < km)
X {
X t = ls_box(rotr(t, 8)) ^ *rcp++;
X t ^= *k1++; *k2++ = t;
X t ^= *k1++; *k2++ = t;
X t ^= *k1++; *k2++ = t;
X t ^= *k1++; *k2++ = t;
X }
X break;
X
X case 6: while(k2 < km)
X {
X t = ls_box(rotr(t, 8)) ^ *rcp++;
X t ^= *k1++; *k2++ = t;
X t ^= *k1++; *k2++ = t;
X t ^= *k1++; *k2++ = t;
X t ^= *k1++; *k2++ = t;
X t ^= *k1++; *k2++ = t;
X t ^= *k1++; *k2++ = t;
X }
X break;
X
X case 8: while(k2 < km)
X {
X t = ls_box(rotr(t, 8)) ^ *rcp++;
X t ^= *k1++; *k2++ = t;
X t ^= *k1++; *k2++ = t;
X t ^= *k1++; *k2++ = t;
X t ^= *k1++; *k2++ = t;
X t = ls_box(t);
X t ^= *k1++; *k2++ = t;
X t ^= *k1++; *k2++ = t;
X t ^= *k1++; *k2++ = t;
X t ^= *k1++; *k2++ = t;
X }
X break;
X }
X }
X
#else
X
X switch(RIJNDAEL(k_len))
X {
X case 4: t = RIJNDAEL(e_key)[3];
X for(i = 0; i < 10; ++i)
X loop4(i);
X break;
X
X case 6: RIJNDAEL(e_key)[4] = u4byte_in(in_key + 16);
X t = RIJNDAEL(e_key)[5] = u4byte_in(in_key + 20);
X for(i = 0; i < 8; ++i)
X loop6(i);
X break;
X
X case 8: RIJNDAEL(e_key)[4] = u4byte_in(in_key + 16);
X RIJNDAEL(e_key)[5] = u4byte_in(in_key + 20);
X RIJNDAEL(e_key)[6] = u4byte_in(in_key + 24);
X t = RIJNDAEL(e_key)[7] = u4byte_in(in_key + 28);
X for(i = 0; i < 7; ++i)
X loop8(i);
X break;
X }
X
#endif
X
X if(mode != enc)
X {
X RIJNDAEL(d_key)[0] = RIJNDAEL(e_key)[0]; RIJNDAEL(d_key)[1] = RIJNDAEL(e_key)[1];
X RIJNDAEL(d_key)[2] = RIJNDAEL(e_key)[2]; RIJNDAEL(d_key)[3] = RIJNDAEL(e_key)[3];
X
X for(i = 4; i < 4 * RIJNDAEL(k_len) + 24; ++i)
X {
X imix_col(RIJNDAEL(d_key)[i], RIJNDAEL(e_key)[i]);
X }
X }
X
X return;
}
X
// encrypt a block of text
X
#define f_nround(bo, bi, k) \
X f_rn(bo, bi, 0, k); \
X f_rn(bo, bi, 1, k); \
X f_rn(bo, bi, 2, k); \
X f_rn(bo, bi, 3, k); \
X k += 4
X
#define f_lround(bo, bi, k) \
X f_rl(bo, bi, 0, k); \
X f_rl(bo, bi, 1, k); \
X f_rl(bo, bi, 2, k); \
X f_rl(bo, bi, 3, k)
X
void RIJNDAEL(encrypt(const u1byte in_blk[16], u1byte out_blk[16]))
{ u4byte b0[4], b1[4], *kp;
X
X b0[0] = u4byte_in(in_blk ) ^ RIJNDAEL(e_key)[0];
X b0[1] = u4byte_in(in_blk + 4) ^ RIJNDAEL(e_key)[1];
X b0[2] = u4byte_in(in_blk + 8) ^ RIJNDAEL(e_key)[2];
X b0[3] = u4byte_in(in_blk + 12) ^ RIJNDAEL(e_key)[3];
X
X kp = RIJNDAEL(e_key) + 4;
X
X if(RIJNDAEL(k_len) > 6)
X {
X f_nround(b1, b0, kp); f_nround(b0, b1, kp);
X }
X
X if(RIJNDAEL(k_len) > 4)
X {
X f_nround(b1, b0, kp); f_nround(b0, b1, kp);
X }
X
X f_nround(b1, b0, kp); f_nround(b0, b1, kp);
X f_nround(b1, b0, kp); f_nround(b0, b1, kp);
X f_nround(b1, b0, kp); f_nround(b0, b1, kp);
X f_nround(b1, b0, kp); f_nround(b0, b1, kp);
X f_nround(b1, b0, kp); f_lround(b0, b1, kp);
X
X u4byte_out(out_blk, b0[0]); u4byte_out(out_blk + 4, b0[1]);
X u4byte_out(out_blk + 8, b0[2]); u4byte_out(out_blk + 12, b0[3]);
}
X
// decrypt a block of text
X
#define i_nround(bo, bi, k) \
X i_rn(bo, bi, 0, k); \
X i_rn(bo, bi, 1, k); \
X i_rn(bo, bi, 2, k); \
X i_rn(bo, bi, 3, k); \
X k -= 4
X
#define i_lround(bo, bi, k) \
X i_rl(bo, bi, 0, k); \
X i_rl(bo, bi, 1, k); \
X i_rl(bo, bi, 2, k); \
X i_rl(bo, bi, 3, k)
X
void RIJNDAEL(decrypt(const u1byte in_blk[16], u1byte out_blk[16]))
{ u4byte b0[4], b1[4], *kp;
X
X b0[0] = u4byte_in(in_blk ) ^ RIJNDAEL(e_key)[4 * RIJNDAEL(k_len) + 24];
X b0[1] = u4byte_in(in_blk + 4) ^ RIJNDAEL(e_key)[4 * RIJNDAEL(k_len) + 25];
X b0[2] = u4byte_in(in_blk + 8) ^ RIJNDAEL(e_key)[4 * RIJNDAEL(k_len) + 26];
X b0[3] = u4byte_in(in_blk + 12) ^ RIJNDAEL(e_key)[4 * RIJNDAEL(k_len) + 27];
X
X kp = RIJNDAEL(d_key) + 4 * (RIJNDAEL(k_len) + 5);
X
X if(RIJNDAEL(k_len) > 6)
X {
X i_nround(b1, b0, kp); i_nround(b0, b1, kp);
X }
X
X if(RIJNDAEL(k_len) > 4)
X {
X i_nround(b1, b0, kp); i_nround(b0, b1, kp);
X }
X
X i_nround(b1, b0, kp); i_nround(b0, b1, kp);
X i_nround(b1, b0, kp); i_nround(b0, b1, kp);
X i_nround(b1, b0, kp); i_nround(b0, b1, kp);
X i_nround(b1, b0, kp); i_nround(b0, b1, kp);
X i_nround(b1, b0, kp); i_lround(b0, b1, kp);
X
X u4byte_out(out_blk, b0[0]); u4byte_out(out_blk + 4, b0[1]);
X u4byte_out(out_blk + 8, b0[2]); u4byte_out(out_blk + 12, b0[3]);
}
SHAR_EOF
  $shar_touch -am 08141639100 'rrandom/rijndael.c' &&
  chmod 0644 'rrandom/rijndael.c' ||
  $echo 'restore of' 'rrandom/rijndael.c' 'failed'
  if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'rrandom/rijndael.c:' 'MD5 check failed'
3b95af060a0ad1fbf06b045bc2b33b2e rrandom/rijndael.c
SHAR_EOF
  else
    shar_count="`LC_ALL=C wc -c < 'rrandom/rijndael.c'`"
    test 13868 -eq "$shar_count" ||
    $echo 'rrandom/rijndael.c:' 'original size' '13868,' 'current size' "$shar_count!"
  fi
fi
# ============= rrandom/aes_defs.h ==============
if test -f 'rrandom/aes_defs.h' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'rrandom/aes_defs.h' '(file already exists)'
else
  $echo 'x -' extracting 'rrandom/aes_defs.h' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'rrandom/aes_defs.h' &&
X
// Copyright in this code is held by Dr B. R. Gladman but free direct or
// derivative use is permitted subject to acknowledgement of its origin.
// Dr B. R. Gladman (brian.gladman@btinternet.com). 25th January 2000.
X
#ifndef _AES_DEFS_
#define _AES_DEFS_
X
// 1. Standard types for AES cryptography source code
X
typedef unsigned char u1byte; // an 8 bit unsigned character type
typedef unsigned short u2byte; // a 16 bit unsigned integer type
typedef unsigned long u4byte; // a 32 bit unsigned integer type
X
typedef signed char s1byte; // an 8 bit signed character type
typedef signed short s2byte; // a 16 bit signed integer type
typedef signed long s4byte; // a 32 bit signed integer type
X
// 2. Standard interface for AES cryptographic routines
X
#define LITTLE_ENDIAN
X
enum dir_flag { enc = 1, dec = 2, both = 3 };
X
#ifdef __cplusplus
X
# define STATIC
X
X class AES
X {
X protected:
X dir_flag mode;
X public:
X AES(void) : mode(both) { };
X virtual char *name(void) = 0;
X virtual void set_key(const u1byte key[], const u4byte key_bits, const enum dir_flag f = both) = 0;
X virtual void encrypt(const u1byte in_blk[], u1byte out_blk[]) = 0;
X virtual void decrypt(const u1byte in_blk[], u1byte out_blk[]) = 0;
X };
X
# define AESREF AES&
# define IFREF std::ifstream&
# define OFREF std::ofstream&
# define IFILE std::ifstream
# define OFILE std::ofstream
X
#else
X
# define inline __inline
# define STATIC static
# define bool int
# define false 0
# define true 1
X
X typedef char* (*name_alg)(void);
X typedef void (*key_alg)(const u1byte key[], const u4byte key_bits, const enum dir_flag f);
X typedef void (*enc_alg)(const u1byte in_blk[], u1byte out_blk[]);
X typedef void (*dec_alg)(const u1byte in_blk[], u1byte out_blk[]);
X
X typedef struct
X { name_alg name;
X key_alg set_key;
X enc_alg encrypt;
X dec_alg decrypt;
X } alg_struct;
X
X extern enum dir_flag mode; // in C the mode flag is declared in aes_aux.c
X
# define AESREF alg_struct
# define IFREF FILE*
# define OFREF FILE*
# define IFILE FILE*
# define OFILE FILE*
X
#endif
X
// 3. Basic macros for speeding up generic operations
X
// Circular rotate of 32 bit values
X
#ifdef _MSC_VER
X
# include <stdlib.h>
# pragma intrinsic(_lrotr,_lrotl)
# define rotr(x,n) _lrotr(x,n)
# define rotl(x,n) _lrotl(x,n)
X
#else
X
#define rotr(x,n) (((x) >> ((int)((n) & 0x1f))) | ((x) << ((int)((32 - ((n) & 0x1f))))))
#define rotl(x,n) (((x) << ((int)((n) & 0x1f))) | ((x) >> ((int)((32 - ((n) & 0x1f))))))
X
#endif
X
// Invert byte order in a 32 bit variable
X
#define bswap(x) (rotl(x, 8) & 0x00ff00ff | rotr(x, 8) & 0xff00ff00)
X
// Put or get a 32 bit word (v) in machine order from a byte address in (x)
X
#ifdef LITTLE_ENDIAN
X
#define u4byte_in(x) (*(u4byte*)(x))
#define u4byte_out(x, v) (*(u4byte*)(x) = (v))
X
#else
X
#define u4byte_in(x) bswap(*(u4byte)(x))
#define u4byte_out(x, v) (*(u4byte*)(x) = bswap(v))
X
#endif
X
#endif
SHAR_EOF
  $shar_touch -am 08150105100 'rrandom/aes_defs.h' &&
  chmod 0644 'rrandom/aes_defs.h' ||
  $echo 'restore of' 'rrandom/aes_defs.h' 'failed'
  if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'rrandom/aes_defs.h:' 'MD5 check failed'
b8d598686a9c53b616400f4c61fb7d45 rrandom/aes_defs.h
SHAR_EOF
  else
    shar_count="`LC_ALL=C wc -c < 'rrandom/aes_defs.h'`"
    test 3111 -eq "$shar_count" ||
    $echo 'rrandom/aes_defs.h:' 'original size' '3111,' 'current size' "$shar_count!"
  fi
fi
# ============= rrandom/rantest.c ==============
if test -f 'rrandom/rantest.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'rrandom/rantest.c' '(file already exists)'
else
  $echo 'x -' extracting 'rrandom/rantest.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'rrandom/rantest.c' &&
#include <stdio.h>
#include <stdlib.h>
X
#include "rrandom.h"
X
#define CHURN 3
#define LOOP 25
X
int main( int argc, char **argv )
{
X int i, r, loop, churn ;
X u4byte temp, *p ;
X churn = CHURN ;
X loop = LOOP ;
X /*
X add code here to change those from command line
X */
X if( (r=rrandom_init(churn)) == 1) {
X printf("init() completes----------------\n");
X fflush(stdout) ;
X }
X else {
X printf("init() failed\n") ;
X exit(1) ;
X }
X printf("looping %d times -----\n", loop) ;
X for( i = 0 ; i < loop ; i++ ) {
X if( (p=rrandom(&temp,1)) == NULL )
X printf("----- failure\n") ;
X else printf("----- %8x\n", temp) ;
X fflush(stdout);
X }
X exit(0) ;
}
SHAR_EOF
  $shar_touch -am 08141639100 'rrandom/rantest.c' &&
  chmod 0644 'rrandom/rantest.c' ||
  $echo 'restore of' 'rrandom/rantest.c' 'failed'
  if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'rrandom/rantest.c:' 'MD5 check failed'
2f03f2b263bcdf8182f380d14276591c rrandom/rantest.c
SHAR_EOF
  else
    shar_count="`LC_ALL=C wc -c < 'rrandom/rantest.c'`"
    test 644 -eq "$shar_count" ||
    $echo 'rrandom/rantest.c:' 'original size' '644,' 'current size' "$shar_count!"
  fi
fi
# ============= rrandom/rijndael.h ==============
if test -f 'rrandom/rijndael.h' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'rrandom/rijndael.h' '(file already exists)'
else
  $echo 'x -' extracting 'rrandom/rijndael.h' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'rrandom/rijndael.h' &&
X
// Copyright in this code is held by Dr B. R. Gladman but free direct or
// derivative use is permitted subject to acknowledgement of its origin.
// Dr B. R. Gladman (brian.gladman@btinternet.com). 25th January 2000.
X
#ifdef __cplusplus
X
# define RIJNDAEL(x) rijndael::##x
X
X class rijndael : public AES
X {
X private:
X u4byte k_len;
X u4byte e_key[64];
X u4byte d_key[64];
X public:
#else
X
# define RIJNDAEL(x) rijndael_##x
X
X STATIC u4byte RIJNDAEL(k_len);
/*
X * STATIC in original removed so we can see it for testing
X * this is my (Sandy Harris) only change in this file
X */
X u4byte RIJNDAEL(e_key)[64];
X STATIC u4byte RIJNDAEL(d_key)[64];
X
#endif
X
X char* RIJNDAEL(name(void));
X void RIJNDAEL(set_key(const u1byte key[], const u4byte key_len, const enum dir_flag f));
X void RIJNDAEL(encrypt(const u1byte in_blk[], u1byte out_blk[]));
X void RIJNDAEL(decrypt(const u1byte in_blk[], u1byte out_blk[]));
X
#ifdef __cplusplus
X };
#endif
SHAR_EOF
  $shar_touch -am 08150104100 'rrandom/rijndael.h' &&
  chmod 0644 'rrandom/rijndael.h' ||
  $echo 'restore of' 'rrandom/rijndael.h' 'failed'
  if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'rrandom/rijndael.h:' 'MD5 check failed'
e6b9d9f7133dc5b8e994b9f765106d40 rrandom/rijndael.h
SHAR_EOF
  else
    shar_count="`LC_ALL=C wc -c < 'rrandom/rijndael.h'`"
    test 1025 -eq "$shar_count" ||
    $echo 'rrandom/rijndael.h:' 'original size' '1025,' 'current size' "$shar_count!"
  fi
fi
# ============= rrandom/README ==============
if test -f 'rrandom/README' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'rrandom/README' '(file already exists)'
else
  $echo 'x -' extracting 'rrandom/README' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'rrandom/README' &&
This directory contains a random number generator
based on the Rijndael stream cipher. It is in
files
X rrandom.c source, heavily commented
X rrandom.h external interface
X rantest.c rather dumb test program
X Makefile
X
There is no separate design documentation.
Comments in rrandom.c should cover it.
X
This is based on Rijndael code from Brian Gladman.
See his copyright notice, toward the end of rrandom.c
X
To have code to test against, I also include
some of Gladman's original files:
X rijndael.c
X rijndael.h
X aes_defs.h
I have changed exactly one line in those files,
removing the static qualifier from a variable
definition in rijndael.h so I can compare results
from his code to mine.
SHAR_EOF
  $shar_touch -am 08150100100 'rrandom/README' &&
  chmod 0644 'rrandom/README' ||
  $echo 'restore of' 'rrandom/README' 'failed'
  if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'rrandom/README:' 'MD5 check failed'
86fc14830c876c521577d478a4449b23 rrandom/README
SHAR_EOF
  else
    shar_count="`LC_ALL=C wc -c < 'rrandom/README'`"
    test 688 -eq "$shar_count" ||
    $echo 'rrandom/README:' 'original size' '688,' 'current size' "$shar_count!"
  fi
fi
$echo $shar_n 'x -' 'lock directory' "\`_sh02109': " $shar_c
if rm -fr _sh02109; then
  $echo 'removed'
else
  $echo 'failed to remove'
fi
exit 0

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Aug 15 2000 - 21:00:36 EST