[svn] / ecrypt / trunk / submissions / frogbit / unused / frogbit.old.c  

svn: ecrypt/trunk/submissions/frogbit/unused/frogbit.old.c

File: [svn] / ecrypt / trunk / submissions / frogbit / unused / frogbit.old.c (download) (as text)
Revision: 1, Sun Jun 26 18:46:26 2005 UTC (7 years, 10 months ago) by cdecanni
File size: 32632 byte(s)
* imported original ECRYPT submissions after first automatic cleanup.
/*        Frogbit demonstration and challenge program

          Copyright (C) 1996 CONNOTECH Experts-Conseils Inc.

Author:   Thierry Moreau

          CONNOTECH Experts-Conseils Inc.
          9130 Place de Montgolfier
          Montreal, Qc
          Canada
          H2M 2A1

Date:     April 17, 1996, revised April 2005

Revision History:

     Bug fix in LFSR generator(!).

     Idiosyncracies of 16-bit C.

     Fixed a name clash with a BSD definition in string.h

     Removed huffman coding for packing the final state in the verbose mode

     Reverted to binary ciphertext file; default binary cleartext file;
     command-line options starting with - instead of +

     Added the -o[1-7] option to omit from 1 to 7 bits from the end of the file,
     for enhanced flexibility in the standard challenge

     Enhanced source code readability with the last source code change

     Fixed a bug in state input rule enforcement

     Implemented 20 LFSRs from pi hexadecimal notation instead of 10 simpler
     LFSRs for the 10 frogbit PRNGs

     Changed from most significant bit first to least significant bit first

     Minor source code readability enhancements

Purposes: 1) to foster cryptanalysis attempts against the Frogbit
          hash function,
          2) to foster cryptanalysis attempts against the Frogbit
          encryption, granted a 25-years old attack on the
          underlying stream cipher.

Comment:  This program provides a simple file encryption
          capability, but the (claimed) distinctive advantage of
          the Frogbit algorithm is DATA INTEGRITY protection. As
          a consequence, the "challenge" aspect of this program
          relates to finding collision in a hash function.

Prerequisite: This is cryptographic stuff. The intended reader is
          familiar with the subject area.

Practical limitations: No attempt has been made to make the
          encryption capability convenient and/or portable.
          Little validation is applied to the input data (but the
          parameter values are forced to abide by the theoretical
          requirements). Moreover, although the cryptographic
          strength of this program is conjectured to be good, an
          important component (the underlying pseudo-random
          algorithm) has been deliberately chosen to be an
          INSECURE alternative.

User's guide:

     This is ANSI C source code. The compiled program is a
     command-line utility, taking four optional file names:
     cleartext file, ciphertext file, final secret key file, and
     initial secret key file.

     The main challenge is to find two pairs <cleartext file,
     initial secret key file> that produce the same final secret
     key file.

     The auxiliary challenge is to find an algorithm that
     recovers the initial secret key file from a cleartext file
     and the corresponding ciphertext file.

How to read this source code:

     Sequentially. Housekeeping stuff is identified with /**/
/*   at the beginning of each line. In addition, /*RULE*/
/*   identifies places in the source code where a theoretical
     rule is enforced (in the context of processing the initial
     secret key file).

*/

/**********************************************************************/
/***                                                                ***/
/***                The base Frogbit algorithm                      ***/
/***                                                                ***/
/**********************************************************************/

 typedef int ind_t;
 typedef int bit;

/*--------------------------------------------------------------------*/
/*---------------- the state of the Frogbit algorithm ----------------*/

 ind_t T[10];      /* the current permutation table, T(i-1-r'(i-1))   */
 ind_t d_;         /* the current key stream number, d'(i-1)          */

 bit s;            /* the previous bit, s{i-1}                        */

 /* local variables for the run length process                        */
 ind_t r_;         /* the current bounded run count, r'(i-1)          */
 ind_t acc_d;      /* accumulated binary representation K2{i-1}, k2{i}*/

/*--------------------------------------------------------------------*/
/*------------------ keystream "drift" accumulators ------------------*/

    /* These accumulators are for information purposes. Their final
       values may come into play for a hash code. The active state of
       the pseudo-random generators is dealt with later.              */

 struct cntr
 {
   unsigned long c;  /* A count of consumed keystream bits ...        */
   int i;            /*               ... for this key stream source. */
 } drift_cnt[10];

/*--------------------------------------------------------------------*/
/*------------------ the index permutation process -------------------*/

