// hashattack3.c

/*
 Written by
 Huang,Jessica C : jessica9@MIT.EDU
 Huang,Kai : kaih@MIT.EDU
 Huang, Edward : eych@MIT.EDU
 Shi,Melissa F : mshi@MIT.EDU
 
 September 25, 2001

 May be freely reproduced for educational or personal use
*/

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "types.h"
#include "hashtable3.h"
#include "hashlib.h"


typedef enum { FORWARD, BACKWARD } Direction;

long initWords( char words[][ 8 ] );
void generateKey( char words[][ 8 ], long nwords, Key k );
void printKeys( Direction z, Key key1, Key key2, Key mkey1, Key mkey2 );


int main( int argc, char *argv[] )
{
    int stime;
    long ltime;

    long nwords;
    char words[ 100000 ][ 8 ];

    Vect I, D;
    Hashtable forward, backward;

    unsigned long counter;
    int match;
    Direction z;
    Key key1, key2, temp, mkey1, mkey2;
    Vect outVect;

    ltime = time( NULL );
    stime = ( unsigned int ) ltime / 2;
    srand( stime );

    nwords = initWords( words );

    I[0] = 0x0001;
    I[1] = 0x0002;
    D[0] = 0xDC98;
    D[1] = 0xF5EF;
    
    initHash( forward );
    initHash( backward );

    if ( freopen( "output.txt", "a", stdout ) == NULL ) {
        printf( "Cannot open output.txt!\n" );
        exit( 1 );
    }

    counter = 0;
    match = 0;


    while ( 1 ) {

            generateKey( words, nwords, key1 );
            generateKey( words, nwords, key2 );

            z = FORWARD; 
            RC5_SETUP( key1 );
            RC5_ENCRYPT( I, outVect );
            RC5_SETUP( key2 );
            RC5_ENCRYPT( outVect, outVect );
            hashPut( forward, outVect, key1, key2 );
            if ( hashGet( backward, outVect, mkey1, mkey2 ) )
                printKeys( z, key1, key2, mkey1, mkey2 );

            z = BACKWARD;
            // RC5_SETUP( key2 );
            RC5_DECRYPT( D, outVect );
            RC5_SETUP( key1 );
            RC5_DECRYPT( outVect, outVect );
            hashPut( backward, outVect, key1, key2 );
            if ( hashGet( forward, outVect, mkey1, mkey2 ) )
                printKeys( z, key1, key2, mkey1, mkey2 );

            copyKey( temp, key1 );
            copyKey( key1, key2 );
            copyKey( key2, temp );

            z = FORWARD; 
            RC5_SETUP( key1 );
            RC5_ENCRYPT( I, outVect );
            RC5_SETUP( key2 );
            RC5_ENCRYPT( outVect, outVect );
            hashPut( forward, outVect, key1, key2 );
            if ( hashGet( backward, outVect, mkey1, mkey2 ) )
                printKeys( z, key1, key2, mkey1, mkey2 );

            z = BACKWARD;
            // RC5_SETUP( key2 );
            RC5_DECRYPT( D, outVect );
            RC5_SETUP( key1 );
            RC5_DECRYPT( outVect, outVect );
            hashPut( backward, outVect, key1, key2 );
            if ( hashGet( forward, outVect, mkey1, mkey2 ) )
                printKeys( z, key1, key2, mkey1, mkey2 );

            ++counter;
            if ( counter % 1000 == 0 ) {
	        fprintf( stderr, "%d..", counter / 1000 );
                fflush( stderr );
            }

	    if ( counter == 600000 ) {
	        fflush( stdout );
	        exit( 0 );
	    }

    }

    return 0;
}


long initWords( char words[][ 8 ] )
{
    FILE *pfile;
    char word[ 30 ];
    long nwords = 0, j;

    if ( ( pfile = fopen( "common_edited.txt", "r" ) ) == NULL ) {
        printf( "Cannot open common_edited.txt!\n" );
        exit( 1 );
    }

    while ( fscanf( pfile, "%s", word ) != EOF ) {
        if ( strlen( word ) > 7 ) continue;
        strncpy( words[ nwords ], word, 8 );
        ++nwords;
    }

    fclose( pfile );
    return nwords;
}


void generateKey( char words[][ 8 ], long nwords, Key key )
{
    int r, len, start, i = 0, j;

    r = rand() % nwords;
    len = strlen( words[ r ] );
    start = rand() % ( 8 - len );

    for ( i = 0; i < 8; ++i ) {
        if ( start <= i && i <= start + len - 1 )
            key[ i ] = words[ r ][ i - start ];
        else
            key[ i ] = ' ';
    }
}


void printKeys( Direction z, Key key1, Key key2, Key mkey1, Key mkey2 )
{
    printf("\"");
    if ( z == FORWARD ) {
        printKeyChar( key1 );
        printKeyChar( key2 );
        printKeyChar( mkey1 );
        printKeyChar( mkey2 );
    } else {
        printKeyChar( mkey1 );
        printKeyChar( mkey2 );
        printKeyChar( key1 );
        printKeyChar( key2 );
    }
    printf("\"\n");
}
