#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#include <string.h>
#include <setjmp.h>

#define BUFSIZE 1024
#define MD5LEN  16

jmp_buf env;
#define AD(kod, numer) if (setjmp(env) == 0)			\
{								        \
  goto skok_ad_##numer;					\
}								        \
else								    \
{								        \
  kod;								    \
}								        \
goto koniec_ad_##numer;					\
skok_ad_##numer:						\
  longjmp(env,1);						\
koniec_ad_##numer:						\
;

//wyznacz MD5 pliku
void MD5(char *filename,char *);
//szyfruj zawartosc pliku i wynik przypisz zmiennej, albo zapisz w innym pliku
void RC4(char *,char *,char *);
//szyfruj podany ciag i przypisz zmiennej wynik
//void RC4a(char *,char *,char *);
void zamien(int *,int *);

int main(int argc, char *argv[])
{   
    char source[]="ok.txt";
    char dest[]="ok2.txt";
    char tekst[BUFSIZE]="";
    char klucz[33];
    char MD5Baz[33];
    
//aby nie podawac wprost wzorcowego klucza, by nie byl latwy do odnalezienia w pliku binarnym  
    klucz[3]=50;        klucz[0]=56;    klucz[10]=50;    klucz[27]=101;    klucz[7]=51;    klucz[1]=51;    klucz[14]=100;    klucz[4]=50;    klucz[6]=97;
    klucz[20]=98;    klucz[8]=97;    klucz[2]=49;        klucz[11]=55;    klucz[28]=99;    klucz[16]=56;    klucz[12]=51;
    klucz[32]=0;    klucz[9]=102;    klucz[30]=56;    klucz[22]=97;    klucz[19]=49;    klucz[5]=49;    klucz[21]=98;    klucz[24]=48;  klucz[23]=51;
    klucz[17]=100; klucz[18]=97; klucz[13]=53; klucz[26]=55; klucz[15]=52; klucz[29]=57; klucz[25]=97; klucz[31]=100;

//szyfrujemy plikbazowy powyzszm kluczem i zapisujemy do wynik do pliku
    AD(RC4(source,dest,klucz);,0)
//wyznaczamy MD5 pliku bazowego
    AD(MD5(source,MD5Baz);,1)
//jesli MD5 pliku bazowego rozni sie od wzorca, ktos musial zeedytowac plik bazowy
    AD(if(strncmp(MD5Baz,klucz,33))
    {
      printf("Blad. Zedytowano nieedytowalny plik\nNie odszyfrujesz juz cennego pliku.\n");
      AD(RC4(dest,tekst,MD5Baz);,3)
      printf("%s\n",tekst);
      getchar();
      return 1;
    },2)
    
//odszyfruj plik i przypisz wynik do zmiennej    
    AD(RC4(dest,tekst,MD5Baz);
       AD(printf("%s\n",tekst);,5)
    ,4)
    getchar();
    return 0;
}

void zamien(int *x1,int *x2)
{
   int tmp=*x1;
   *x1=*x2;
   *x2=tmp;
}

void MD5(char *filename,char *MD5ofFile)
{
//zmodyfikowana funkcja ze strony 
//http://msdn.microsoft.com/en-us/library/aa382380%28v=VS.85%29.aspx     
     
    DWORD dwStatus = 0;
    BOOL bResult = FALSE;
    HCRYPTPROV hProv = 0;
    HCRYPTHASH hHash = 0;
    HANDLE hFile = NULL;
    BYTE rgbFile[BUFSIZE];
    DWORD cbRead = 0;
    BYTE rgbHash[MD5LEN];
    DWORD cbHash = 0;
    CHAR rgbDigits[] = "0123456789abcdef";
    //char MD5ofFile[33];

    // Copyright (c) Microsoft Corporation.  All rights reserved.
    // Logic to check usage goes here.

    AD(hFile = CreateFile(filename,
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_SEQUENTIAL_SCAN,
        NULL);

      AD(if (INVALID_HANDLE_VALUE == hFile)
      {
        dwStatus = GetLastError();
        printf("Error opening file %s\nError: %d\n", filename, 
            dwStatus); 
        return;,7)
    },6)

    // Get handle to the crypto provider
    AD(if (!CryptAcquireContext(&hProv,
        NULL,
        NULL,
        PROV_RSA_FULL,
        CRYPT_VERIFYCONTEXT))
      AD({
        dwStatus = GetLastError();
        printf("CryptAcquireContext failed: %d\n", dwStatus); 
        CloseHandle(hFile);
        return;
      },9)

      AD(if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
      {
        dwStatus = GetLastError();
        printf("CryptAcquireContext failed: %d\n", dwStatus); 
        AD(CloseHandle(hFile);,11)
        AD(CryptReleaseContext(hProv, 0);,12)
        return;
      },10),
    8)

    AD(while (bResult = ReadFile(hFile, rgbFile, BUFSIZE, 
        &cbRead, NULL))
    {
        AD(if (0 == cbRead)
        {
            break;
        },14)

        AD(if (!CryptHashData(hHash, rgbFile, cbRead, 0))
        {
            dwStatus = GetLastError();
            printf("CryptHashData failed: %d\n", dwStatus); 
            AD(CryptReleaseContext(hProv, 0);,16)
            AD(CryptDestroyHash(hHash);,17)
            AD(CloseHandle(hFile);,18)
            return;
        },15)
    },13)

    AD(if (!bResult)
    {
        dwStatus = GetLastError();
        printf("ReadFile failed: %d\n", dwStatus); 
        AD(CryptReleaseContext(hProv, 0);,20)
        AD(CryptDestroyHash(hHash);,21)
        AD(CloseHandle(hFile);,22)
        return;
    },19)

    AD(cbHash = MD5LEN;
      AD(if (CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))
      {
        AD(for (DWORD i = 0; i < cbHash; i++)
        {
            AD(MD5ofFile[2*i]=rgbDigits[rgbHash[i] >> 4];
            MD5ofFile[2*i+1]=rgbDigits[rgbHash[i] & 0xf];,26)    
        }        
        MD5ofFile[2*cbHash]=0;,25)
      }
      else
      {
        AD(dwStatus = GetLastError();,27)
        printf("CryptGetHashParam failed: %d\n", dwStatus); 
      },24)

      CryptDestroyHash(hHash);
      CryptReleaseContext(hProv, 0);
      CloseHandle(hFile);,
    23)

    //return MD5ofFile;    
}