void index_permutation(int j)
{
  int temp;
  int temp_d_= T[j];
  switch((d_<<1)+s)
  {
  case 0:
     temp=T[0];T[0]=T[5];T[5]=T[2];T[2]=T[7];T[7]=temp;
     temp=T[1];T[1]=T[8];T[8]=T[6];T[6]=T[4];T[4]=T[3];T[3]=T[9];
               T[9]=temp;
    break;
  case 1:
     temp=T[0];T[0]=T[2];T[2]=T[7];T[7]=temp;
     temp=T[1];T[1]=T[3];T[3]=T[6];T[6]=T[9];T[9]=T[4];T[4]=T[8];
               T[8]=T[5];T[5]=temp;
    break;
  case 2:
     temp=T[0];T[0]=T[6];T[6]=T[8];T[8]=T[9];T[9]=T[5];T[5]=T[7];
               T[7]=T[1];T[1]=temp;
     temp=T[2];T[2]=T[4];T[4]=T[3];T[3]=temp;
    break;
  case 3:
     temp=T[0];T[0]=T[6];T[6]=temp;
     temp=T[1];T[1]=T[5];T[5]=T[3];T[3]=T[4];T[4]=T[2];T[2]=T[8];
               T[8]=T[7];T[7]=T[9];T[9]=temp;
    break;
  case 4:
     temp=T[0];T[0]=T[3];T[3]=T[6];T[6]=T[5];T[5]=T[1];T[1]=T[2];
               T[2]=temp;
     temp=T[4];T[4]=T[8];T[8]=T[7];T[7]=T[9];T[9]=temp;
    break;
  case 5:
     temp=T[0];T[0]=T[6];T[6]=T[7];T[7]=T[3];T[3]=T[1];T[1]=T[2];
               T[2]=T[9];T[9]=temp;
     temp=T[4];T[4]=T[5];T[5]=T[8];T[8]=temp;
    break;
  case 6:
     temp=T[0];T[0]=T[4];T[4]=T[3];T[3]=T[7];T[7]=T[6];T[6]=T[1];
               T[1]=T[8];T[8]=T[5];T[5]=temp;
     temp=T[2];T[2]=T[9];T[9]=temp;
    break;
  case 7:
     temp=T[0];T[0]=T[5];T[5]=T[4];T[4]=temp;
     temp=T[1];T[1]=T[9];T[9]=T[8];T[8]=T[6];T[6]=T[2];T[2]=T[3];
               T[3]=T[7];T[7]=temp;
    break;
  case 8:
     temp=T[0];T[0]=T[8];T[8]=T[9];T[9]=T[5];T[5]=T[3];T[3]=T[2];
               T[2]=T[1];T[1]=temp;
     temp=T[4];T[4]=T[6];T[6]=T[7];T[7]=temp;
    break;
  case 9:
     temp=T[0];T[0]=T[9];T[9]=T[7];T[7]=T[8];T[8]=T[1];T[1]=T[4];
               T[4]=T[2];T[2]=T[6];T[6]=temp;
     temp=T[3];T[3]=T[5];T[5]=temp;
    break;
  case 10:
     temp=T[0];T[0]=T[7];T[7]=T[2];T[2]=T[4];T[4]=T[1];T[1]=T[6];
               T[6]=T[5];T[5]=T[9];T[9]=temp;
     temp=T[3];T[3]=T[8];T[8]=temp;
    break;
  case 11:
     temp=T[0];T[0]=T[1];T[1]=T[4];T[4]=T[7];T[7]=T[5];T[5]=T[2];
               T[2]=T[8];T[8]=T[3];T[3]=temp;
     temp=T[6];T[6]=T[9];T[9]=temp;
    break;
  case 12:
     temp=T[0];T[0]=T[7];T[7]=T[6];T[6]=T[3];T[3]=temp;
     temp=T[1];T[1]=T[4];T[4]=T[9];T[9]=T[2];T[2]=T[5];T[5]=T[8];
               T[8]=temp;
    break;
  case 13:
     temp=T[0];T[0]=T[3];T[3]=T[5];T[5]=T[2];T[2]=temp;
     temp=T[1];T[1]=T[9];T[9]=T[7];T[7]=T[4];T[4]=T[6];T[6]=T[8];
               T[8]=temp;
    break;
  case 14:
     temp=T[0];T[0]=T[8];T[8]=T[4];T[4]=T[2];T[2]=T[1];T[1]=T[9];
               T[9]=T[3];T[3]=temp;
     temp=T[5];T[5]=T[7];T[7]=T[6];T[6]=temp;
    break;
  case 15:
     temp=T[0];T[0]=T[9];T[9]=T[6];T[6]=T[3];T[3]=T[1];T[1]=T[5];
               T[5]=temp;
     temp=T[2];T[2]=T[4];T[4]=T[7];T[7]=T[8];T[8]=temp;
    break;
  case 16:
     temp=T[0];T[0]=T[7];T[7]=T[2];T[2]=T[6];T[6]=T[1];T[1]=T[3];
               T[3]=T[9];T[9]=T[8];T[8]=temp;
     temp=T[4];T[4]=T[5];T[5]=temp;
    break;
  case 17:
     temp=T[0];T[0]=T[4];T[4]=T[1];T[1]=T[7];T[7]=T[8];T[8]=temp;
     temp=T[2];T[2]=T[9];T[9]=T[3];T[3]=T[5];T[5]=T[6];T[6]=temp;
    break;
  case 18:
     temp=T[0];T[0]=T[2];T[2]=T[3];T[3]=T[8];T[8]=temp;
     temp=T[1];T[1]=T[7];T[7]=T[5];T[5]=T[6];T[6]=T[4];T[4]=T[9];
               T[9]=temp;
    break;
  case 19:
     temp=T[0];T[0]=T[1];T[1]=T[6];T[6]=T[7];T[7]=T[3];T[3]=T[4];
               T[4]=temp;
     temp=T[2];T[2]=T[5];T[5]=T[9];T[9]=T[8];T[8]=temp;
    break;
  }
  d_ = temp_d_;
}

