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
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