The Cracking of Gregory Braun's Crypto v3.5

by

CASIMIR

Part C

Other Essays by Casimir
  • Cracking of Crypt-o-Text v1.21 & v1.24
  • Correspondence From Casimir On Reversing Turbo Encrypto
  • Cracking of Encrypt-It For Windows
  • Cracking of WinXFiles
  • The Cracking of File Locker
  • The Cracking of Keeper
  • The Cracking of SecurityPlus!
  • The Cracking of MasterKey v1.02/1.05
  • PART C. 'C' SOURCE FOR CRACKER

    This source code was modified,in January by Casimir, to crack version 2.6 as well as 3.5.

    
    #include <stdio.h>
    #include <io.h>
    #include <time.h>
    #include <malloc.h>
    #include <conio.h>
    #include <math.h>
    #include <fcntl.h>
    #include <dos.h>
    #include <alloc.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys\stat.h>
    
    // char_min and char_max are Unsigned Long
    const int hash1_nb=112; //number of element in Hash table 1
    static unsigned long Hash_1[hash1_nb]={
    			     0x23,0x73,0x65,0x72,  0x42,0x26,0x6E,0x7A,
    			     0x7C,0x6D,0x66,0x4D,  0x31,0x2F,0x35,0x28,
    			     0x21,0x73,0x64,0x24,  0x4D,0x71,0x2E,0x7B,
    			     0x73,0x5D,0x2B,0x73,  0x46,0x6A,0x74,0x4B,
    			     0x70,0x7A,0x53,0x64,  0x74,0x7A,0x6F,0x58,
    			     0x71,0x6D,0x62,0x5E,  0x41,0x6C,0x40,0x64,
    			     0x76,0x3A,0x73,0x3F,  0x78,0x2F,0x00,0x00,
    			     0x7C,0x62,0x21,0x70,  0x7A,0x2A,0x6C,0x73,
    			     0x3B,0x72,0x6E,0x7C,  0x6C,0x66,0x24,0x76,
    			     0x69,0x5E,0x41,0x78,  0x70,0x65,0x29,0x72,
    			     0x78,0x35,0x61,0x69,  0x63,0x26,0x39,0x2F,
    			     0x32,0x6D,0x35,0x6C,  0x73,0x69,0x34,0x40,
    			     0x30,0x64,0x6D,0x5A,  0x77,0x39,0x34,0x63,
    			     0x6D,0x71,0x70,0x66,  0x68,0x77,0x00,0x00};
    
    const int hash2_nb=56; //number of element in Hash table 2
    static unsigned long Hash_2[hash2_nb]={
    			     0x7C,0x62,0x21,0x70,  0x7A,0x2A,0x6C,0x73,
    			     0x3B,0x72,0x6E,0x7C,  0x6C,0x66,0x24,0x76,
    			     0x69,0x5E,0x41,0x78,  0x70,0x65,0x29,0x72,
    			     0x78,0x35,0x61,0x69,  0x63,0x26,0x39,0x2F,
    			     0x32,0x6D,0x35,0x6C,  0x73,0x69,0x34,0x40,
    			     0x30,0x64,0x6D,0x5A,  0x77,0x39,0x34,0x63,
    			     0x6D,0x71,0x70,0x66,  0x68,0x77,0x00,0x00};
    
    
    /****************************  PROTOTYPES  *****************************/
    void Hi_folks(void);
    int Get_target(void);
    void Fill_header(int,char **,int);
    int Get_release(int);
    unsigned long Calc_key0(int,unsigned long *,unsigned long **);
    void Calc_coef(int,int,unsigned long ***,unsigned long **,int ***,int **,
    	       int **);
    void Calc_pwd_bound(int,int,unsigned long,unsigned long,unsigned long *,
    		    unsigned long **,unsigned long **);
    int Check_key1(unsigned long,unsigned long);
    void Calc_key0_bound(unsigned long,unsigned long,unsigned long *,
    		     unsigned long *);
    void Check_parity(unsigned long,int,int,int *,int *,int **,int **);
    void Check_inter(int,int,int *,int **,unsigned long,unsigned long,
    		 unsigned long *,unsigned long *,int **);
    void Check_inter4(int,int,int *,int **,int *,unsigned long,
    		  unsigned long,unsigned long *,unsigned long *);
    int Next_pwd(int,unsigned long,unsigned long,int,int,int *,
    	     unsigned long **,unsigned long **);
    int Adj_parity(int,int,int,int,unsigned long,unsigned long **);
    void Adj_char(int,unsigned long,unsigned long,unsigned long,unsigned long,
    	      unsigned long,unsigned long *,unsigned long *,int);
    void Wait_key();
    void Print_pwd(int,unsigned long *);
    unsigned long Get_key_chk(int);
    
    /******************************   MAIN   *******************************/
    main()
    {
    int pwd_len_min=1;
    int pwd_len_max=56;
    unsigned long char_min,char_max;
    unsigned long char_min_no_ext=0x20; // SPACE
    unsigned long char_max_no_ext=0x7E; // ~
    unsigned long char_min_ext=0xFFFFFFE7;
    unsigned long char_max_ext=0xFFFFFFF6;
    unsigned long char_min_adj,char_max_adj;
    unsigned long const_or  = 0x06A30DE8;
    unsigned long const_mul = 0x000343FD;
    unsigned long const_add = 0x00269EC3;
    unsigned long mask = 0x7FFF0000;
    unsigned long key0,key1,key_chk;
    unsigned long key_a,key_b,key_c,key_d,key_e,key_f,key_g,key_tmp; //temp vars
    unsigned long key_right,last_key1,step,delta_key;
    int done_half,done_all,use_mask,too_high,failed,pwd_found,char_ext;
    int const_or_odd,key1_odd,nb_zone_ok,i,len;
    float combi;
    int fn;       //encrypted file'handle
    int ver;  //26 or 35
    
    unsigned long **Coef;
    unsigned long *Coef_sum;
    int **Odd;
    int *Odd_nb;
    int *Last_odd;
    int *Parity_ok;
    int *Zone_ok;
    int *Intersection;
    unsigned long *Pwd;
    unsigned long *Bound_min;
    unsigned long *Bound_max;
    unsigned long key0_min,key0_max;
    
    Pwd=(unsigned long *)malloc(sizeof(unsigned long)*pwd_len_max);
    Parity_ok=(int *)malloc(sizeof(int)*(pwd_len_max+1));
    Zone_ok=(int *)malloc(sizeof(int)*(pwd_len_max+1));
    Intersection=(int *)malloc(sizeof(int)*(pwd_len_max+1));
    
    //for Crypto v3.5, 3 steps:
    //step 1 : read key_chk from cipher's header
    //step 2 : find 1 or more key1 compatible with key_chk
    //step 3 : find a Password and a key0 compatible with each key1 found
    
    //for Crypto v2.6, 2 steps only (as key_chk = key1):
    //step 1 : read key_chk = key1 from cipher's header
    //step 2 : find a  Password and a key0 compatible with key1
    
    Hi_folks();
    fn=Get_target();
    ver=Get_release(fn);
    key_chk=Get_key_chk(fn);
    //solve for key_chk
    Calc_coef(pwd_len_min,pwd_len_max,&Coef,&Coef_sum,&Odd,&Odd_nb,&Last_odd);
    //One loop for non-extended characters, one loop for extended characters
    for(char_ext=0;char_ext<=1;char_ext++)
    {
    if(!char_ext) {char_min=char_min_no_ext; char_max=char_max_no_ext;}
    else {char_min=char_min_ext; char_max=char_max_ext;}
    Calc_pwd_bound(pwd_len_min,pwd_len_max,char_min,char_max,Coef_sum,
    	       &Bound_min,&Bound_max);
    
    const_or_odd=(const_or&0x00000001); //0:even    1:odd
    step=((0xFFFFFFFF/(0x00010000+const_mul))+1);
    key_right=(key_chk*0x00010000); //with key_chk=12345678 : key_right=56780000
    done_half = 0;
    done_all  = 0;
    use_mask  = 0;
    if(ver==26) {key1=key_chk;}
    else
    {key1=((key_right+0x00007FFF-const_add+(use_mask*0x80000000))/(0x00010000+const_mul));}
    do
     {
     too_high = 0;
     key_tmp=((0x00010000+const_mul)*key1+const_add-(use_mask*0x80000000));
     //check if key1 OK
     if(((key_tmp >= key_right) && (key_tmp <= (key_right+0x0000FFFF))) || (ver==26))
      {
      key_a = (const_mul * key1 + const_add);
      //check masking
      if((((key_a <  0x80000000) && (use_mask == 0)) ||
         ((key_a >= 0x80000000) && (use_mask == 1))) || (ver==26))
       {
       key_b = key_a & mask;
       key_c = key_b / 0x10000;
       key_d = key_a * const_mul + const_add;
       key_e = key_d & mask;
       key_f = key_c + key_e;
       key_g = key_f + key1;
       if((key_g == key_chk) || (ver==26))
        {
        for(i=0;i<=pwd_len_max;i++) {Zone_ok[i]=1;}
        if((Check_key1(key1,const_or)) || (ver==26))
         {//solve for key1
         key1_odd=(key1&0x00000001); //0:even    1:odd
         Calc_key0_bound(const_or,key1,&key0_min,&key0_max);
         nb_zone_ok=pwd_len_max-pwd_len_min+1;
         if(!const_or_odd)
          {
          Check_parity(key1,pwd_len_min,pwd_len_max,Odd_nb,&nb_zone_ok,&Zone_ok,
    		   &Parity_ok);
          }
         if(nb_zone_ok)
          {
          Check_inter(pwd_len_min,pwd_len_max,&nb_zone_ok,&Zone_ok,
    		  key0_min,key0_max,Bound_min,Bound_max,&Intersection);
          }
         if(nb_zone_ok)
          {
          Check_inter4(pwd_len_min,pwd_len_max,&nb_zone_ok,&Zone_ok,Intersection,
    		   key1,const_or,Bound_min,Bound_max);
          }
         if(nb_zone_ok)
          {
          pwd_found=0;
          failed=0;
          for(len=pwd_len_min;len<=pwd_len_max;len++)
           {//search pwd in each valid zone
           if(Zone_ok[len])
    	{//start iterations
    	Adj_char(Intersection[len],Coef_sum[len],key0_min,key0_max,
    		 char_min,char_max,&char_min_adj,&char_max_adj,char_ext);
    	pwd_found=0;
    	failed=0;
    	combi=0;
    	for(i=0;i<len;i++) {Pwd[i]=char_min_adj;}
    	do
    	 {
    	 combi++;
    	 key0=Calc_key0(len,Pwd,Coef);
    	 if((key0 | const_or) == key1) {pwd_found=1;}
    	 else
    	  {
    	  if(!Next_pwd(len,char_min_adj,char_max_adj,const_or_odd,key1_odd,
    		       Last_odd,Coef,&Pwd))
    	   {
    	   failed=1;
    	   }
    	  }
    	 } while((!pwd_found) && (!failed));
    	}//stop iterations
           if(pwd_found)
    	{
    	Print_pwd(len,Pwd);
    	Wait_key();
    	//break;
    	exit(0);
    	}
           }//each len
          if(!pwd_found) {printf("\n%08lX : [%02d] : PWD NOT FOUND)",key1,len,combi);}
          }
         }//each key1 found
        }
       }
      }
     //go on searching
     if(key_tmp > (key_right+0x0000FFFF))
      {
      delta_key=(key_tmp-key_right);
      too_high=1;
      }
     else
      {
      delta_key = ((key_right+0x0000FFFF)-key_tmp);
      }
     //check delta
     if(delta_key >= (0x00010000+const_mul))
      {
      if(too_high) {key1--; }
      else {key1++; }
      }
     else
      {
      last_key1=key1;
      key1+=step;
      if(key1 <= last_key1)
       {
       if(done_half) {done_all = 1;}
       else
        {
        done_half = 1;
        use_mask = 1;
        key1=(((key_right+0x00007FFF)-const_add+(use_mask*0x80000000))/(0x00010000+const_mul));
        }
       }
      }
     } while(!done_all); //stop when no more key1 to try
    }//2 loops
    exit(0);
    }
    
    /***********************************************************************/
    /**************************   FUNCTIONS   ******************************/
    /***********************************************************************/
    
    /***********************************************************************/
    /* If Intersection is of type 1 2 3 we increase char_min and/or        */
    /* decrease char_max so we search only in the useful zone              */
    /*                             |------ key0 ------|                    */
    /* before adjust:     |-------- search zone --------|                  */
    /*  after adjust:              |-- search  zone --|                    */
    void Adj_char(int intersection,unsigned long coef_sum,
    	      unsigned long key0_min, unsigned long key0_max,
    	      unsigned long char_min,unsigned long char_max,
    	      unsigned long *char_min_adj,unsigned long *char_max_adj,
    	      int char_ext)
    {
    unsigned long min,max;
    
    if((intersection==0) || (intersection==4) || (char_ext))
       {
       *char_min_adj=char_min;
       *char_max_adj=char_max;
       return;
       }
    
    //intersection 1 2 3
    min=floor(key0_min/coef_sum);
    if(min<char_min) {min=char_min;}
    max=ceil(key0_max/coef_sum);
    if(max>char_max) {max=char_max;}
    
    if(intersection==1)
       {*char_min_adj=min;      *char_max_adj=max;      return;}
    if(intersection==2)
       {*char_min_adj=min;      *char_max_adj=char_max; return;}
    if(intersection==3)
       {*char_min_adj=char_min; *char_max_adj=max;      return;}
    
    }
    
    /***********************************************************************/
    /* If key0 must be odd, then we must multiplicate at least 1 odd       */
    /* coeficient by 1 odd character.                                      */
    /* If the character which is multiplied by the odd coeficient is even, */
    /* then we add 1 to the character, if possible                         */
    /* e.g:             coeficient     EVEN ODD EVEN EVEN EVEN             */
    /* before adjust:    character       20  20   20   20   20             */
    /*  after adjust:    character       20  21   20   20   20             */
    /* return 0 if can't adjust parity, otherwise return 1                 */
    int Adj_parity(int const_or_odd,int key0_odd,int key1_odd,int last_odd,
    	       unsigned long char_max,unsigned long **Pwd)
    {
    if(const_or_odd) {return(1);}                 //no need to adjust parity
    if(key0_odd == key1_odd) {return(1);}         //no need to adjust parity
    if((*Pwd)[last_odd] == char_max) {return(0);} //can not adjust parity
    else {(*Pwd)[last_odd]++; return(1);}         //parity adjusted
    }
    
    /***********************************************************************/
    /* Password is made of n characters, for each character Pwd[i] we have:*/
    /*                    char_min <= Pwd[i] <= char_max                   */
    /* Every possible password is tried, until good password is found.     */
    /* This function calculates a new password to try.                     */
    /* e.g.: password's lenght=5, char_min=0x41 ("A"), char_max=0x5A ("Z") */
    /*           41 41 41 41 41   <--- first password to try               */
    /*           41 41 41 41 42                                            */
    /*            .  .  .  .  .                                            */
    /*           41 41 41 42 41                                            */
    /*            .  .  .  .  .                                            */
    /*           5A 5A 5A 5A 5A   <--- last password to try 	       */
    /* Return 1 if there is a new password to try                          */
    /* Return 0 if no more password to try                                 */
    int Next_pwd(int len,unsigned long char_min,unsigned long char_max,
    	     int const_or_odd,int key1_odd,int *Last_odd,
    	     unsigned long **Coef,unsigned long **Pwd)
    {
    int i,found,failed;
    int key0_odd;
    unsigned long key0;
    
    i=(len-1);
    found=0;
    failed=0;
    do
       {
       (*Pwd)[i]++;
       if( ((*Pwd)[i]<=char_max) && ((*Pwd)[i]!=0))
          {
          key0=Calc_key0(len,*Pwd,Coef);
          key0_odd=(key0&0x00000001); //0:even    1:odd
          if(Adj_parity(const_or_odd,key0_odd,key1_odd,Last_odd[len],char_max,Pwd))
    	 {
    	 found=1;
    	 }
          else
    	 {
    	 if(i) {(*Pwd)[i]=char_min; i--;}
    	 else {failed=1;}
    	 }
          }
       else
          {
          if(i) {(*Pwd)[i]=char_min; i--;}
          else {failed=1;}
          }
       } while((!found) && (!failed));
    
    if(found) {return(1);}
    else {return(0);}
    }
    
    /***********************************************************************/
    /* If Intersection is of type 4, we are not sure that a valid key0     */
    /* (i.e. a key0 such as: key0 OR or_const = key1) can be found in zone */
    /* because neither key0_min nor key0_max are included in search space  */
    /* case 4:   |------- k0 -------| <-- key0 belongs to this space       */
    /*                   |-- key --|  <-- we search here B_min<=key<=B_max */
    /* so we check that B_min and B_max are not both wrong and similar     */
    /* for instance:    B_min OR const_or != key1                          */
    /*                  B_max OR const_or != key1                          */
    /*          high bits                      low bits                    */
    /*  B_min = 000011111001101111000000...............                    */
    /*  B_max = 000011111001101111111100...............                    */
    /*          <   similarity * >                                         */
    /*	                   |                                           */
    /*                       wrong bit                                     */
    /* B_min and B_max are similar and wrong, so we skip this zone         */
    void Check_inter4(int pwd_len_min,int pwd_len_max,int *nb_zone_ok,
    		  int **Zone_ok,int *Intersection,unsigned long	key1,
    		  unsigned long const_or,unsigned long *Bound_min,
    		  unsigned long *Bound_max)
    {
    int i,len,bad_bit,bad_bit_pos,same_start;
    unsigned long o_v_bit,bound_min_bit,bound_max_bit,key1_bit,mask;
    
    for(len=pwd_len_min;len<=pwd_len_max;len++)
       {
       if(Intersection[len]==4)
          {
          bad_bit=0; mask=0x80000000;
          for(i=31;i>=0;i--)
    	 {
    	 o_v_bit=(const_or & mask);
    	 if(!o_v_bit)
    	    {
    	    bound_min_bit=(Bound_min[len] & mask);
    	    key1_bit=(key1 & mask);
    	    if(bound_min_bit!=key1_bit)
    	       {
    	       bad_bit=1;
    	       bad_bit_pos=i;
    	       break;
    	       }
    	    }
    	 mask/=2;
    	 }
          if(bad_bit)
    	 {
    	 same_start=1; mask=0x80000000;
    	 for(i=31;i>=bad_bit_pos;i--)
    	    {
    	    bound_min_bit=(Bound_min[len] & mask);
    	    bound_max_bit=(Bound_max[len] & mask);
    	    if(bound_min_bit!=bound_max_bit) {same_start=0; break;}
    	    mask/=2;
    	    }
    	 if(same_start)
    	    {
    	    if((*Zone_ok)[len])
    	       {
    	       (*Zone_ok)[len]=0;
    	       (*nb_zone_ok)--;
    	       }
    	    }
    	 }
          }
       } //each pwd_len
    }
    
    /***********************************************************************/
    /* We have:                                                            */
    /* Good   Zone (GZ) : k0_min <= key0 <= k0_max                         */
    /* Search Zone (SZ) :  B_min <= key0 <= B_max                          */
    /* Given k0_min, k0_max, B_min, B_max, 5 intersection cases possible:  */
    /*                                                                     */
    /* case 0:   |--- GZ ---|                or               |--- GZ ---| */
    /*                        |--- SZ ---|      |--- SZ ---|               */
    /*                                                                     */
    /* case 1:            |--- GZ ---|                                     */
    /*           |---------- SZ ----------| 	                       */
    /*                                                                     */
    /* case 2:                |------- GZ -------|                         */
    /*           |--------- SZ ---------|                                  */
    /*                                                                     */
    /* case 3:   |----- GZ -----|                                          */
    /*                |---------- SZ ----------|                           */
    /*                                                                     */
    /* case 4:   |------------ GZ ------------|                            */
    /*                            |-- SZ --|                               */
    /* so:                                                                 */
    /*       if case = 0: skip zone, otherwise: keep zone                  */
    void Check_inter(int pwd_len_min,int pwd_len_max,int *nb_zone_ok,
    		 int **Zone_ok,unsigned long key0_min,unsigned long key0_max,
    		 unsigned long *Bound_min,unsigned long *Bound_max,
    		 int **Intersection)
    {
    int len,key1_odd;
    
    for(len=pwd_len_min;len<=pwd_len_max;len++)
       {
       if((Bound_max[len]<key0_min) || (Bound_min[len]>key0_max))
          {
          (*Intersection)[len]=0;
          if((*Zone_ok)[len])
    	 {
    	 (*Zone_ok)[len]=0;   //null intersection: bad zone
    	 (*nb_zone_ok)--;
    	 }
          }
       else if(Bound_min[len]<=key0_min)
          {
          if(Bound_max[len]>=key0_max) {(*Intersection)[len]=1;}
          else {(*Intersection)[len]=2;}
          }
       else
          {
          if(Bound_max[len]>=key0_max) {(*Intersection)[len]=3;}
          else {(*Intersection)[len]=4;}
          }
       }
    }
    
    /***********************************************************************/
    /*  we have:            key0 OR const_or = key1                        */
    /*  remember that:                                                     */
    /*                       ODD   OR  ODD   =  ODD                        */
    /*                       ODD   OR  EVEN  =  ODD                        */
    /*                       EVEN  OR  EVEN  =  EVEN                       */
    /*    key0 = weighted sum of Password's characters                     */
    /*         = Coef[len][0]*Pwd[0] + ... + Coef[len][len-1]*Pwd[len-1]   */
    /*  remember too that:                                                 */
    /*     ODD   *  ODD   =  ODD            ODD   +  ODD   =  EVEN         */
    /*     ODD   *  EVEN  =  EVEN           ODD   +  EVEN  =  ODD          */
    /*     EVEN  *  EVEN  =  EVEN           EVEN  +  EVEN  =  EVEN         */
    /*  so if key1 is ODD and const_or is EVEN, key0 must be ODD           */
    /*  and to obtain an ODD key0, you must have at least 1 ODD coeficient */
    /*  this function checks that key1 can effectively be obtained using   */
    /*  calculated coeficients                                             */
    /*  Parity_ok = 1: no problem, key1 can be obtained: keep zone         */
    /*  Parity_ok = 0: wrong, key1 can not be obtained:  skip zone         */
    void Check_parity(unsigned long key1,int pwd_len_min,int pwd_len_max,
    		  int *Odd_nb,int *nb_zone_ok,int **Zone_ok,int **Parity_ok)
    {
    int len,key1_odd;
    
    key1_odd=(key1&0x00000001); //0:even    1:odd
    
    for(len=pwd_len_min;len<=pwd_len_max;len++)
       {
       if(key1_odd && !Odd_nb[len])
          {
          (*Parity_ok)[len]=0;
          if((*Zone_ok)[len])
    	 {
    	 (*Zone_ok)[len]=0;
    	 (*nb_zone_ok)--;
    	 }
          }
       else {(*Parity_ok)[len]=1;}
       }
    }
    
    /***********************************************************************/
    /* we look for key0_min and key0_max:    key0_min <= key0 <= key0_max  */
    /* key1 and const_or are known                                         */
    /* key0_min: smallest key0 value such as: key0_min OR const_or = key1  */
    /* key0_max: largest  key0 value such as: key0_max OR const_or = key1  */
    void Calc_key0_bound(unsigned long const_or,unsigned long key1,
    		     unsigned long *key0_min,unsigned long *key0_max)
    {
    *key0_max=key1;
    *key0_min=key1-const_or;
    }
    
    /***********************************************************************/
    /*  we have:          key0 OR const_or = key1                          */
    /*  at this point, we don't know key0 but we can check that key1 is    */
    /*  compatible with const_or (const_or is a known constant)            */
    /*  so we check, at BIT level, that:  const_or[ 0] < or = key1[ 0]     */
    /*                                    const_or[ 0] < or = key1[ 0]     */
    /*                                            ...                      */
    /*                                    const_or[31] < or = key1[31]     */
    /*  return 1 if compatible, 0 otherwise                                */
    int Check_key1(unsigned long key1,unsigned long const_or)
    {
    int i;
    unsigned long o_v_bit, key1_bit, mask=1;
    
    for(i=0;i<32;i++)
       {
       o_v_bit=(const_or & mask);
       key1_bit=(key1 & mask);
       if(o_v_bit>key1_bit) {return(0); /*no good*/}
       mask*=2;
       }
    return(1); //OK
    }
    
    /***********************************************************************/
    /*    Coeficient depend only on:                                       */
    /*      - 2 hash tables (H1 and H2)                                    */
    /*      - password's lenght (len)                                      */
    /*      - coeficient's position (l)                                    */
    /*                                                                     */
    /*    Coeficient[len][l] = Hash_1[len+l] * Hash_2[l] * l               */
    void Calc_coef(int pwd_len_min,int pwd_len_max,unsigned long ***Coef,
    	       unsigned long **Coef_sum,int ***Odd,int **Odd_nb,
    	       int **Last_odd)
    {
    int i,l,len;
    unsigned long h1h2,h1h2l;
    
    (*Coef)=(unsigned long **)malloc(sizeof(unsigned long *)*(pwd_len_max+1));
    (*Odd)=(int **)malloc(sizeof(int *)*(pwd_len_max+1));
    (*Coef_sum)=(unsigned long *)malloc(sizeof(unsigned long)*(pwd_len_max+1));
    (*Odd_nb)=(int *)malloc(sizeof(int)*(pwd_len_max+1));
    (*Last_odd)=(int *)malloc(sizeof(int)*(pwd_len_max+1));
    
    for(len=pwd_len_min;len<=pwd_len_max;len++)
       {
       (*Coef)[len]=(unsigned long *)malloc(sizeof(unsigned long)*len);
       (*Odd)[len]=(int *)malloc(sizeof(int)*len);
       }
    
    for(len=pwd_len_min;len<=pwd_len_max;len++)
       {
       (*Odd_nb)[len]=0;
       (*Coef_sum)[len]=0;
       for(l=0;l<len;l++)
          {
          h1h2=Hash_1[l+len]*Hash_2[l];
          h1h2l=h1h2*(l+1);
          (*Coef)[len][l]=h1h2l;
          (*Coef_sum)[len]+=h1h2l;
          if(h1h2l&0x00000001)
    	 {
    	 (*Odd)[len][l]=1;
    	 (*Odd_nb)[len]++;
    	 (*Last_odd)[len]=l;
    	 }
          else {(*Odd)[len][l]=0;}
          }
       }
    }
    
    /***********************************************************************/
    /*   we have:                                                          */
    /*         key0 = Co[len][0]*Pwd[0] + ... + Co[len][len-1]*Pwd[len-1]  */
    /*   so the smallest value we can obtain for key0 is:                  */
    /*    B_min[len] = Co[len][0]*char_min + ... + Co[len][len-1]*char_min */
    /*               = Coef_sum[len]*char_min                              */
    /*   and the greatest value:                                           */
    /*    B_max[len] = Co[len][0]*char_max + ... + Co[len][len-1]*char_max */
    /*               = Coef_sum[len]*char_max                              */
    /*   B_min and B_max delimit a search zone                             */
    void Calc_pwd_bound(int pwd_len_min,int pwd_len_max,
    		    unsigned long char_min,unsigned long char_max,
    		    unsigned long *Coef_sum,
    		    unsigned long **Bound_min,unsigned long **Bound_max)
    {
    int len;
    unsigned long tmp;
    
    (*Bound_min)=(unsigned long *)malloc(sizeof(unsigned long)*(pwd_len_max+1));
    (*Bound_max)=(unsigned long *)malloc(sizeof(unsigned long)*(pwd_len_max+1));
    
    for(len=pwd_len_min;len<=pwd_len_max;len++)
       {
       (*Bound_min)[len]=Coef_sum[len]*char_min;
       (*Bound_max)[len]=Coef_sum[len]*char_max;
       }
    }
    
    /***********************************************************************/
    /*    key0 = weighted sum of Password's characters                     */
    /*         = Coef[len][0]*Pwd[0] + ... + Coef[len][len-1]*Pwd[len-1]   */
    /*    return key0                                                      */
    unsigned long Calc_key0(int len,unsigned long *Pwd,unsigned long **Coef)
    {
    int i;
    unsigned long key0;
    
    key0=0;
    for(i=0;i<len;i++)
       {
       key0+=(Coef[len][i]*Pwd[i]);
       }
    return(key0);
    }
    
    /***********************************************************************/
    void Hi_folks(void)
    {
    printf("\n\nYet Another Password Cracker by CASIMIR {:-)");
    printf("\n-> Target: Crypto v2.6/3.5 by Gregory Braun\n");
    }
    
    /***********************************************************************/
    /*    try to open crypted file  (must be in the SAME directory)        */
    /*    - success : return file'handle                                   */
    /*    - failure : exit prg                                             */
    int Get_target(void)
    {
    unsigned char buf[110];
    int fn;
    
    printf("\nFile to decrypt [ e.g: secret.(=txt=) or secret.(_t ]? ");
    gets(buf);
    
    // try to open file
    fn=open(buf,O_BINARY|O_RDONLY);
    switch(fn)
       {
       case -1:printf("\nFILE NOT FOUND!");
       printf("\n->File to crack MUST be in SAME directory as Cracker");
       printf("\n->DO NOT forget file's extension (usually (=txt=) or (_t)!\n");
       Wait_key(); exit(0);
       default: /*printf("\nOK, FILE FOUND")*/; return(fn);
       }
    }
    
    /***********************************************************************/
    /* Header from encrypted file has following structure:                 */
    /*                                                                     */
    /* v2.6:   CryptoHeader????pathfilename.............encryptedfile      */
    /* v3.5:   CryptoHdrBlk????pathfilename.............encryptedfile      */
    /*         <------------- 276 bytes ---------------><  original >      */
    /*                                                       size          */
    /* The ???? is the key_chk we're looking for.                          */
    unsigned long Get_key_chk(int fn)
    {
    unsigned long *Buffer;
    
    //start reading on byte 12
    lseek(fn,12,0);
    //read 4 bytes
    read(fn,Buffer,4);
    close(fn);
    return(*Buffer);
    }
    
    /***********************************************************************/
    /* The 12 first characters from header tell us which release of Crypto */
    /* was used to encrypt file:                                           */
    /*     CryptoHeader <=> v2.6                                           */
    /*     CryptoHdrBlk <=> v3.5                                           */
    int Get_release(int fn)
    {
    char *tmp;
    tmp=(char *)malloc(sizeof(char)*13);
    read(fn,tmp,12);
    tmp[12]='\0';
    if(!strcmp(tmp,"CryptoHeader")) {return(26);}
    else {return(35);}
    }
    
    /***********************************************************************/
    /*                   wait for key pressed                              */
    void Wait_key()
    {
    printf("\n");
    printf("              ******************\n");
    printf("              * hit any key... *\n");
    printf("              ******************\n");
    getch(); {/* wait until key pressed */}      //kbhit
    }
    
    /***********************************************************************/
    /*                        display password                             */
    void Print_pwd(int pwd_len,unsigned long *Pwd)
    {
    int i;
    int pwd_char;
    
    printf("\n\n ASCII seq: ");
    for(i=0;i<pwd_len;i++)
       {//normal character : 000000XX      extended character : FFFFFFXX
       if(Pwd[i]<0x80) {pwd_char=Pwd[i];}
       else {pwd_char=(Pwd[i]-0xFFFFFF00);}
       printf("[%d]",pwd_char);
       if((i+1)%10==0) {printf("\n            ");}
       }
    
    printf("\n\n  PASSWORD: >>>");
    for(i=0;i<pwd_len;i++)
       {
       if(Pwd[i]<0x80) {pwd_char=Pwd[i];}
       else {pwd_char=(Pwd[i]-0xFFFFFF00);}
       printf("%c",Pwd[i]);
       }
    printf("<<< (%d characters)\n\n",pwd_len);
    printf("(don't type >>> and <<<)\n");
    }
    
    Here is the executable

    Copyright September 1999, January 2000 by Casimir.

    Mail Casimir

    Converted to hypertext by Joe Peschel September 20, 1999; revised January 8, 2000.