/*--------------------------------------------------------------------*/
/*-------------------- the core Frogbit algorithm --------------------*/

bit get_PR_bit(ind_t PR_gen_selector,int ik); /* Forward reference:
                                          key stream sources          */

bit encipher_bit(bit m_i_)
{
   int base;

   bit k1_i_   = get_PR_bit(d_,0);
   bit k2_i_   = get_PR_bit(d_,1);

   bit s_i_    = m_i_^k1_i_;

   drift_cnt[d_].c++;

   if (s!=s_i_)
        if (r_==0) base=0;
        else       base=(acc_d+1)<<1;
   else if (r_!=0) base=(acc_d+3)<<1;
        else
        {
          acc_d=k2_i_;
          r_=1;
          return s_i_^k2_i_;
        }

   index_permutation(base+k2_i_);
   r_= 0;
   s=s_i_;

   return s_i_^k2_i_;
}

bit decipher_bit(bit e_i_)
{
   int base;

   bit k1_i_   = get_PR_bit(d_,0);
   bit k2_i_   = get_PR_bit(d_,1);

   bit s_i_    = e_i_^k2_i_;

   drift_cnt[d_].c++;

   if (s!=s_i_)
        if (r_==0) base=0;
        else       base=(acc_d+1)<<1;
   else if (r_!=0) base=(acc_d+3)<<1;
        else
        {
          acc_d=k2_i_;
          r_=1;
          return s_i_^k1_i_;
        }

   index_permutation(base+k2_i_);
   r_= 0;
   s=s_i_;

   return s_i_^k1_i_;
}

/*--------------------------------------------------------------------*/
/*------------ default initialization of the Frogbit state -----------*/

void start_cipher(void) /* This mechanism may be overridden, and indeed
                           it is when a secret key file includes more
                           than just the PRNG state.                  */
{
  ind_t i;
  d_= s= r_= 0;

  for (i=0;i<10;i++)
  {
    T[i]=i;
    drift_cnt[i].c=0;
    drift_cnt[i].i=i;
  }

/* do the processing as if m{i}=0 until one d(i) is drawn,
   and do it once more                                          */
  do
    encipher_bit(0);
  while (r_!=0);
  encipher_bit(0);
}

/*--------------------------------------------------------------------*/

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

#if (INT_MAX<=32767)
#define L "l"
#else
#define L
#endif

/*--------------------------------------------------------------------*/
/*------------------- file encryption/decryption ---------------------*/

int omit_count=0;

void encipher(FILE *in, FILE *out)
{
  int i, c, e;
  int cnext;
  cnext=getc(in);
  if (EOF==cnext)  return;
  for (;;)
  {
    c=cnext;
    cnext=getc(in);
    if (EOF==cnext)  break;

    e=0;
    for (i=1;i<=(1<<(CHAR_BIT-1));i<<=1)
      if (encipher_bit(0!=(i&c)))  e|=i;

    fputc(e,out);
  }

  e=0;
  for (i=1;i<=(1<<(CHAR_BIT-omit_count-1));i<<=1)
    if (encipher_bit(0!=(i&c)))  e|=i;

  fputc(e,out);
}

void decipher(FILE *in, FILE *out)
{
  int i, c, e;
  int cnext;
  cnext=getc(in);
  if (EOF==cnext)  return;
  for (;;)
  {
    e=cnext;
    cnext=getc(in);
    if (EOF==cnext)  break;

    c=0;
    for (i=1;i<=(1<<(CHAR_BIT-1));i<<=1)
      if (decipher_bit(0!=(i&e)))  c|=i;

    fputc(c,out);
  }

  c=0;
  for (i=1;i<=(1<<(CHAR_BIT-omit_count-1));i<<=1)
    if (decipher_bit(0!=(i&e)))  c|=i;

  fputc(c,out);
}

