/* 
 * FBox
 *
 * Implementation of the DES FBox.
 *
 * Taken from RSAREF, and their copyrights must probably
 * also apply.
 *
 * 2000(c) Burton Rosenberg. All rights reserved.
 *
 * 1.2 : Tue Aug 31 22:54:26 EDT 2004
 * 1.1 : Tue Sep 19 14:48:02 EDT 2000
 * 1.0 : Tue Sep 19 11:50:12 EDT 2000
 */

/*
 * Bit-selection table E.
 */

unsigned char E[] = {
  32,  1,  2,  3,  4,  5,  
   4,  5,  6,  7,  8,  9,
   8,  9, 10, 11, 12, 13, 
  12, 13, 14, 15, 16, 17,
  16, 17, 18, 19, 20, 21, 
  20, 21, 22, 23, 24, 25,
  24, 25, 26, 27, 28, 29, 
  28, 29, 30, 31, 32,  1
};

/*
 * Selection functions (S-boxes). [[These are 0-origin indexed.]]
 */

unsigned char S[8][64] = {
  14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,
   0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,
   4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
  15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13,

  15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
   3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
   0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
  13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9,

  10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
  13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
  13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
   1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12,

   7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
  13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
  10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
   3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14,

   2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
  14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
   4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
  11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3,

  12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
  10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
   9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
   4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13,

   4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
  13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
   1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
   6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12,

  13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
   1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
   7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
   2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11
};

/* 
 * Permutation P.
 */

unsigned char P[32] = {
  16,  7, 20, 21, 29, 12, 28, 17,  1, 15, 23, 26,  5, 18, 31, 10,
   2,  8, 24, 14, 32, 27,  3,  9, 19, 13, 30,  6, 22, 11,  4, 25
};


/*
 * utility routines
 */

void
print2bits( char * a )
{
    int j ;
    j = (a[0]<<1) + a[1] ;
    printf("%x", j) ;
}

void
print4bits( char * a )
{
    int j ;
    j = (a[0]<<3) + (a[1]<<2) + (a[2]<<1) + a[3] ;
    printf("%x", j) ;
}

void 
print8by4( char * a )
{
    int i ;
    for ( i=0; i<32; i+=4 )
    {
       printf(" ") ;
       print4bits(a+i) ;
       printf(" ") ;
    }
    printf("\n") ;
}

void
print8by6( char * a )
{
   int i, j ;
   for ( i=0; i<48; i+= 6 )
   {
       print2bits( a+i ) ;
       print4bits( a+(i+2) ) ;
       printf(" ") ;
   }
   printf("\n") ;
}

void
unpack( unsigned long v, char * o, int count ) 
{
  unsigned bit = 1 ;
  while ( count )
  {
     count-- ;
     o[count] = (v & bit ) ? 1 : 0 ;
     bit <<= 1 ;
  }
}

unsigned long
pack( char * a, int len )
{
    unsigned long r = 0L ;
    unsigned long bit = 1L ;
    int i ;
    for ( i=len-1; i>=0; i-- )
    {
        if ( a[i] ) r |= bit ;
        bit <<= 1 ;
    }
    return r ;
}

/* 
 * FBox
 */

static int verbose = 0 ;

unsigned int 
fBox( unsigned int input, unsigned int keyhigh, unsigned int keylow )
{
  unsigned char sInput[48] ;
  unsigned char sOutput[32] ;
  unsigned char keyA[48] ;
  unsigned char eInput[32] ;
  unsigned char eOutput[48] ;
  unsigned char pOutput[32] ;

  unsigned char t ;
  unsigned int k ;

  unpack( (unsigned long) input, eInput, 32 ) ;
  unpack( (unsigned long) keyhigh, keyA, 24 ) ;
  unpack( (unsigned long) keylow, keyA+24, 24 ) ;

  for ( k=0; k<48; k++ ) eOutput[k] = eInput[E[k]-1] ;
  for ( k=0; k<48; k++ ) sInput[k] = eOutput[k] ^ keyA[k] ;

  /* 
   * Apply eight S boxes. Index into S box k is formed from these
   *     bits of sInput:
   *
   *              6*k 6*k+5 6*k+1 6*k+2 6*k+3 6*k+4
   *
   *     Value of S box k becomes these bits of sOutput:
   *     
   *                    4*k 4*k+1 4*k+2 4*k+3
   */

   for (k = 0; k < 8; k++) 
   {
        t = S[k][(sInput[6*k] << 5) | (sInput[6*k + 5] << 4) |
                 (sInput[6*k + 1] << 3) | (sInput[6*k + 2] << 2) |
                 (sInput[6*k + 3] << 1) | (sInput[6*k + 4] << 0)];

        sOutput[4*k] = (unsigned char)((t >> 3) & 1);
        sOutput[4*k + 1] = (unsigned char)((t >> 2) & 1);
        sOutput[4*k + 2] = (unsigned char)((t >> 1) & 1);
        sOutput[4*k + 3] = (unsigned char)(t & 1);
    }

    /* 
     * Compute P(sOutput).
     */
    for (k = 0; k < 32; k++) pOutput[k] = sOutput[P[k]-1];

    if ( verbose )
    {
        printf("\n") ;
        printf("======== Input ========\n") ;
        print8by4( eInput ) ;
        printf("---------- E ----------\n") ;
        print8by6( eOutput ) ;
        printf("---------- K ----------\n") ;
        print8by6( keyA ) ;
        printf("---------- + ----------\n") ;
        print8by6( sInput ) ;
        printf("---------- S ----------\n") ;
        printf("S1-S2-S3-S4-S5-S6-S7-S8\n") ;
        printf("---------- S ----------\n") ;
        print8by4( sOutput ) ;
        printf("---------- P ----------\n") ;
        print8by4( pOutput ) ;
        printf("======== Output =======\n") ;
        printf("\n") ;
    }

    return (int) pack( pOutput, 32 ) ;

}

/*
 * main
 */

void
usage()
{
    printf("fbox v h l\n") ;
    printf("     v: 32 bits of value, in hex\n") ;
    printf("     h: high 24 bits of key, in hex\n") ;
    printf("     l: low 24 bits of key, in hex\n") ;
    printf("     output: DES_{h|l}(v)\n") ;
}

int
main( int argc, char * argv[] )
{
    unsigned int t ;
    unsigned int kl ;
    unsigned int kh ;
    unsigned int s ;

    if ( argc != 4 ) 
    {
        usage() ;
        return 0 ;
    }

    verbose = 1 ;
    sscanf( argv[1], "%x", &t) ;
    sscanf( argv[2], "%x", &kh) ;
    sscanf( argv[3], "%x", &kl) ;
    s = fBox(t,kh,kl) ;

printf("fbox(0x%08x)[0x%06x%06x] = 0x%08x\n", t, kh, kl, s ) ;

    return 0 ;
 
}
