Kodowanie pliku hasłem

cx3

Witam, mój pierwszy artykuł więc proszę o wybaczenie ewentualnych błędów. Po ponad roku czasu korzystania z serwisu, postanowiłem dać coś od siebie. Chciałbym przedstawić mój algorytm kodowania i dekodowania pojedynczego pliku. Napisałbym porządny kod źródłowy aplikacji do szyfrowania wielu plików i folderów, lecz jestem pozbawiony kompilatora i nie chcę napisać wadliwej aplikacji - nie mam możliwości sprawdzenia, czy gdzieś nie popełniłem błędu. Pytanie: skąd pewność, że w takim razie poniższy kod źródłowy nie jest wadliwy? Jestem na 99% pewny, że jeśli znajdzie się błąd, to jego wyeliminowanie jest bardzo proste. Urzęduję 100km od mojego miejsca zamieszkania, komputer należy do osoby która nie zgodziła się na instalację Delphi, a we mnie pali się do podzielenia wiedzą :)

Kod przedstawiam poniżej, komentarz umieszczę na samym końcu.

Function KodujPlik(haslo,sciezka,wynik:string):byte;
Var
  tablica         : Array [1..1024] of Char
  psciezka,pwynik : TextFile;
  plik            : File;
  rozmiar         : longint;
  i,j             : longint;
  c,d             : char;
  licznik         : byte;
  s,t             : string;
Begin

  if length(haslo)=0 then
  begin
    KodujPlik:=-1;
    exit;  
  end;

{$I-}
  AssignFile(plik,sciezka);
  Reset(plik);
{$I+}
  If IOResult<>0 then
  begin
    KodujPlik:=-2;
    exit;
  end;  

  rozmiar:=GetFileSize(plik); 
  CloseFile(plik);

  AssignFile(psciezka,sciezka);
  Reset(psciezka);

  AssignFile(pwynik,wynik);
  Rewrite(pwynik); 

  Randomize;
  
  For Licznik:=1 to 1024 do
  begin
    tablica[licznik]:=char(random(255));
    write(pwynik,tablica[licznik]);
  end;

  j:=Length(haslo);
  t:='';
  write(pwynik,chr(j));
  
  For i:=j downto 1 do
  begin
    t[i]:=chr( ord(haslo[i]) xor i );
    write(pwynik,t[i]);
  end;
  
  s:=IntToStr(rozmiar);
  j:=Length(s);

  write(pwynik,chr(j));

  For i:=j downto i do
  Begin 
    t[i]:=chr(ord(s[i]) xor i);
    write(pwynik,t[i]);
  End;
  
  Licznik:=0;
  XorChar:=chr(Random(255));
  Write(pwynik,XorChar);
  
  Repeat  {*PĘTLA GŁÓWNA*}
    
    Read(psciezka,c);   
    
      if licznik=1025 then
      begin
        Licznik:=1;
        XorChar:=Random(255);
        Write(pwynik,XorChar);
      end else 
        Licznik:=Licznik+1;    
   
    d:=char( (ord(c) xor ord(tablica[licznik]) ) xor ord(XorChar));
    Write(pwynik,d);

  Until Eof(psciezka); {*KONIEC PĘTLI*}

  CloseFile(pwynik);
  CloseFile(psciezka);

  KodujPlik:=333;

End;

Jako komentarz przedstawiam listę kroków.

  • Sprawdzenie, czy hasło zostało wprowadzone. Jeśli nie, funkcja KodujPlik zwraca wartość -1

  • Sprawdzenie, czy w ogóle istnieje plik do zakodowania :) Jeśli nie... -2. Można sprawdzać za pomocą FileExists, ale nie ma to jak swój kod.

  • Sprawdzenie rozmiaru pliku do zakodowania, zapis rozmiaru do zmiennej

  • Otworzenie pliku do odczytu (PSciezka), tworzenie pliku wynikowego (PWynik)

  • Wykonanie procedury Randomize, następnie losowanie jest 1024 znaków i zapis ich do zmiennej tablicowej Tablica[1..1024]:=char. Zmienna ta jest kluczową jeśli chodzi o algorytm kodowania. Jej znaczenie omówie dalej.

  • Kodowanie hasła i jego zapis do pliku wynikowego. Na samym początku do zmiennej typu liczbowego zostaje wprowadzona liczba oznaczająca długość hasła. Liczba ta zostaje zamieniona na znak "char" - kod ASCII tego znaku oznacza jak długie jest hasło. Następuje zapis tego znaku. Teraz kodowane jest hasło. Mamy pętle For..downto. Pętla wykorzystuje zmienną, za jej pomocą i słowa kluczowego xor zostaje kodowany każdy znak hasła. Hasło dodatkowo zostaje odwrócone. Prawdą jest, że hasło za każdym razem w pliku będzie takiej samej długości i po zakodowaniu zawsze będzie takie samo. Pozostawiam to użytkownikowi :)

  • Podobnie jak z hasłem, dzieje się z rozmiarem pliku do zakodowania. Rozmiar się przyda przy dekodowaniu. Rozmiar zamieniony jest do postaci string, powstaje znak, którego kod ASCII określa długość tego stringa. Następnie rozmiar w wersji tekstowej zostaje odwrócony i kodowany (w taki sam sposób jak hasło) w pliku wynikowym. Podobnie jak hasło, rozmiar zawsze będzie taki sam.

  • Zmiennej licznik przypisane jest zero. Zmiennej XorChar losowany jest znak. XorChar przyda się nam do kodowania pliku, o tym zaraz.