/**********************************************************************/
/***                                                                ***/
/***              read and write the Frogbit state                  ***/
/***             (minimal and extended secret keys)                 ***/
/***                                                                ***/
/**********************************************************************/

/*--------------------------------------------------------------------*/
/*---------- the state of the 10 PRNGs (minimal secret key) ----------*/

unsigned long next [10][2]={{1,1},{1,1},{1,1},{1,1},{1,1}
                           ,{1,1},{1,1},{1,1},{1,1},{1,1}};

/*--------------------------------------------------------------------*/
/*---- get the state from the file data, enforce theoretical rules ---*/

void adjust_prng_state(void);                   /* forward references */
void get_prng_design(int argc, char *argv[]);

void get_state(int argc, char *argv[])
{
  int i;

  /*{ PRNG state }*/
  for (i=0;i<10;i++) {
    if (argc>(2*i+1))
    {
      next[i][0]=strtoul(argv[2*i+1],NULL,0);
    }
    else
      break;

    if (argc>(2*i+2))
    {
      next[i][1]=strtoul(argv[2*i+2],NULL,0);
    }
    else
      break;
  }

  if (argc>=21)
  {
    /*{ key-stream selection state }*/
    d_= 0;
    if (argc>21)
      d_=strtoul(argv[21],NULL,0)%10;             /*RULE*//* 0<=d_<10 */
    /*{ index permutation state }*/
    for (i=0;i<10;i++)
      T[i]=i;
    for (i=0;i<10;i++)
      if (argc>(i+22))
      {
        int ii;
        int cand=strtoul(argv[i+22],NULL,0)%10; /*RULE*//* 0<=T[i]<10 */
        for (ii=i;ii<10;ii++)
          if (T[ii]==cand)
            break;
        if (ii<10)       /*RULE*//* the vector T[10] is a permutation */
        {
          for (;ii>i;ii--)
            T[ii]=T[ii-1];
          T[i]=cand;
        }
      }
      else
        break;

    /*{ run length encoding (RLE) state }*/
    s= r_= acc_d= 0;
    if (argc>32)
      s=strtoul(argv[32],NULL,0)%2;      /*RULE*//* s is a single bit */
    if (argc>33)
      r_=strtoul(argv[33],NULL,0)%2;               /*RULE*//* 0<=r_<2 */
    if ((argc>34)&&(r_>0))
    {
      acc_d=strtoul(argv[34],NULL,0);
      acc_d%=1<<r_;                       /*RULE*//* 0<=acc_d<(2**r_) */
    }
    if (argc>35)
      /*{ PRNG design parameters }*/
      get_prng_design(argc-34,argv+34); /* rules specific to the PRNG */
    adjust_prng_state();                /* rules specific to the PRNG */
    for (i=0;i<10;i++)
    {
      drift_cnt[i].c=0;
      drift_cnt[i].i=i;
    }
  }
  else
  { /* secret key limited to PRNG state, use
       default Frogbit initialization           */
    adjust_prng_state();                /* rules specific to the PRNG */
    start_cipher();
  }
}

/*--------------------------------------------------------------------*/
/*----------- write the state to the final secret key file -----------*/

/**/void print_prng_design(FILE *fp); /* forward reference */
/**/void print_drift_accum(FILE *fp); /* forward reference */

/**/int verbose_flag=0;

/**/void print_state(FILE *fp)
/**/{
/**/  int i;
/**/  adjust_prng_state();
/**/  fprintf(fp,"{ PRNG state }");
/**/  for (i=0;i<10;i++)
/**/  {
/**/    fprintf(fp," 0x%" L "X 0x%" L "X",next[i][0],next[i][1]);
/**/    if (0==((i+2)%3)) fprintf(fp,"\n");
/**/  }
/**/  fprintf(fp,"\n");
/**/  if (verbose_flag)
/**/    print_drift_accum(fp);
/**/  fprintf(fp,"{ key-stream selection state } %d\n",d_);

/**/  fprintf(fp,"{ index permutation state }");
/**/  for (i=0;i<10;i++)
/**/    fprintf(fp," %d",T[i]);
/**/  fprintf(fp,"\n{ run length encoding (RLE) state } %d %d %d\n"
/**/         ,s,r_,acc_d%(1<<r_));
/**/  print_prng_design(fp);
/**/}

