FTP Search to find the software.)
This file presents cracking procedure for both proprietary algorithms found in this software:
3 Way Proprietary
Multilayer Proprietary +
Source code (C) for a cracker is also provided.
Map of the essay:
Introduction
Strategy
PART A - REVERSING OF EIW
1. Warm up
2. What's going on with my input?
2.1. Task 1: Computation of Block_size
2.2. Task 2: Permutations in encrypted file
3. Building of Sum_vector
4. Making of Xor_vector
5. Making of Cmp_vector
6. The Ultimate CMP
PART B - ANALYSIS AND BREAKING OF EIW
1. Questions/answers
2. Mimic of EIW
3. The 3 solving methods
3.1. High speed solving method
3.2. Medium speed solving method
3.3. Low speed solving method
PART C - SOURCE FOR CRACKER
PART C - SOURCE FOR CRACKER
OK, enough blah-blah, compile C listing below into DOS executable CRACKEIW.EXE, and enjoy!
********************************************************************************
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <errno.h>
#include <dir.h>
#include <string.h>
#include <dos.h>
#include <alloc.h>
#include <malloc.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <math.h>
// PROTOTYPES
void Hi_folks(void);
int Get_target(void);
void Chrono(void);
void Wait_key();
int Min(int,int);
int Max(int,int);
void Print_pwd(int,int *,time_t);
void Euclid(int,int **);
int Odd(int);
void Update_pwd(int,int,int **,int **);
void Fill_buffer(int,char **,int);
int Shift(int,int,int ***,int *);
void Set_free_vars(int,int,int,int **,int *,int ***,int ***,int **);
void Set_other_vars(int,int,int,int,int,int **,int *,int ***,int ***,int **);
int Check_eqs(int,int,int,int,int **,int *,int **,int ***,int **);
void Order_vars(int,int **);
int Calc_free_nb(int *,int,int *,int *);
void Extract(unsigned char *,int,int,int,int **,int **,int *,int **,int **);
int Check_block_size(int,int,int *);
int Check_init_12(int,int,int *);
int Check_tail_0(int,int,int *,int *);
int Speed_high(int,int,int,int,int *,int **);
int Check_char_0(int,int,int *);
int Speed_medium(int,int,int,int,int *,int **);
int Check_init_12_pwd(int,int,int *);
int Check_pwd(int,int *,int *);
int Can_break(char *,int *);
void Show_progress(int,int,int);
int Speed_low(int,int,int,int,int *,int *,int **,int **,int **,int **,
int ***,int ***,int ***);
main()
{
const int buf_size=1000;
const int name_size=12;
const int head_size=8;
int soft_len_max; // max pwd'lenght allowed by EIW (40 or 123 characters)
int fn; //encrypted file'handle
int pwd_len,pwd_len_min,pwd_len_max; // pwd_len_min<=pwd_len<=pwd_len_max
int char_0; // 13ψ character in permuted file
int block_size; //0x02<=block_size<=0x11
int tail_0_nb; //number of "0" (0x00) AFTER password in Tail
int i,found;
time_t time_start,t; // chrono
char *Buffer; // storage for beginning of encrypted file
int *Pwd;
int *Header,*Name_enc,*Pwd_enc,*Tail; //arrays filled with cypher file
int *Order,*Sum,*Char_0_bin;
int **Carry,**Pwd_enc_bin,**Pwd_bin; //*_bin : binary variables
Hi_folks();
fn=Get_target();
Fill_buffer(fn,&Buffer,buf_size);
if(!Can_break(Buffer,&soft_len_max)) {Wait_key(); exit(0);}
//we search the whole range
pwd_len_min=5;
pwd_len_max=soft_len_max;
time_start=time(NULL); //start chrono
printf("\nPROGRESS |");
Pwd=(int *)malloc(sizeof(int)*soft_len_max);
Header=(int *)malloc(sizeof(int)*8);
Name_enc=(int *)malloc(sizeof(int)*12);
Pwd_enc=(int *)malloc(sizeof(int)*soft_len_max);
Tail=(int *)malloc(sizeof(int)*(124));
Order=(int *)malloc(sizeof(int)*soft_len_max);
Sum=(int *)malloc(sizeof(int)*soft_len_max);
Char_0_bin=(int *)malloc(sizeof(int)*8);
Pwd_bin=(int **)malloc(sizeof(int *)*soft_len_max);
Pwd_enc_bin=(int **)malloc(sizeof(int *)*soft_len_max);
Carry=(int **)malloc(sizeof(int *)*soft_len_max);
for(i=0;i<soft_len_max;i++)
{
Pwd_bin[i]=(int *)malloc(sizeof(int)*8);
Pwd_enc_bin[i]=(int *)malloc(sizeof(int)*8);
Carry[i]=(int *)malloc(sizeof(int)*8);
}
// ******** MAIN LOOPS ********
for(pwd_len=pwd_len_min;pwd_len<=pwd_len_max;pwd_len++) //loop 0
{
tail_0_nb=soft_len_max+1-pwd_len;
Show_progress(pwd_len,tail_0_nb,soft_len_max);
for(block_size=0x02;block_size<=0x11;block_size++) //loop 1
{
Extract(Buffer,block_size,pwd_len_max,soft_len_max,&Header,&Name_enc,
&char_0,&Pwd_enc,&Tail);
if(tail_0_nb>=pwd_len)
{
found=Speed_high(pwd_len,block_size,soft_len_max,char_0,Tail,&Pwd);
}
else
{
if(tail_0_nb>=12)
{
found=Speed_medium(pwd_len,block_size,soft_len_max,char_0,Tail,&Pwd);
}
else
{
found=Speed_low(pwd_len,block_size,soft_len_max,char_0,Pwd_enc,Tail,
&Pwd,&Order,&Sum,&Char_0_bin,&Carry,&Pwd_enc_bin,&Pwd_bin);
}
}
if(found) {break;}
} //end loop 1 (each block_size)
if(found) {break;}
} //end loop 0 (each pwd_len)
Print_pwd(pwd_len,Pwd,time_start);
Wait_key();
}
/***************************************************************************/
/************************* FUNCTIONS ***************************/
/***************************************************************************/
/***************************************************************************/
/* Method used to recover largest passwords (up to 40 and 123 characters) */
int Speed_low(int pwd_len,int block_size,int soft_len_max,int char_0,
int *Pwd_enc,int *Tail,int **Pwd,int **Order,int **Sum,
int **Char_0_bin,int ***Carry,int ***Pwd_enc_bin,int ***Pwd_bin)
{
int first_var; // where to start enumeration
int case_1,case_2;
int init_12,temp_int;
int free_nb; // number of free variable(s), can be 0
int found; // 0: pwd not found yet 1: pwd found
int i,j,weight; //0<=weight<=7
for(i=0;i<pwd_len;i++)
{
(*Order)[i]=0; (*Pwd)[i]=0; (*Sum)[i]=0;
for(j=0;j<8;j++) {(*Pwd_bin)[i][j]=0; (*Pwd_enc_bin)[i][j]=0;
(*Carry)[i][j]=0;}
}
for(i=0;i<pwd_len;i++)
{
Euclid(Pwd_enc[i],&(*Pwd_enc_bin)[i]);
}
Euclid(char_0,Char_0_bin);
Order_vars(pwd_len,Order);
free_nb=Calc_free_nb(*Order,pwd_len,&case_1,&case_2);
for(init_12=0x00;init_12<0x100;init_12++) //loop 2
{
for(i=0;i<pwd_len;i++) {(*Pwd)[i]=0; (*Carry)[i][0]=0;}
if(char_0>=init_12) {temp_int=char_0-init_12;}
else {temp_int=0x100+char_0-init_12;}
Euclid(temp_int,&(*Pwd_bin)[(*Order)[0]]); //!!!!
for(weight=0;weight<8;weight++) //loop 3: slicing
{ //initializations
for(i=0;i<pwd_len;i++) {(*Sum)[i]=0;}
for(i=0;i<pwd_len && i!=(*Order)[0];i++) {(*Pwd_bin)[i][weight]=0;}
first_var=0;
(*Sum)[0]=(*Char_0_bin)[weight];
do //loop 4:solving
{
Set_free_vars(first_var,free_nb,weight,*Pwd_enc_bin,*Order,Pwd_bin,Carry,Sum);
Set_other_vars(pwd_len,case_1,case_2,free_nb,weight,*Pwd_enc_bin,*Order,Pwd_bin,Carry,Sum);
found=Check_eqs(case_1,case_2,pwd_len,weight,*Pwd_enc_bin,*Order,*Pwd_bin,Carry,Sum);
if(found)
{
Update_pwd(pwd_len,weight,*Pwd_bin,Pwd);
break;
}
else {if(!Shift(free_nb,weight,Pwd_bin,&first_var)) {break;}}
} while(!found); //end loop 4
if(!found) {break;}
} //end loop 3 (each weight)
if(found)
{// begin checks
if(Check_block_size(pwd_len,block_size,(*Pwd)))
{
if(Check_init_12(pwd_len,init_12,(*Pwd)))
{
if(Check_tail_0(pwd_len,soft_len_max,(*Pwd),Tail))
{
if(Check_pwd(pwd_len,(*Pwd),Tail))
{
//printf("\nSlow Way block:%x init_12:%x len:%d PWD FOUND ",
//block_size,init_12,pwd_len);
return(1);
}
}
}
}
}// end checks
}//end loop 2 (each init_12)
return(0);
}
/***************************************************************************/
/* Can be used to recover passwords longer than with Speed_high, but */
/* some more work is needed. max pwd'lenght=29 (Int. Ver.) */
/* or 112 characters (U.S. Ver.) */
/* init_12=Sum(pwd'chars)+first 12 chars of pwd (wrap if pwd'lenght<12) */
/* Build password using 3 rounds: */
/* Pwd[13],Pwd[14],...,Pwd[23],Pwd[24] 1ψ round */
/* Pwd[12] */
/* Pwd[ 0],Pwd[ 1],...,Pwd[10],Pwd[11] 2ψ round */
/* Pwd[25],Pwd[26],...and so on 3ψ round */
int Speed_medium(int pwd_len,int block_size,int soft_len_max,int char_0,
int *Tail,int **Pwd)
{
const int name_size=12;
int i,sum,init_12,init_12_pwd,pos,tail_0_nb,temp;
tail_0_nb=soft_len_max+1-pwd_len;
for(init_12_pwd=0x00;init_12_pwd<0x100;init_12_pwd++) //loop 0
{
sum=init_12_pwd;
for(i=0;i<name_size;i++)
{//1ψ round: (sum+Pwd[13+i])^Tail[pwd_len+i]=0x00 => Pwd[13+i]
pos=name_size+1+pwd_len+i;
pos=fmod(pos,pwd_len);
if(Tail[pwd_len+i]>=sum) {(*Pwd)[pos]=Tail[pwd_len+i]-sum;}
else {(*Pwd)[pos]=0x100+Tail[pwd_len+i]-sum;}
sum+=(*Pwd)[pos];
sum=(sum&0x000000FF); //mask
}
for(init_12=0x00;init_12<0x100;init_12++) //loop 1
{
if(char_0>=init_12) {(*Pwd)[12]=char_0-init_12;}
else {(*Pwd)[12]=0x100+char_0-init_12;}
sum=init_12+(*Pwd)[12];
sum=(sum&0x000000FF); //mask
for(i=0;i<name_size;i++)
{//2ψ round: (sum+Pwd[13+i])^Tail[i]=Pwd[i] => Pwd[i]
pos=name_size+1+i;
pos=fmod(pos,pwd_len);
sum+=(*Pwd)[pos];
sum=(sum&0x000000FF); //mask
(*Pwd)[i]=(sum^Tail[i]);
}
for(i=25;i<pwd_len;i++)
{//3ψ round: (sum+Pwd[25+i])^Tail[12+i]=Pwd[12+i] => Pwd[25+i]
temp=(*Pwd)[i-13]^Tail[i-13];
if(temp>=sum) {(*Pwd)[i]=temp-sum;}
else {(*Pwd)[i]=0x100+temp-sum;}
sum+=(*Pwd)[i];
sum=(sum&0x000000FF); //mask
}
//begin checks
if(Check_block_size(pwd_len,block_size,(*Pwd)))
{
if(Check_init_12(pwd_len,init_12,(*Pwd)))
{
if(Check_char_0(char_0,pwd_len,(*Pwd)))
{
if(Check_init_12_pwd(pwd_len,init_12_pwd,(*Pwd)))
{
if(Check_tail_0(pwd_len,soft_len_max,(*Pwd),Tail))
{
if(Check_pwd(pwd_len,(*Pwd),Tail))
{
//printf("\nSnail Way block:%x init_12:%x init_12_pwd:%x len:%d PWD FOUND ",
//block_size,init_12,init_12_pwd,pwd_len);
return(1);
}
}
}
}
}
}//end checks
}//end loop 1 (each init_12)
}//end loop 0 (each init_12_pwd)
return(0);
}
/***************************************************************************/
/* Fastest method. Direct computation of password, no "guessing" needed. */
/* Can only be used if pwd to recover is short enough: max pwd'lenght=20 */
/* (International Version) or 62 characters (U.S. Version). */
/* Build whole pwd: Pwd[13],Pwd[14],...,Pwd[pwd_len-1],Pwd[0],...,Pwd[12]. */
int Speed_high(int pwd_len,int block_size,int soft_len_max,int char_0,
int *Tail,int **Pwd)
{
const int name_size=12;
int i,sum,init_12_pwd,pos;
for(init_12_pwd=0x00;init_12_pwd<0x100;init_12_pwd++) //loop 0
{
sum=init_12_pwd;
for(i=0;i<pwd_len;i++)
{
pos=name_size+1+pwd_len+i;
pos=fmod(pos,pwd_len);
if(Tail[pwd_len+i]>=sum) {(*Pwd)[pos]=Tail[pwd_len+i]-sum;}
else {(*Pwd)[pos]=0x100+Tail[pwd_len+i]-sum;}
sum+=(*Pwd)[pos];
sum=(sum&0x000000FF); //mask
}
//begin checks
if(Check_block_size(pwd_len,block_size,(*Pwd)))
{
if(Check_char_0(char_0,pwd_len,(*Pwd)))
{
if(Check_init_12_pwd(pwd_len,init_12_pwd,(*Pwd)))
{
if(Check_tail_0(pwd_len,soft_len_max,(*Pwd),Tail))
{
if(Check_pwd(pwd_len,(*Pwd),Tail))
{
//printf("\nFast Way block:%x init:%x len:%d ",block_size,init_12_pwd,pwd_len);
return(1);
}
}
}
}
}//end checks
}//end loop 0 (each init_12_pwd)
return(0);
}
/***************************************************************************/
/* Ultimate (and more time-costing) test for accepting pwd. */
/* EIW performs exactly the same test in International and U.S. releases. */
/* Return 1 if pwd pass test, 0 if it fails. */
int Check_pwd(int pwd_len,int *Pwd,int *Tail)
{
int i,sum,dec_pwd,pos;
for(i=0,sum=0;i<pwd_len;i++) {sum+=Pwd[i];} // Sum(pwd'chars)
for(i=0;i<=12;i++) {pos=fmod(i,pwd_len); sum+=Pwd[pos];}
for(i=0;i<pwd_len;i++)
{
pos=13+i;
pos=fmod(pos,pwd_len);
sum+=Pwd[pos];
sum=(sum&0x000000FF); //mask
dec_pwd=(sum^Tail[i]);
if(dec_pwd!=Pwd[i]) {return(0); /*no good*/}
}
return(1); //OK, good pwd!
}
/***************************************************************************/
/* check if char_0=0 (0x00) after decryption */
/* return 1 if OK, 0 otherwise */
int Check_char_0(int char_0,int pwd_len,int *Pwd)
{
const int name_size=12;
int i,sum,pos; //pos=position in pwd (0...pwd_len-1)
for(i=0,sum=0;i<pwd_len;i++) {sum+=Pwd[i];} // Sum(pwd'chars)
for(i=0;i<=name_size;i++) {pos=fmod(i,pwd_len); sum+=Pwd[pos];}
sum=(sum&0x000000FF); //mask
if(sum==char_0) {return(1);} //char_0=(sum^char_0)
else {return(0);}
}
/***************************************************************************/
/* Called by speed_low routine: return number of free variable(s) */
int Calc_free_nb(int *Order,int pwd_len,int *case_1,int *case_2)
{
const int name_size=12;
int free_nb;
(*case_1)=pwd_len-(Order[0]+1);
(*case_2)=Order[0];
if(pwd_len!=(name_size+1)) {free_nb=Min((*case_1),(*case_2));}
else {free_nb=Max((*case_1),(*case_2));}
return(free_nb);
}
/***************************************************************************/
/* Called by speed_low routine: order all variables (free+other) */
void Order_vars(int pwd_len,int **Order)
{
const int name_size=12;
int i,start;
if(pwd_len>name_size) {start=name_size;}
else {start=fmod(name_size,pwd_len);}
for(i=0;i<pwd_len;i++)
{
if(start+i<pwd_len) {(*Order)[i]=start+i;}
else {(*Order)[i]=start+i-pwd_len;} //wrap
}
}
/***************************************************************************/
/* Called by speed_low routine: checks remaining equation(s) */
/* Return 1 if OK, 0 otherwise */
int Check_eqs(int case_1,int case_2,int pwd_len,int weight,int **Pwd_enc_bin,
int *Order,int **Pwd_bin,int ***Carry,int **Sum)
{
int i;
// test(s)
i=Max(case_1,case_2);
for(i;i<pwd_len-1;i++)
{
if(Pwd_bin[i][weight]==Pwd_enc_bin[i][weight])
{
if(Odd((*Sum)[i]+(*Carry)[i][weight]+Pwd_bin[Order[i+1]][weight])) {return(0);}
}
else
{
if(!Odd((*Sum)[i]+(*Carry)[i][weight]+Pwd_bin[Order[i+1]][weight])) {return(0);}
}
(*Carry)[i][weight+1]=floor(((*Sum)[i]+Pwd_bin[Order[i+1]][weight]+(*Carry)[i][weight])/2);
(*Sum)[i+1]=(*Sum)[i]+Pwd_bin[Order[i+1]][weight];
}
//last test
i=pwd_len-1;
if(Pwd_bin[i][weight]==Pwd_enc_bin[i][weight])
{
if(Odd((*Sum)[i]+(*Carry)[i][weight]+Pwd_bin[Order[0]][weight])) {return(0);}
}
else
{
if(!Odd((*Sum)[i]+(*Carry)[i][weight]+Pwd_bin[Order[0]][weight])) {return(0);}
}
(*Carry)[i][weight+1]=floor(((*Sum)[i]+Pwd_bin[Order[0]][weight]+(*Carry)[i][weight])/2);
return(1);
}
/***************************************************************************/
/* Called by speed_low routine: sets non-free variable(s) during slicing */
void Set_other_vars(int pwd_len,int case_1,int case_2,int free_nb,int weight,
int **Pwd_enc_bin,int *Order,int ***Pwd_bin,int ***Carry,
int **Sum)
{
int i;
//set other variables
if(case_1<case_2)
{ //right=fψ(left)
for(i=free_nb;i<Order[0];i++)
{
if(Odd((*Sum)[i]+(*Pwd_bin)[Order[i+1]][weight]+(*Carry)[i][weight]))
{
if(Odd(Pwd_enc_bin[i][weight])) {(*Pwd_bin)[i][weight]=0;}
else {(*Pwd_bin)[i][weight]=1;}
}
else
{
if(Odd(Pwd_enc_bin[i][weight])) {(*Pwd_bin)[i][weight]=1;}
else {(*Pwd_bin)[i][weight]=0;}
}
(*Carry)[i][weight+1]=floor(((*Sum)[i]+(*Pwd_bin)[Order[i+1]][weight]
+(*Carry)[i][weight])/2);
(*Sum)[i+1]=(*Sum)[i]+(*Pwd_bin)[Order[i+1]][weight];
}
}
else
{ //left=fψ(right)
for(i=free_nb;i<pwd_len-(Order[0]+1);i++)
{
if((*Pwd_bin)[i][weight]==Pwd_enc_bin[i][weight])
{
if(Odd((*Sum)[i]+(*Carry)[i][weight])) {(*Pwd_bin)[Order[i+1]][weight]=1;}
else {(*Pwd_bin)[Order[i+1]][weight]=0;}
}
else
{
if(Odd((*Sum)[i]+(*Carry)[i][weight])) {(*Pwd_bin)[Order[i+1]][weight]=0;}
else {(*Pwd_bin)[Order[i+1]][weight]=1;}
}
(*Carry)[i][weight+1]=floor(((*Sum)[i]+(*Pwd_bin)[Order[i+1]][weight]
+(*Carry)[i][weight])/2);
(*Sum)[i+1]=(*Sum)[i]+(*Pwd_bin)[Order[i+1]][weight];
}
}
}
/***************************************************************************/
/* Called by speed_low routine: sets free variable(s) (if any) */
void Set_free_vars(int first_var,int free_nb,int weight,int **Pwd_enc_bin,
int *Order,int ***Pwd_bin,int ***Carry,int **Sum)
{
int i;
for(i=first_var;i<free_nb;i++) //set free variable(s)
{
if(Odd(Pwd_enc_bin[i][weight]+(*Pwd_bin)[i][weight]))
{
if(Odd((*Sum)[i]+(*Carry)[i][weight])) {(*Pwd_bin)[Order[i+1]][weight]=0;}
else {(*Pwd_bin)[Order[i+1]][weight]=1;}
}
else
{
if(Odd((*Sum)[i]+(*Carry)[i][weight])) {(*Pwd_bin)[Order[i+1]][weight]=1;}
else {(*Pwd_bin)[Order[i+1]][weight]=0;}
}
//carry
(*Carry)[i][weight+1]=floor(((*Sum)[i]+(*Carry)[i][weight]
+(*Pwd_bin)[Order[i+1]][weight])/2);
//sum
(*Sum)[i+1]=(*Sum)[i]+(*Pwd_bin)[Order[i+1]][weight]; //do NOT add carry !
}
}
/***************************************************************************/
/* return 0 if no more combi to try, 1 otherwise */
int Shift(int free_nb,int weight,int ***Pwd_bin,int *first_var)
{
int i;
for(i=free_nb-1;i>=0;i--) //backward
{
if(!(*Pwd_bin)[i][weight])
{
// OK, var i can be changed
(*Pwd_bin)[i][weight]++;
*first_var=i;
return(1);
}
else {(*Pwd_bin)[i][weight]=0;} //reset
}
return(0); //no more combi to try => stop
}
/***************************************************************************/
void Hi_folks(void)
{
printf("\n\n CASIMIR'Cracker for: Encrypt-It for Windows (MaeDae Enterprises)");
printf("\n For International & U.S./Canadian versions\n");
}
/***************************************************************************/
/* try to open crypted file (must be in the SAME directory) */
/* - success : return file'handle */
/* - fail : exit prg */
int Get_target(void)
{
unsigned char buf[100];
int fn;
printf("\nFile to decrypt [e.g: SECRETXT.~00]? ");
gets(buf);
// try to open file
fn=open(buf,O_BINARY|O_RDONLY);
switch(fn)
{
case -1:printf("\nFILE NOT FOUND! (file to crack MUST be in SAME");
printf("\ndirectory than Cracker; file'name CAN NOT exceed");
printf("\n8 characters; DO NOT forget file'extension!)\n ");
Wait_key(); exit(0);
default: /*printf("\nOK, FILE FOUND")*/; return(fn);
}
}
/***************************************************************************/
/* chronometer */
void Chrono(void)
{
static time_t t1;
time_t t2;
t2=time(NULL);
if(difftime(t2,t1)>1){printf(".");t1=time(NULL);}
}
/***************************************************************************/
/* wait for key pressed */
void Wait_key()
{
printf("\n");
printf(" ΙΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝ»\n");
printf(" Ί Hit any key to exit... Ί\n");
printf(" ΘΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝ1/4\n");
getch(); {/* wait until key pressed */} //kbhit
exit(0); //back to DOS
}
/***************************************************************************/
/* return smallest value */
int Min(int a,int b)
{
if(a<b) {return(a);}
return(b);
}
/***************************************************************************/
/* return greatest value */
int Max(int a,int b)
{
if(a>b) {return(a);}
return(b);
}
/***************************************************************************/
/* Print password decrypted, along with equivalent "ALT" sequence */
void Print_pwd(int pwd_len,int *Pwd,time_t time_start)
{
int i;
time_t t;
t=time(NULL);
printf("\n\n ALT sequence: ");
for(i=0;i<pwd_len;i++)
{
printf("[%d]",Pwd[i]);
if((i+1)%10==0) {printf("\n ");}
}
printf("\n\n PASSWORD: >>> ");
for(i=0;i<pwd_len;i++)
{
printf("%c",Pwd[i]);
}
printf(" <<<\n");
printf("\n%d characters [elapsed time: %3.0lfs]\n",pwd_len,difftime(t,time_start));
}
/***************************************************************************/
/* Euclid's decomposition */
void Euclid(int data_hex,int **data_bin)
{
int weight;
for(weight=0;weight<8;weight++)
{
(*data_bin)[weight]=fmod(data_hex,2);
data_hex=floor(data_hex/2);
}
}
/***************************************************************************/
/* return 0 if num is even; 1 if num is odd */
int Odd(int num)
{
if(fmod(num,2)==0) {return(0); /*num is even*/}
else {return(1); /*num is odd*/}
}
/***************************************************************************/
/* pwd is built "slice by slice", beginning with */
/* low-weight bit (weight=0) and ending with high-weight bit (weight=7) */
void Update_pwd(int pwd_len,int weight,int **Pwd_bin,int **Pwd)
{
int i;
for(i=0;i<pwd_len;i++) {(*Pwd)[i]+=(pow(2,weight)*Pwd_bin[i][weight]);}
}
/***************************************************************************/
/* Called only once */
void Fill_buffer(int fn,char **Buffer,int buf_size)
{
(*Buffer)=(unsigned char *)malloc(sizeof(char)*buf_size);
// read first 1000 characters of file
read(fn,*Buffer,buf_size);
close(fn);
}
/***************************************************************************/
/* Extract some reordered characters from encrypted file */
/* file'structure: | A B C D E F G H | I J K L M N O P Q R S .... */
/* |<--- header --->|<---- useful part ---- .... */
/* step 1: copy header (8 chars, indicates algo used to encrypt file) */
/* step 2: reordering of "useful" part (header is NOT used) */
/* (ex:block'size=4) before permutations: IJKL MNOP QRST UVWX ... */
/* after " " : LKJI PONM TSRQ XWVU ... */
/* step 3: extraction of encrypted file'name, char_0 and encrypted pwd */
/* before decryption: LKJIPONMTSRQ X WVUBAZYF */
/* after " " : filename.doc 0x00 password */
/* NB: -file'name format: 8.3 (12 chars) */
/* -char_0 (1 char): there's always a 0x00 between original file'name */
/* and password (sort of "borderline") */
/* -to recover a password of n characters, we need n chars from file */
void Extract(unsigned char *Buffer,int block_size,int pwd_len_max,
int soft_len_max,int **Header,int **Name_enc,int *char_0,
int **Pwd_enc,int **Tail)
{
const int head_size=8;
const int name_size=12;
int i,j,block_nb,pos_temp,pos_buf;
int *Temp;
//read header
for(i=0;i<head_size;i++) {(*Header)[i]=Buffer[i];}
//permute block_nb block(s)
block_nb=floor((name_size+1+soft_len_max+1)/block_size)+1;
Temp=(int *)malloc(sizeof(int)*block_nb*block_size); //pb mem
pos_temp=0;
for(i=0;i<block_nb;i++)
{
pos_buf=head_size+(i+1)*block_size-1;
for(j=pos_buf;j>(pos_buf-block_size);j--)
{
Temp[pos_temp]=Buffer[j];
pos_temp++;
}
}
//read file'name
for(i=0;i<name_size;i++) {(*Name_enc)[i]=Temp[i];}
//read char_0
*char_0=Temp[name_size];
//read pwd_len_max characters
for(i=name_size+1,j=0;i<name_size+1+pwd_len_max;i++,j++)
{(*Pwd_enc)[j]=Temp[i];}
//read soft_len_max+1 characters
for(i=name_size+1,j=0;i<name_size+1+soft_len_max+1;i++,j++)
{(*Tail)[j]=Temp[i];}
free(Temp);
}
/***************************************************************************/
/* check if [(Sum(pwd'chars)+pwd_len)AND(0000000F)]+2=block_size */
/* return 1 if pwd pass test, 0 otherwise */
int Check_block_size(int pwd_len,int block_size,int *Pwd)
{
int i,sum;
for(i=0,sum=0;i<pwd_len;i++) {sum+=Pwd[i];}
sum+=pwd_len;
sum=(sum&0x0000000F); //mask
sum+=2;
if(sum==block_size) {/*printf("CBSgood");*/ return(1);}
else {/*printf("CBSbad");*/ return(0);}
}
/***************************************************************************/
/* check if init_12=Sum(pwd'chars)+first 12 chars of pwd (+mask) */
/* (wrap if pwd'lenght<12 chars) */
/* return 1 if pwd pass test, 0 otherwise */
/* e.g: pwd=12345 */
/* init_12 = 31+32+33+34+35 + 31+32+33+34+35+31+32+33+34+35+31+32 */
/* init_12 = 360, masking with 000000FF we obtain: init_12=60 */
int Check_init_12(int pwd_len,int init_12,int *Pwd)
{
const int name_size=12;
int i,sum,pos;
for(i=0,sum=0;i<pwd_len;i++) {sum+=Pwd[i];} // Sum(pwd'chars)
for(i=0;i<name_size;i++) {pos=fmod(i,pwd_len); sum+=Pwd[pos];}
sum=(sum&0x000000FF); //mask
if(sum==init_12) {/*printf("good");*/ return(1);}
else {/*printf("no good");*/ return(0);}
}
/***************************************************************************/
/* check if init_12_pwd=Sum(pwd'chars)+first 13 chars of pwd */
/* (wrap if pwd'lenght<13 chars)+Sum(pwd'chars) */
/* return 1 if pwd pass test, 0 otherwise */
/* e.g: pwd=ABCDEFGHIJKLMNOPQRSTUVWXYZ012 sum=872 */
/* init_12_pwd = 872 + 41+42+*/
int Check_init_12_pwd(int pwd_len,int init_12_pwd,int *Pwd)
{
const int name_size=12;
int i,sum,pos;
for(i=0,sum=0;i<pwd_len;i++) {sum+=Pwd[i];} // Sum(pwd'chars)
sum*=2;
for(i=0;i<=name_size;i++) {pos=fmod(i,pwd_len); sum+=Pwd[pos];}
sum=(sum&0x000000FF); //mask
if(sum==init_12_pwd) {/*printf("good");*/ return(1);}
else {/*printf("no good");*/ return(0);}
}
/***************************************************************************/
/* Start of decrypted file always has this structure (NB: 0 means 0x00): */
/* |name.doc0000| 0 |password000000000000000000000000000000000| */
/* |<-12 chars->|<-1 char->|<--- Tail: soft_len_max+1 characters --->| */
/* check if 0s AFTER password are present */
/* return 1 if pwd pass test, 0 otherwise */
int Check_tail_0(int pwd_len,int soft_len_max,int *Pwd,int *Tail)
{
const int name_size=12;
int i,sum,pos;
for(i=0,sum=0;i<pwd_len;i++) {sum+=Pwd[i];} // Sum(pwd'chars)
for(i=0;i<name_size+1+pwd_len;i++) {pos=fmod(i,pwd_len); sum+=Pwd[pos];}
for(i=pwd_len;i<soft_len_max+1;i++)
{
pos=fmod(name_size+1+i,pwd_len);
sum+=Pwd[pos];
sum=(sum&0x000000FF); //mask
if((sum^Tail[i])!=0x00) {return(0);/*no good*/}
}
return(1); //OK
}
/***************************************************************************/
/* The 2 first bytes of an encoded file learn us software release */
/* (International or U.S. version) and algo used: */
/* International U.S.\Canada Can break? */
/* 3 Way Proprietary 00.00. 00.01. yes */
/* Multilayer Proprietary + 02.00. 02.01. yes */
/* D.E.S. none 01.01. no */
/* D.E.S + C.B.C. none 03.01. no */
/* D.E.S + C.B.C. + Blowfish none 04.01. no */
/* */
/* Return 1 if encryption can be broken, 0 otherwise */
int Can_break(char *Buffer,int *soft_len_max)
{
int byte_0,byte_1;
byte_0=Buffer[0];
byte_1=Buffer[1];
switch(byte_0)
{
case(0):{printf("\n Encryption method: 3 Way Proprietary"); break;}
case(2):{printf("\n Encryption method: Multilayer Proprietary +"); break;}
default:{printf("\n Sorry, can't break DES stuff {:-( \n");
return(0);}
}
//Benchmark: how long will you wait for password to pop up?
if(byte_1)
{
*soft_len_max=123;
printf(" (U.S. & Canada version)\n");
printf("\npwd'len: |5±±±±±±±±±±±±±±±±±±±±±±±±±±62|63±±±±±±±±±±±±±±±±±±±±112|113±±±±±123|\n");
printf("waiting: |<- 12s ->|<- 30min ->|<- 22h ->|");
}
else
{
*soft_len_max=40;
printf(" (International version)\n");
printf("\npwd'len: |5±±±±±±±±±±±±±20|21±±±±±29|30±±±±±±±40|\n");
printf("waiting: |<- 1s ->|<-150s ->|<-2h45min->|");
}
return(1);
}
/***************************************************************************/
/* Display progression of research. */
void Show_progress(int pwd_len,int tail_0_nb,int soft_len_max)
{
switch(soft_len_max)
{
case(40):
{
printf("°");
if(pwd_len==20 || pwd_len==29) {printf("|");}
break;
}
case(123):
{
if(pwd_len==62 || pwd_len==112) {printf("|");}
if((pwd_len<113)&&(Odd(pwd_len))) {printf("°");}
else
{
if(pwd_len>=113) {printf("°");}
}
break;
}
}
}
Here is the Executable Crackeiw and Source Code
Mail Casimir.