<font size="3"><font color="red">Danie Główne.</span></span>

Wszystko znajduje się w pętli repeat..until. Pętla ta będzie wykonywana do momentu Eof(PSciezka) czyli End Of File. Lista kroków pętli:

  • Oczytanie znaku c:char z pliku PSciezka

  • Sprawdzenie, czy licznik wynosi 1025. Jeśli tak, przypisana jest wartość "1" zmiennej licznik, na nowo losowany jest XorChar i wtedy znowu zapisany jest do pliku.
    Jeżeli jednak licznik różny jest od 1025, zwiększa się go o jeden.

  • Następuje kodowanie odczytanego znaku "c". Wynikiem będzie d:char, powstaje on dośc łatwo. Kod ASCII zmiennej "c" xorowany jest przez kod ASCII zmiennej typu char zapisanej w zmiennej tablica na miejscu licznik. Teraz wyjaśnię (o ile to jeszcze potrzebne) do czego służy tablica, XorChar i licznik. Licznik określa który znak ma być pobrany z tablicy, XorChar służy dodatkowemu bezpieczeństwu.

  • Po wykonanej pętli następuje zamknięcie plików. Przydałoby się wyczyszczenie tablicy i wyzerowanie zmiennych.

  • Pod sam koniec funkcja zwraca wartość 333. Czemu 3? Trójka to moja ulubiona liczba.

Po co tyle kombinowania? Otóż jeśli ktoś stworzyłby plik załóżmy 1mb składający się z ciągu takich samych znaków, nie przyjemnie by się ździwił przeglądając go w notatniku. Zapewne algorytm możnaby było rozszyfrować używając plików znacznie większych, rzędu wielu mb.

≅≅≅≅≅≅≅≅≅≅

Bez sensu jest kodowac plik, tak żeby go nie odkodować. Procedurę (funkcję) zamieszczam poniżej

Function DekodujPlik(haslo,sciezka,wynik:string):byte;
// -1 zły format pliku,  -2 złe hasło
Var
  tablica                   : Array [1..1024] of char;
  psciezka,pwynik       : TextFile;
  plik                        : File;
  rozmiar,rozmiar        : longint;
  XorChar                  : char;
  i,j                          : longint;
  c,d                        : char;
  licznik                     : byte;
  s,t                         : string;
Begin
  
  AssignFile(psciezka,sciezka);
  Reset(psciezka); // Dodać założenia

  AssignFile(pwynik,wynik);
  Rewrite(pwynik);

  For i:=1 to 1024 do
    Read(psciezka,tablica[i]);

  Read(psciezka,c);
  j:=ord(c);
  
  t:='';  

  For i:=j downto 1 do
  begin
    Read(psciezka,c);
    d:=chr( ord(c) xor i );
    t[i]:=d;
  end;
  
  IF haslo<>t then
  begin
    DekodujPlik:=-1;
    exit;
  end;
 

  Read(psciezka,c);
  j:=ord(c);

  For i:=j downto 1 do
  begin
    Read(psciezka,c);
    d:=chr( ord(c) xor i );
    s[i]:=d;
  end;

  Val(s,rozmiar,i);
  if i<>0 then
  begin
    DekodujPlik:=-2;
    CloseFile(PSciezka);
    Exit;
  end; 
  
  Read(psciezka,XorChar);
  
  Licznik:=0;
  Rozmiar2:=0;

  Repeat {PĘTLA}
  
    rozmiar2:=rozmiar2+1;    

    if licznik=1025 then
    begin
      Read(psciezka,XorChar);
      Licznik:=1;
    end else
      Licznik:=Licznik+1;

    Read(psciezka,c); 
    d:=chr( (ord(c) xor ord(tablica[licznik])) xor ord(XorChar));
    Write(wynik,d);

  Until Eof(psciezka);  

  if rozmiar2<>rozmiar then :)


END;

Funkcja dekodująca jest na podstawie kodującej dlatego pomijam komentarz. Pytania: cx3@tenbit.pl

5 komentarzy

Kodowanie != szyfrowanie

Ja tylko chciałem przedstawić nie za skomplikowany algorytm pozwalający na dość bezpieczne kodowanie :) Nie pracuję w Microsoft'cie lecz samouk jestem.

Xorowania już było od cholery i nazad.
Faktycznie ciężko dodać coś poza hash, równania krzywych eliptycznymi, równania wielomianowe, fkatoryzację czy proste przekształcenia dwustronne pokroju prostych operacji arytmetycznych/logicznych.

Ostatnio miałem pomysł na wykorzystanie macierzy oraz równania elipsy(zafascynowanie krzywymi eliptycznymi nie mające z moim pomysłem większego związku ;))

Oj, ile razy trzeba bedzie pisac:

Pomoc

Artykuly o formatowaniu tekstu i o ZASADACH REDAGOWANIA artykulow w dziale Delphi.

Zapomniałem. W procedurze dekodującej powinno się sprawdzić czy rozmiar podany w pliku jest zgodny z rozmiarem rzeczywistym pliku przed zakodowaniem. Na dodatek chyba źle umieściłem arta, wrrr. Pozdro