/**/int cmp_cntr(const void *a,const void *b)
/**/{
/**/  return ( (((struct cntr *)a)->c<((struct cntr *)b)->c)
/**/          ?-1
/**/          :(((struct cntr *)a)->c>((struct cntr *)b)->c)
/**/         );
/**/}

/**/void print_drift_accum(FILE *fp)
/**/{
/**/  int i;
/**/  qsort(drift_cnt,10,sizeof(drift_cnt[0]),cmp_cntr);
/**/  fprintf(fp,"{ keystream drift: %d:%" L "d"
/**/                                 ,drift_cnt[0].i,drift_cnt[0].c);
/**/  for(i=1;i<10;i++)
/**/    fprintf(fp," %d+%" L "d",drift_cnt[i].i
/**/                       ,drift_cnt[i].c-drift_cnt[i-1].c);
/**/  fprintf(fp," }\n");
/**/}

/**********************************************************************/
/***                                                                ***/
/***                      housekeeping tasks                        ***/
/***                                                                ***/
/**********************************************************************/

/*--------------------------------------------------------------------*/
/*-------- housekeeping: lexical analysis of secret key file ---------*/

/**/char file_buf[8*1024];

/**/void parse_state(FILE *fp)
/**/{
/**/  int argc;
/**/  char *argv[25+11];
/**/  char *s;

/**/  file_buf[fread(file_buf,1,sizeof(file_buf)-1,fp)]=0;
/**/  fclose(fp);
/**/  s=file_buf;
/**/  argv[0]="?";
/**/  for(argc=1;argc<(25+11);argc++)
/**/  {
/**/    for (;;)
/**/    {
/**/      char *end_comment;
/**/      argv[argc]=strtok(s," \n\r\t\v\f"); s=NULL;
/**/      if ((NULL==argv[argc])||('{'!=argv[argc][0]))
/**/        break;
/**/      for(;;)
/**/      {
/**/        end_comment=strchr(argv[argc],'}');
/**/        if (NULL!=end_comment) break;
/**/        argv[argc]=strtok(NULL," \n\r\t\v\f");
/**/        if (NULL==argv[argc])
/**/          break;
/**/      }
/**/      if (NULL==argv[argc])
/**/        break;
/**/      if (0!=*(end_comment+1))
/**/      {
/**/        argv[argc]=end_comment+1;
/**/        break;
/**/      }
/**/    }
/**/    if (NULL==argv[argc])
/**/      break;
/**/  }
/**/  get_state(argc,argv);
/**/}

/*--------------------------------------------------------------------*/
/*---------- housekeeping: help to the user in case of error ---------*/

/**/void usage(char *s)
/**/{
/**/  fprintf(stderr,
/**/     "usage: %s [flags] [inp [out [final [init]]]]\n"
/**/     "\n"
/**/     "  Frogbit file encryption demo\n"
/**/     "\n"
/**/     "flags:\n"
/**/     "   -e     encryption operation (default)\n"
/**/     "   -d     decryption operation\n"
/**/     "   -t     cleartext file is text format (default is binary file)\n"
/**/     "   -f     force overwriting existing files\n"
/**/     "   -v     a more verbose final state file\n"
/**/     "   -o[1-7] omit so many bits at the end of input file\n"
/**/     "\n"
/**/     "arguments\n"
/**/     "   inp:   input file name (default: standard input)\n"
/**/     "   out:   output file name (default: standard output)\n"
/**/     "   final: final state file name (default: standard error)\n"
/**/     "   init:  initial state file name (secret key)\n"
/**/    ,s);
/**/}

/*--------------------------------------------------------------------*/
/*- housekeeping: the main program, checking command line parameters -*/

