Szyfrowanie Homofoniczne
Ccobras
<font size="4">1.Czym jest szyfrowanie Homofoniczne?</span>
-Szyfr homofoniczny podstawieniowy jest szyfrem polegającym na tym, że każdemu pojedynczemu znakowi tekstu jawnego zostaje przyporządkowane kilka znaków. Przyporządkowane każdej literze zestawy znaków nazywamy homofonami.
W naszym przypadku każdemu znakowi będziemy przyporządkowywać 3 kody 3-znakowe.
Dla przykładu:
Alfabet
1 A
2 B
3 C
4 D
Kody
1 'sdf' 'aaa' 'gfg'
2 'xxx' 'bvb' 'cvb'
3 'aqw' '34g' '545'
4 'hgf' '343' '545'
Każdy kod musi być unikatowy!
<font size="4">2. Delphi<font size="4"></span></span>
Jak to będzie działać?
-Sprawa jest bardzo prosta:) program będzie przeszukiwał Memo i jeśli napotka któryś ze znaków alfabetu wylosuje odpowiadający mu kod (1 z 3) z Tablicy Kody .
<font size="4">3. Zaczynamy</span>
Na wstępie należy zdać sobie sprawę z tego ile różnych znaków musimy zakodować. Przecież występują małe litery, duże, cyfry, znaki specjalne. Po podliczeniu okaże się że liczba znaków jest spora - około 100. Teraz Każdemu znakowi przyporządkowujemy 3 kody 3-cyfrowe i ze 100 robi się 300 pozycji. Trzymanie tych informacji w naszym programie byłoby uciążliwe. Skorzystamy więc z biblioteki dll i plików *.res.
Tworzymy pliki rc i res
Otwórzmy notatnik i wpiszmy w nim:
STRINGTABLE
BEGIN
1, "A"
2, "Ą"
3, "a"
4, "ą"
5, "B"
6, "b"
END
Oczywiście należy powyższy kod uzupełnić o inne znaki. W załączniku znajduję się plik w którym zawarłem 94znaki (małe litery, duże, polskie znaki, i znaki specjalne). Nazwijmy ten plik Alfabet.rc Teraz musimy plik Alfabet.rc zamienić na Alfabet res. Posłuży nam do tego aplikacja Borlanda (Borland\Delphi\Bin\brcc32.exe). Skopiujmy ten program do folderu w którym znajduję się plik rc.
W oknie konsoli (Starty->Uruchom->CMD) przejdźmy do naszego folderu i wpiszmy:
brcc32.exe Alfabet.rc
Tym sposobem pojawił się w tym folderze plik Alfabet.res
Teraz powinniśmy zająć się Listą Kodów. Musimy powtórzyć całą operację od początku, a więc otwórzmy notatnik i wpiszmy:
STRINGTABLE
BEGIN
1, "1jh"
2, "2df"
3, "3hg"
4, "4ti"
5, "5uy"
6, "6er"
7, "7gf"
8, "8df"
9, "9de"
END
Tak jak napisałem wyżej każdemu znakowi z Alfabetu odpowiadają 3 kody. Ja dla przykładu stworzyłem tu 9 RÓŻNYCH kodów, aczkolwiek powinno ich być 3*94=282 (pełna tabela kodów w załączniku). Zapiszmy ten plik jako Lista.rc. Postępując analogicznie przekształćmy go na Lista.res.
Tworzymy własną bibliotekę dll
Jak się domyślasz musimy stworzyć dwie biblioteki jedną dla alfabetu i drugą dla kodów.
Project->New->Other->Dll Wizard
Ukazało się nam okno w którym możemy zacząć pisać swoją bibliotekę. W naszym przypadku kod będzie króciutki. Przecież chodzi tylko o załadowanie pliku res.
- Dla Alfabet.res
library AlfabetDLL;
{$R Alfabet.RES}
begin
end.
Zapiszmy ten projekt pod nazwą AlfabetDLL. Biblioteki Dll mają to do siebie że nie możemy ich uruchomić. Więc nie próbuj wciskać zielonego trójkąta Run:) Ale musimy je skompilować, więc Project->Compile AlfabetDll w tym momencie w naszym folderze powinna ukazać się biblioteka AlfabetDLL.dll
- Dla Lista.res
library ListaKodowDL;
{$R Lista.RES}
begin
end.
Przeprowadźmy kompilację i tyle jeśli chodzi o tworzenie biblioteki :)
<font size="4">4.Właściwy Program<font size="4"></span></span>
Umieśćmy na formie 3 memo, oraz dwa przyciski. W pierwszym Memo będziemy wpisywać tekst, w drugim zobaczymy go w postaci zakodowanej, zaś w trzecim odkodowany. Pierwszym przyciskiem będziemy kodować tekst, drugim jak się pewnie domyślasz odkodujemy go.
Zmienne które wykorzystuje dodaj do sekcji var:
Var
Form1 : TForm1;
I, J, K, Alf, Losowana : Integer;
Tekst, TrzyZnaki : String;
Alfabet : Array[0..255] of String;
ListaKodow : Array[1..500, 1..3] of String;
Ładujemy nasze bilbioteki
Stwórzmy takie dwie procedury:
Procedure LadowanieAlfabetu;
var
DLL : THandle; //Uchwyt do biblioteki DLL
Buffer : Array[0..255] of Char; // Bufor przechowujący tekst
I : Integer; //Zmienna potrzebna do pętli
begin
DLL := LoadLibrary('AlfabetDLL.dll'); //Załaduj bibliotekę Alfabetu
Try
//Załadowanie tekstu
For I := 1 to 94 do
Begin
LoadString(DLL, i, Buffer, SizeOf(Buffer));
//Do tablicy Alfabetu wczytuje dane z biblioteki
Alfabet[i] := Buffer;
End;
Finally
FreeLibrary(DLL); //Zwalniam bibliotekę
End;
End;
Procedure LadowanieKodow;
Var
DLL : THandle; //Uchwyt do biblioteki DLL
Buffer : Array[0..255] of Char; // Bufor przechowujący tekst
I, W, Z: Integer; //Potrzebne do pętli
Begin
W:= 1; //odnosi się do kolumn, na początku =1
Z := 1; //odnosi się do wierszy, na początku =1
DLL := LoadLibrary('ListaKodowDL.dll'); //Ładuje bibliotekę Kodow
Try
//Załadowanie tekstu
For I := 1 to 282 So //bo tyle jest wierszy w bibliotece kodów
Begin
LoadString(DLL, i, Buffer, SizeOf(Buffer));
//Te 282 wiersze z biblioteki trzeba podzielić na tablicę dwuwymiarową
// 3 kolumny i 94 wiersze
ListaKodow[w][z] := Buffer;
Inc(Z);
if Z = 4 Then
Begin
Inc(W);
Z := 1;
End;
End;
Finally
FreeLibrary(DLL); //Zwalniam Bibliotekę
End;
End;
Wczytaliśmy już nasz Alfabet oraz Kody, teraz należy napisać procedury którymi zakodujemy tekst wpisany w Memo1. Zakodowany ukaże się w Memo2, a odkodowany w Memo3.
A więc, do dzieła !
Procedure Kodowanie;
Begin
Form1.Memo2.Clear; //Trzeba wyczyścić memo
For I := 0 To Form1.Memo1.Lines.Count-1 Do //Po wszystkich wierszach
Begin
For J := 1 to Length(Form1.Memo1.Lines[i]) Do // Po wszystkich elementach w wierszu
Begin
For Alf := 1 to 94 do //Po wszystkich wierszach Tablicy Alfabet
Begin
//Jeżeli konkretny element memo będzie taki sam jak kolejny element Alfabetu
if Form1.Memo1.Lines[i][j] = Alfabet[alf] Then
Begin
//to wylosuj liczbę z przedziału 1-3
Losowana := Random(3)+1; //Aby nie było 0
//przypisz że zmienna tekst jest równa to co miała do tej pory
//plus Kod odpowiadający danemu znakowi (alf) i wylosowana pozycja kodu
Tekst := Tekst + ListaKodow[Alf][Losowana];
End;
End; //koniec pętli po alfabecie
End; //koniec pętli po elementach wiersza
//Po przeanalizowaniu całego wiersza dodaje jedną linię do memo
Form1.Memo2.Lines.Add(Tekst); //dodaje do memo zmienna tekst
Tekst := ''; //czyszcze tekst dla nowej petli
End; //Koniec drugiej petli
End;
Procedure Dekodowanie;
Var Kol, Wier : Integer;
Begin
Form1.Memo3.Lines.Clear; //czyszczę memo
For I := 0 To Form1.Memo2.Lines.Count-1 Do //Po wszystkich wierszach
Begin
For J := 1 to Length(Form1.Memo2.Lines[i]) do //Po wszystkich elementach wiersza
Begin
// Ładuje każdy wiersz po 3 znaki (bo kod jest 3-znakowy)
TrzyZnaki := TrzyZnaki + Form1.Memo2.Lines[i][j];
//Jeżeli wczytałem 3 znaki (k = zero na początku)
if J = K+3 Then
Begin
For Kol := 1 To 94 Do //Po wszystkich wierszach kodów
Begin
For Wier := 1 To 3 Do //Po wszystkich elementach każdego wiersza kodów
Begin
//Jeżeli wczytane do tej pory trzyznaki pasują do któregoś z kodów...
if TrzyZnaki = ListaKodow[Kol][Wier] Then
Begin
//...To do zmiennej tekst dopisuje konkretny znak z alfabetu
Tekst := Tekst + Alfabet[Kol];
End;
End;
End;
Inc(K, 3); //Zwiększ k o 3 żeby sprawdzić kolejne 3 znaki w tym wierszu
TrzyZnaki := ''; //Wyczyść trzy znaki by móc wczytać nowe, to co wyżej
End;
//Jeżeli k będzie równe długości wiesza wówczas kończę operację dla tego wiersza
if K = Length(Form1.Memo2.Lines[i]) Then
Begin
K := 0; //Ustawiam z powrotem k na zero
End;
End; //Koniec pętli po elementach wiersza
Form1.Memo3.Lines.Add(tekst); //dodaje do memo zmienna tekst
Tekst := ''; //czyszcze tekst dla nowej petli
End; //Koniec pętli po ilości wierszy
End;
To już prawie koniec, teraz tylko wpiszmy W Buttonie1 (który będzie kodował)
Procedure TForm1.Button1Click(Sender: TObject);
Begin
LadowanieAlfabetu;
LadowanieKodow;
Kodowanie;
End;
Oraz dla Buttona2:
Procedure TForm1.Button2Click(Sender: TObject);
Begin
Dekodowanie;
End;
To już naprawdę koniec. Zdaję sobie sprawę że z formatowaniem tego tekstu szału nie ma :) Ale jest to pierwszy mój artykuł więc proszę o wyrozumiałość.
Podsumujmy
Program wczytuje sobie znaki (małe litery,duże,polskie znaki,specjalne,cyfry) do tablicy -94kolumn i 1 wiersz, oraz tworzy tablice również o 94 wierszach (każdy wiersz kodu odpowiada jednemu znakowi) i 3 kolumnach ponieważ dla danego znaku mogą być 3 różne kody. Następnie sprawdza tekst wpisany w Memo1 porównując go z tablicą znaków. Jeśli wpisany znak odpowiada w tablicy np numerowi 44 wówczas z tablicy kodów losuje hasło [44][1] [44][2] lub [44][3]. Dekodowanie sprawdza czy kod wpisany występuje w tablicy kodów. Gdy znajduje się np na pozycji [44][3] wówczas wprowadza odkodowany znak z alfabetu który znajduje się na pozycji 44.
<font size="3">Autor: Tomasz Bartnik</span><right></right>
Aplikacja:
Szyfrow_Homofoniczne.rar
Jak chcesz to popraw
Miałem mało czasu, zaraz mieliśmy z rodzinką jechać do Parku Miniatur :)
Patryk: wcięcie na poziomie jednej spacji? Nie sądzę ;)
Szkoda, że autor nie napisał tego tydzień temu.
Jakiś użytkownik czegoś takiego szukał :-)
Poprawiłem formatowanie kodu, teraz jest czytelny
alfabety można łatwo zdefiniować wewnątrz programu - tablica tablic stringów inicjowana wartościami inline - od razu w deklaracji.
opisana metoda jest fajniejsza od zwykłego szyfru podstawieniowego i tylko minimalnie bardziej skomplikowana, ale przy odpowiednio długim tekście tak samo narażona na złamanie przez analizę statystyczną. żeby była w miarę skuteczna, tekst nie może być długi, alfabet z podstawieniami długi (kilkadziesiąt alternatyw dla każdej litery), ilość podstawień dla każdej litery powinna być inna (najwięcej dla najczęściej używanych liter - to powinno mocno utrudnić analizę statystyczną), a długość "liter" alfabetu podstawionego powinna być zmienna (ale oczywiście jednoznaczna).
do szybkiego odszyfrowania przydałaby się tablica haszująca.
co do samego srtykułu - fatalnie formatujesz kod. po każdym begin, type, var, try itp powinno być wcięcie bloku kodu.