void RC4(char *source,char *dest,char *pass)
{
     DWORD dwStatus = 0;
     BOOL bResult = FALSE;
     HANDLE hFile = NULL;
     HANDLE hFile2= NULL;
     BYTE rgbFile[BUFSIZE];
     DWORD cbRead = 0;
     DWORD bytes;
     
     char data;
     int t=0;
     int k=0;
     int S[256];
     int K[256];
     int sizePas=strlen(pass);
     int i=0,j=0;
     //wstepna inicjalizacja Skrzynki i Tablicy K
     AD(for(i=0; i<=255; i++)
     {
       AD(S[i]=i;      
       K[i]=pass[(i % sizePas)];,29)
     },28)
     //Mieszanie Skrzynki
       AD(for(i=0; i<=255; i++)
       {
         j=(j+S[i]+K[i])%256;
         AD(zamien(&S[j],&S[i]);,31)       
       },30)
       i=j=0;
     //otwarcie bazowego pliku
       AD(hFile= CreateFile(source,
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_SEQUENTIAL_SCAN,
        NULL);

       if (INVALID_HANDLE_VALUE == hFile)
       {
        dwStatus = GetLastError();
        printf("Error opening file %s\nError: %d\n", source,dwStatus); 
        return;
       },32)
     
    //otwarcie pliku do zaszyfrowania
      AD(hFile2= CreateFile(dest,
        GENERIC_WRITE,
        FILE_SHARE_WRITE,
        NULL,
        CREATE_ALWAYS,
        FILE_FLAG_SEQUENTIAL_SCAN,
        NULL);,33)
                 
      AD(while (bResult = ReadFile(hFile, rgbFile, 1, &cbRead, NULL))
      {
                 AD(if (!cbRead) break;,35)   
                 AD(i=(i+1)%256;
                 j=(j+S[i])%256;,36)
                 AD(zamien(&S[i],&S[j]);
                 t=(S[i]+S[j])%256;               
                 data=S[t]^(*rgbFile);
                 bytes=k++;,37) 
                 //jesli nie powiodlo sie utworzenie pliku, zaszyfrowany tekst zapisywany do zmiennej
                 AD(if (INVALID_HANDLE_VALUE == hFile2)
                   dest[k-1]=data;
                 else
                   WriteFile(hFile2,&data,1,&bytes,NULL);,38)
     }        
       AD(CloseHandle(hFile);,39),
     34)
     AD(CloseHandle(hFile2);,40)
}

/*  Funkcja szyfrujaca/deszyfrujaca na ciagach znakow, nie na plikach
void RC4a(char *source,char *dest,char *pass)
{
     DWORD dwStatus = 0;
     BOOL bResult = FALSE;
     HANDLE hFile = NULL;
     BYTE rgbFile[BUFSIZE];
     DWORD cbRead = 0;
     int t=0;
     int k=0;
     int S[256];
     int K[256];
     int sizePas=strlen(pass);
     int i=0,j=0;
     for(i=0; i<=255; i++)
     {
       S[i]=i;      
       K[i]=pass[(i % sizePas)];
     }
     for(i=0; i<=255; i++)
     {
       j=(j+S[i]+K[i])%256;
       zamien(&S[j],&S[i]);       
     }
     i=j=0;
     
     for(k=0;k<strlen(source);k++)
     {
       i=(i+1)%256;
       j=(j+S[i])%256;
       zamien(&S[i],&S[j]);
       t=(S[i]+S[j])%256;               
       dest[k]=S[t]^source[k];
     } 
}
*/