/**/int main (int argc, char *argv[])
/**/{
/**/  FILE *in=stdin;
/**/  FILE *out=stdout;
/**/  FILE *init_st=NULL;
/**/  FILE *final_st=stderr;
/**/  int decrypt_flag=0;
/**/  int binary_flag=1;
/**/  int force_flag=0;
/**/  int i;

/**/  for (i=1;i<argc;i++)
/**/  {
/**/    if ('-'==argv[i][0])
/**/      switch (toupper(argv[i][1]))
/**/      {
/**/        case 'D':
/**/          decrypt_flag=1;
/**/        case 'E':
/**/          break;
/**/        case 'F':
/**/          force_flag=1;
/**/          break;
/**/        case 'T':
/**/          binary_flag=0;
/**/          break;
/**/        case 'V':
/**/          verbose_flag=1;
/**/          break;
/**/        case 'O':
/**/          omit_count= ((argv[i][2]>='1')&&(argv[i][2]<='7'))
/**/                     ?(argv[i][2]-'0')
/**/                     :0;
/**/          break;
/**/        default:
/**/        {
/**/          fprintf(stderr,"Error: unknown flag!\n\n");
/**/          usage(argv[0]);
/**/          exit(EXIT_FAILURE);
/**/        }
/**/      }
/**/    else
/**/      break;
/**/  }

/**/  if (argc>(i))
/**/  {
/**/    in=fopen(argv[i],(binary_flag||decrypt_flag)?"rb":"r");
/**/    if (NULL==in)
/**/      fprintf(stderr,"Error: can't open file \"%s\"!\n\n",argv[i]);
/**/  }
/**/  if (argc>(i+1))
/**/  {
/**/    out=fopen(argv[i+1],"r"); if (out) fclose(out);
/**/    if ((NULL==out)||force_flag)
/**/    {
/**/      out=fopen(argv[i+1],(binary_flag||!decrypt_flag)?"wb":"w");
/**/      if (NULL==out)
/**/    fprintf(stderr,"Error: can't open file \"%s\"!\n\n",argv[i+1]);
/**/    }
/**/    else
/**/    {
/**/      fprintf(stderr,"Error: file \"%s\" already exists!\n\n"
                        ,argv[i+1]);
/**/      out=NULL;
/**/    }
/**/  }
/**/  if (argc>(i+2))
/**/  {
/**/    final_st=fopen(argv[i+2],"r"); if (final_st) fclose(final_st);
/**/    if ((NULL==final_st)||force_flag)
/**/    {
/**/      final_st=fopen(argv[i+2],"w");
/**/      if (NULL==final_st)
/**/        fprintf(stderr,"Error: can't open file \"%s\"!\n\n"
                          ,argv[i+2]);
/**/    }
/**/    else
/**/    {
/**/      fprintf(stderr,"Error: file \"%s\" already exists!\n\n"
                        ,argv[i+2]);
/**/      final_st=NULL;
/**/    }
/**/  }
/**/  if (argc>(i+3))
/**/  {
/**/    init_st=fopen(argv[i+3],"r");
/**/    if (NULL==init_st)
/**/     fprintf(stderr,"Error: can't open file \"%s\"!\n\n",argv[i+3]);
/**/  }
/**/  if ((NULL==in)||(NULL==out)||(NULL==final_st))
/**/  {
/**/    usage(argv[0]);
/**/    exit(EXIT_FAILURE);
/**/  }

/**********************************************************************/
/***                                                                ***/
/***              here is what this program really does!            ***/
/***                                                                ***/
/**********************************************************************/

  if (NULL!=init_st) parse_state(init_st);/* use the initial key file */
  else               start_cipher();       /* use defaut (secret) key */

  if (decrypt_flag)
    decipher(in,out);
  else
    encipher(in,out);
  print_state(final_st);

  fclose(in);
  fclose(out);
  fclose(final_st);

  return EXIT_SUCCESS;
}

/**********************************************************************/
/***                                                                ***/
/***              the PRNG, pseudo-random number generator          ***/
/***                                                                ***/
/**********************************************************************/
/*

The following criteria were used to select a Pseudo-Random Number
Generator:
  -  EASILY cryptanalyzed (when used in a SIMPLE stream cipher),
  -  simple to program,
  -  single bit output,
  -  predictable period,
  -  "key space" close to 2**32 per generator.

The rationale for the first criteria is to present a SINGLE
challenge to cryptanalysis: the very FROGBIT algorithm.

We selected the "Linear Feedback Shift Register" (LFSR) generator
(also known as the Tausworthe generator). We use pairs of
independent LFSR generators to generate the bit pairs needed by
the Frogbit algorithm.

For purpose of programming, here are a few simple facts about the
LFSR generator:
i)   the single parameter of a LFSR generator is a binary number
     representing a "polynomial";
ii)  the "degree" of this polynomial is the rank of the highest
     bit of this number;
iii) the polynomial must be "irreductible", a property analogue
     to the primality of numbers, but based on "polynomial
     arithmetic",
iv)  the degree of the polynomial must be a "Marsenne prime
     number" (p such that 2**p-1 is prime), that is 2, 3, 5, 7,
     13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, and
v)   the state of the generator is a number strictly between 0
     and 2**degree.

Briefly, our design allows any irreductible polynomial of degree
up to 31 (the 20 polynomials must be of the same degree).

An extra benefit of the LFSR is the ability to let the user
customize the generator. This feature is included in this program
in order to provide another variable for cryptanalysis purposes.
Essentially, we allow the "initial secret key file" to specify
the degree, and the 20 polynomials (actually, the program uses
the largest polynomial not exceeding the specified value). The
default polynomials are the 20 largest irreductible polynomials
of degree 31.

*/

/*--------------------------------------------------------------------*/
/*--------- the design parameters of the 10 LSFR generators ----------*/

int degree=31;

unsigned long poly[10][2]=
#define DEFAULT_POLYGONS \
{{0xA43F6A87,0x85A308A7},{0x931989F7,0x8370732D}   \
/*3.243F6A88   85A308D3     13198A2E   03707344 */ \
,{0xA4093815,0xA99F31D1},{0x882EFA97,0xEC4E6C63}   \
/*  A4093822   299F31D0     082EFA98   EC4E6C89 */ \
,{0xC52821B5,0xB8D0135D},{0xBE54668B,0xB4E90C4B}   \
/*  452821E6   38D01377     BE5466CF   34E90C6C */ \
,{0xC0AC2993,0xC97C50A9},{0xBF84D5A1,0xB54708F7}   \
/*  C0AC29B7   C97C50DD     3F84D5B5   B5470917 */ \
,{0x9216D5CF,0x8979FAF1},{0xD1310BA1,0x98DFB581}}; \
/*  9216D5D9   8979FB1B     D1310BA6   98DFB5AC */
DEFAULT_POLYGONS

/*--------------------------------------------------------------------*/
/*-------------------- the LSFR generator program --------------------*/

bit get_PR_bit(ind_t ind,int ik)
{
  /* parity of each byte value */
  static const unsigned char parity[1<<CHAR_BIT]=
{0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1
,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1
,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1
,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1
,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
};

  union  /* an ANSI C programmer's trick to access individual bytes
            of a 32 bit number                                        */
  {
    unsigned long whole;
    unsigned char part[4];
  } s;
  bit return_value;

  s.whole=next[ind][ik]&poly[ind][ik];
  return_value=( parity[s.part[0]]
                ^parity[s.part[1]]
                ^parity[s.part[2]]
                ^parity[s.part[3]]
               );
  next[ind][ik]= (next[ind][ik]>>1)
                |(((unsigned long)return_value)<<(degree-1));
  return return_value;
}

/*--------------------------------------------------------------------*/
/*-- the theoretic rules specific to the state of the LSFR generator -*/

void adjust_prng_state(void)
{
  int i;
  for (i=0;i<10*2;i++)
  {
    next[i/2][i%2]&=(1UL<<degree)-1;     /*RULE*//* for a degree "n"
                               polynomial,there are "n" bits of state */
    if (0==next[i/2][i%2]) next[i/2][i%2]=1;  /*RULE*//* the state =0
                                                      must be avoided */
  }
}

/**********************************************************************/
/***                                                                ***/
/***      we allow modification of the PRNG "design" parameters     ***/
/***                                                                ***/
/**********************************************************************/

/*--------------------------------------------------------------------*/
/*- get the LSFR design from the file data, enforce theoretical rules */

void prepare_irreductibles(void);
int is_irreductible(unsigned long n);

void get_prng_design(int argc, char *argv[])
{
  unsigned long cur_poly;
  int i;
  /*{ PRNG design parameters }*/
  if (argc>1)
    degree=atoi(argv[1]);
         /*RULE*//* the degree of the polynomials is a Marsenne prime
                    number between 13 and 31 inclusive                */
  if ((degree!=13)&&(degree!=17)&&(degree!=19))
    degree=31;

  prepare_irreductibles();
  cur_poly=(1L<<degree)|((1L<<degree)-1);
  for (i=0;i<10*2;i++)
  {
    if (argc>(i+2))
      cur_poly=strtoul(argv[i+2],NULL,0);
    for(;;)
    {
              /*RULE*//* the same degree applies to every polynomials */
             /*RULE*//* an irreductible polynomial has term x**0 to 1 */
       cur_poly &= (1L<<degree)-1;
       cur_poly |= (1L<<degree)+1;
                      /*RULE*//* the polynomials must be irreductible */
       if (is_irreductible(cur_poly))
       {
         int ii;          /*RULE*//* the polynomials must be distinct */
         for (ii=0;ii<i;ii++)
           if (cur_poly==poly[ii/2][ii%2])
             break;
         if (ii>=i)
           break;
       }
       cur_poly-=2; /* try another one */
    }
    poly[i/2][i%2]=cur_poly;
    cur_poly-=2;
  }
}

/*--------------------------------------------------------------------*/
/* write the LSFR design to the final file (if not the default design)*/

/**/void print_prng_design(FILE *fp)
/**/{
/**/  static const unsigned long def_poly[10][2]=DEFAULT_POLYGONS
/**/  int i;
/**/  for (i=0;i<10*2;i++)
/**/    if (poly[i/2][i%2]!=def_poly[i/2][i%2])
/**/      break;
/**/  if ((i<10*2)||(degree!=31)||verbose_flag)
/**/  {
/**/    fprintf(fp,"{ PRNG design parameters } %d",degree);
/**/    for (i=0;i<10;i++)
/**/    {
/**/      fprintf(fp," 0x%" L "X 0x%" L "X",poly[i][0],poly[i][1]);
/**/      if (0==((i+2)%3)) fprintf(fp,"\n");
/**/    }
/**/    fprintf(fp,"\n");
/**/  }
/**/}

/**********************************************************************/
/***                                                                ***/
/***                     polynomial arithmetic                      ***/
/***                                                                ***/
/**********************************************************************/

/*--------------------------------------------------------------------*/
/*-------------------- polynomial multiplication ---------------------*/

/**/unsigned long mult_poly(unsigned long a, unsigned long b)
/**/{
/**/  unsigned long r=0;
/**/  unsigned long i;
/**/  for (i=1;i<=b;i<<=1)
/**/  {
/**/    if (b&i)
/**/      r^=a;
/**/    a<<=1;
/**/  }
/**/  return r;
/**/}

/*--------------------------------------------------------------------*/
/*----------------------- polynomial division ------------------------*/

/**/unsigned long div_poly( unsigned long div_end
/**/                      , unsigned long div_or
/**/                      , unsigned long *remainder)
/**/{
/**/  int m_end=-1;
/**/  int m_or=-1;
/**/  unsigned long r=0;
/**/  unsigned long rem=div_end;
/**/  int i;
/**/  for (i=0;i<(CHAR_BIT*sizeof(unsigned long));i++)
/**/  {
/**/    if (div_end&(1L<<i))
/**/      m_end=i;
/**/    if (div_or&(1L<<i))
/**/      m_or=i;
/**/  }
/**/  if (m_or<0) assert("Polynomial division by zero!");
/**/  for (;m_end>=m_or;m_end--)
/**/  {
/**/    if (rem&(1<<m_end))
/**/    {
/**/      rem ^= div_or<<(m_end-m_or);
/**/      r|=1<<(m_end-m_or);
/**/    }
/**/  }
/**/  *remainder=rem;
/**/  return r;
/**/}

/*--------------------------------------------------------------------*/
/*------------- find all 16 bit irreductible polynomials -------------*/

/**/#define NB_USHORT_IRREDUCTIBLES 4720
/**/unsigned int nb_ushort_irreductibles;
/**/unsigned short all_ushort_irreductibles[NB_USHORT_IRREDUCTIBLES];


/**/void prepare_irreductibles(void)
/**/{
/**/#define MAX 0x10000L
/**/#define INDICE(x) ((x-3)/2)

/**/  char *irreductible = (char *)malloc((size_t)INDICE(MAX));
/**/  long i;
/**/  long i_fact;
/**/  for (i=0;i<INDICE(MAX);i++)
/**/    irreductible[i] = 1;
/**/  for (i_fact=3;i_fact<MAX;i_fact+=2)
/**/    if (irreductible[INDICE(i_fact)])
/**/      for (i=2;;i++)
/**/      {
/**/        unsigned long ip=mult_poly(i_fact,i);
/**/        if (ip >= MAX)
/**/          break;
/**/        if (ip&1) irreductible[INDICE(ip)] = 0;
/**/      }

/**/  nb_ushort_irreductibles = 1;
/**/  for (i=0;i<INDICE(MAX);i++)
/**/    if (irreductible[i])  nb_ushort_irreductibles++;
/**/  assert(NB_USHORT_IRREDUCTIBLES==nb_ushort_irreductibles);

/**/  all_ushort_irreductibles[0] = 2;
/**/  i_fact = 1;
/**/  for (i=3;i<MAX;i+=2)
/**/    if (irreductible[INDICE(i)])
/**/       all_ushort_irreductibles[i_fact++] = i;
/**/  free(irreductible);

/**/#undef MAX
/**/#undef INDICE
/**/}

/*--------------------------------------------------------------------*/
/*----------------- 32 bit polynomial irreductibility ----------------*/

/**/int is_irreductible(unsigned long n)
/**/{
/**/  unsigned int i;
/**/  if (n>1)
/**/   for (i=0;i<nb_ushort_irreductibles;i++)
/**/   {
/**/    unsigned long rem;
/**/    if (all_ushort_irreductibles[i] >= n)
/**/       break;
/**/
/**/    div_poly(n,all_ushort_irreductibles[i],&rem);
/**/    if (0 == rem)
/**/      return 0;
/**/   }
/**/  return 1;
/**/}

/*--------------------------------------------------------------------*/
/*----------------------------- the end ------------------------------*/


eSTREAM Project

Powered by ViewCVS 1.0-dev
(Powered by Apache)

ViewCVS and CVS Help