Kryptologia to dziedzina, która jest nierozłącznie kojarzona z informatyką. Jest tak nie bez powodu - m.in. to właśnie dzięki wszelakiej maści szyfrom, dbamy o bezpieczeństwo naszych danych. Zagłębianie się w tematykę kryptologii warto rozpocząć od zapoznania się z jednym z wielu szyfrów, którym może być chociażby szyfr Playfair.
Trochę historii
Szyfr Playfair został opracowany przez Charlesa Wheatstone – angielskiego wynalazcę. Szyfr ten zawdzięcza swoją nazwę baronowi Lyonowi Playfair, który stał za jego popularyzacją. Korzysta on z jednego klucza do szyfrowania i deszyfrowania wiadomości, należy więc do grupy szyfrów symetrycznych. Jest to także pierwszy z szyfrów, w którym tekst szyfrowany dzielony jest nie na pojedyncze litery (jak chociażby w szyfrze cezara), a na pary liter, zwane digrafami.
Szyfr Playfair był wykorzystywany przez brytyjską armię podczas wojny burskiej. Jest on stosunkowo prosty w użyciu, dzięki czemu nadawał się idealnie do zastosowań polowych.
Szyfr Playfair - zasada działania
Przejdźmy jednak do meritum, jakim jest zasada działania szyfru. Do rozpoczęcia działania potrzebujemy klucza oraz tekstu do szyfrowania. Za klucz przyjmijmy słowo „binary”, a naszym tekstem jawnym będzie słowo „programowanie”.
W pierwszej kolejności potrzebujemy stworzyć kwadrat szyfrowania, który jest niczym innym jak tablicą o wymiarach 5x5. W kolejnym kroku wpisujemy litery klucza w kolejne komórki tablicy, pomijając wpisane już znaki (przykładowo klucz „binarnie” zostałby zapisany jako „binare”).

Następnie wpisujemy do tablicy pozostałe, nie wpisane jeszcze litery alfabetu (pomijając literę „j”, która zmieniana jest na literę „i”, ze względu na ograniczony rozmiar tablicy).2

Mając już gotową tablicę, możemy przystąpić do szyfrowania. Pierwszy krok, który musimy wykonać, to podzielenie szyfrowanego tekstu na pary liter. W naszym przypadku, otrzymamy: pr-og-ra-mo-wa-ni-e. Ze względu na nieparzystą liczbę liter w naszym tekście, dodajemy na koniec tekstu literę „z”, otrzymując: pr-og-ra-mo-wa-ni-ez. Szyfrowanie digrafów podzielone jest na kilka przypadków:
1)Obie litery są w tej samej kolumnie – W tym przypadku, zamieniamy litery, na te znajdujące się pod nimi. Przykładowo OG, zamienia się UO. W przypadku gdy którakolwiek z liter którą mamy zamienić, znajduje się na końcu kolumny, podczas zamiany bierzemy literę znajdującą się na początku tej samej kolumny

2)Obie litery są w tym samym wierszu – Analogicznie do przypadku pierwszego, zamieniamy litery na te sąsiadujące z nimi po prawej stronie. Jeśli któraś z liter znajduje się na końcu wiersza, bierzemy pierwszą literę znajdującą się na początku wiersza. Przykładowo dwuznak RA, zostanie zamieniony na BR.

3)Pozostałe przypadki – Gdy litery nie znajdują się w tej samej kolumnie ani wierszu, należy zlokalizować obie litery w tablicy. Następnie pierwszą literę zamieniamy ze znakiem znajdującym się na przecięciu wiersza litery pierwszej z kolumną litery drugiej. Przykładowo w digrafie PR, litera „p” zostanie zamieniona na literę „t”.

Druga z liter, zostaje natomiast zastąpiona znakiem znajdującym się na przecięciu kolumny litery pierwszej, z wierszem litery drugiej. Litera „r”, z tego samego dwuznaku zostanie więc zastąpiona literą „i”. Digraf PR zostanie więc przekształcony w TI.

Przechodząc przez cały proces, słowo „programowanie” zaszyfrowane przy użyciu klucza „binary”, będzie miało postać „tiuobrgtxnanfx”.
Odszyfrowywanie wiadomości znając procedurę szyfrowania nie należy do najtrudniejszych zadań – procedura jest zwyczajnie odwracana. Jeśli obie litery są w tej samej kolumnie, zamieniamy je na litery znajdujące się nad nimi. W przypadku gdy są w tym samym wierszu czytamy litery sąsiadujące z nimi po lewej stronie. W przypadku gdy litery znajdują się w innych kolumnach i wierszach, tak jak w przypadku szyfrowania szukamy przecięć, w kolejności wiersza litery pierwszej z kolumną litery drugiej, a następnie kolumny litery pierwszej, z wierszem litery drugiej.
Szyfr Playfair – implementacje
Implementacja szyfru Playfair podzielona jest na kilka funkcji. W pierwszej kolejności należy przygotować odpowiednio klucz oraz tekst jawny. Z obu należy usunąć znaki białe i zamienić je na małe, bądź wielkie litery.
C++
void przygotowanie(string &klucz, string &tekstJawny) {
if (klucz.length() == 0) {
klucz = "binary";
}
if (tekstJawny.length() == 0) {
tekstJawny = "programowanie";
}
//Usuniecie spacji
klucz.erase(std::remove(klucz.begin(), klucz.end(), ' '), klucz.end());
tekstJawny.erase(std::remove(tekstJawny.begin(), tekstJawny.end(), ' '), tekstJawny.end());
//Zmiana wszystkich liter na male
transform(klucz.begin(), klucz.end(), klucz.begin(), ::tolower);
transform(tekstJawny.begin(), tekstJawny.end(), tekstJawny.begin(), ::tolower);
//zamiana liter j na i
replace(klucz.begin(), klucz.end(), 'j', 'i');
replace(tekstJawny.begin(), tekstJawny.end(), 'j', 'i');
//Jesli liczba liter jest nieparzysta dodajemy 'z' do tekstu jawnego
if (tekstJawny.length() % 2 != 0) {
tekstJawny += 'z';
}
}
Java
private static String prepare(String wyraz) {
//Usuniecie spacji
wyraz = wyraz.replaceAll(" ", "");
//Zmiana wszystkich liter na male
wyraz = wyraz.toLowerCase();
//zamiana liter j na i
wyraz = wyraz.replaceAll("j", "i");
return wyraz;
}
private static String przygotowanieKlucza(String wyraz) {
if (wyraz.length() == 0) {
wyraz = "binary";
}
return prepare(wyraz);
}
private static String przygotowanieTekstuJawnego(String wyraz) {
if (wyraz.length() == 0) {
wyraz = "programowanie";
}
wyraz = prepare(wyraz);
if(wyraz.length() % 2 != 0) {
wyraz = wyraz + "z";
}
return wyraz;
}
Python
def prepareWord(word):
word = str(word)
word = word.replace(" ", "")
word = word.lower()
word.replace("j", "i")
return word
def prepareKey(key):
if len(key) == 0:
key = "binary"
return prepareWord(key)
def prepareText(text):
if len(text) == 0:
key = "programowanie"
text = prepareWord(text)
if len(text) % 2 != 0:
text = text + "z"
return text
Następnie generować będziemy tablicę szyfrowania o wymiarach 5x5. Następnie wykonujemy wszystkie kroki generowania tablicy. W poniższej implementacji korzystamy z pomocniczego stringa w celu sprawdzania, czy dane litery znajdują się już w tablicy. Wykonywane jest to przy pomocy metody find().
C++
void generowanieTablicy(string klucz, char tablicaSzyfru[5][5]) {
string kontrolny = "";
string alfabet = "abcdefghiklmnopqrstuvwxyz";
int x = 0, y = 0;
size_t pozycja;
//Korzystajac z zaawansowanej petli przechodzimy przez kolejne znaki w kluczu
for (char znak : klucz) {
//Sprawdzamy czy dodany znak znajduje się już w tablicy
pozycja = kontrolny.find(znak);
//Jesli nie dodajemy do tablicy i stringa kontrolnego
if (pozycja == string::npos) {
if (y == 5) {
//Jesli tekscie jawnym znajduja sie inne znaki oprocz liter
//wielkosc tablicy zostanie przekroczona - program nie moze wykonac swojego dzialania
cout << "BLAD PODCZAS SZYFROWANIA! - Za duza ilosc znakow w tablicy" << endl;
return;
}
//Dodajemy znak do kontrolnego stringa i tablicy
kontrolny += znak;
tablicaSzyfru[x][y] = znak;
x++;
//Jesli doszlismy do konca wiersza przechodzimy do kolejnego
if (x == 5) {
x = 0;
y++;
}
}
}
for (char znak : alfabet) {
pozycja = kontrolny.find(znak);
if (pozycja == string::npos) {
if (y == 5) {
cout << "BLAD PODCZAS SZYFROWANIA! - Za duza ilosc znakow w tablicy" << endl;
return;
}
kontrolny += znak;
tablicaSzyfru[x][y] = znak;
x++;
if (x == 5) {
x = 0;
y++;
}
}
}
cout << "Tablica szyfrowania:" << endl;
printTab(tablicaSzyfru);
}
Java
private static void generowanieTablicy(String klucz, char[][] tablicaSzyfru) {
String kontrolny = "";
String alfabet = "abcdefghiklmnopqrstuvwxyz";
int x = 0, y = 0;
int pozycja;
//Korzystajac z zaawansowanej petli przechodzimy przez kolejne znaki w kluczu
for (char znak : klucz.toCharArray()) {
//Sprawdzamy czy dodany znak znajduje się już w tablicy
pozycja = kontrolny.indexOf(znak);
//Jesli nie dodajemy do tablicy i stringa kontrolnego
if (pozycja == -1) {
if (y == 5) {
//Jesli tekscie jawnym znajduja sie inne znaki oprocz liter
//wielkosc tablicy zostanie przekroczona - program nie moze wykonac swojego dzialania
System.out.println("BLAD PODCZAS SZYFROWANIA! - Za duza ilosc znakow w tablicy");
return;
}
//Dodajemy znak do kontrolnego stringa i tablicy
kontrolny += znak;
tablicaSzyfru[x][y] = znak;
x++;
//Jesli doszlismy do konca wiersza przechodzimy do kolejnego
if (x == 5) {
x = 0;
y++;
}
}
}
for (char znak : alfabet.toCharArray()) {
pozycja = kontrolny.indexOf(znak);
if (pozycja == -1) {
if (y == 5) {
System.out.println("BLAD PODCZAS SZYFROWANIA! - Za duza ilosc znakow w tablicy");
return;
}
kontrolny += znak;
tablicaSzyfru[x][y] = znak;
x++;
if (x == 5) {
x = 0;
y++;
}
}
}
System.out.println("Tablica szyfrowania:");
printTab(tablicaSzyfru);
}
Python
def generate(key, tab):
kontrolny = ""
alfabet = "abcdefghiklmnopqrstuvwxyz"
x = 0
y = 0
pozycja = 0
for znak in key: # Korzystajac z petli przechodzimy przez kolejne znaki w kluczu
pozycja = kontrolny.find(znak) # Sprawdzamy czy dodany znak znajduje się już w tablicy
if pozycja == -1: # Jesli nie dodajemy do tablicy i stringa kontrolnego
if y == 5: # Jesli tekscie jawnym znajduja sie inne znaki oprocz liter
print("BLAD PODCZAS SZYFROWANIA! - Za duza ilosc znakow w tablicy")
return # wielkosc tablicy zostanie przekroczona - program nie moze wykonac swojego dzialania
kontrolny += znak
tab[x][y] = znak
x += 1
if x == 5:
x = 0
y += 1
for znak in alfabet:
pozycja = kontrolny.find(znak)
if pozycja == -1:
if y == 5:
print("BLAD PODCZAS SZYFROWANIA! - Za duza ilosc znakow w tablicy")
return
kontrolny += znak
tab[x][y] = znak
x += 1
if x == 5:
x = 0
y += 1
print("Tablica szyfrowania:")
printTab(tab)
Po wygenerowaniu tablicy korzystamy z funkcji pomocniczej do jej wyświetlenia.
C++
void printTab(char tab[5][5]) {
cout << endl;
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
cout << tab[j][i] << " | ";
}
cout << endl;
}
cout << endl;
}
Java
private static void printTab(char[][] tablicaSzyfru) {
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
System.out.print(tablicaSzyfru[j][i] + " | ");
}
System.out.println();
}
}
Python
def printTab(tab):
print()
for x in range(5):
for y in range(5):
print(tab[x][y], end=" | ")
print()
print()
Oprócz funkcji wyświetlającej zawartość tablicy stworzona została struktura point przechowująca współrzędne punktu, która to wykorzystana zostaje w funkcji wyszukującej koordynaty danego znaku.
C++
//Struktura przechowująca pozycje znaku
struct point {
int x;
int y;
};
point* znajdzKoordynatyZnaku(char znak, char tablica[5][5]) {
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (tablica[j][i] == znak) {
point* koordynaty = new point;
koordynaty->x = j;
koordynaty->y = i;
return koordynaty;
}
}
}
return nullptr;
}
Java
private static SimpleEntry<Integer, Integer> znajdzKoordynatyZnaku(char znak, char[][] tablica) { //wykorzystujemy istniejaca juz klase SimpleEntry z biblioteki java.util.AbstractMap
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (tablica[j][i] == znak) {
SimpleEntry<Integer, Integer> koordynaty = new SimpleEntry<Integer, Integer>(j, i);
return koordynaty;
}
}
}
return null;
}
Python
class Point():
x = 0
y = 0
def __init__(self, a, b):
self.x = a
self.y = b
def findCoords(znak, tab):
for i in range(5):
for j in range(5):
if tab[j][i] == znak:
p = Point(j, i)
return p
return None
Po przygotowaniu tablicy szyfrowania, przystępujemy do właściwego szyfrowania. Każdy krok szyfrowania rozpoczynamy od znalezienia współrzędnych obu rozpatrywanych znaków. Następnie przyrównując do siebie koordynaty x i y, odpowiadające za pozycję w wierszu i kolumnie, określamy przypadek. Nowe znaki z tablicy, zostają dodane do zaszyfrowanego ciągu znaków, według standardowych zasad.
C++
string szyfrowanie(string tekstJawny, char tablicaSzyfru[5][5]) {
char pierwszyZnak, drugiZnak;
point* koordynatyPierwszego;
point* koordynatyDrugiego;
string tekstZaszyfrowany = "";
//Rozpoczynamy szyfrowanie zakladajac parzysta liczbe znakow w tekscie jawnym
for (int x = 0; x < tekstJawny.length(); x += 2) {
//Wyszukiwanie koordynatow obu znakow digrafu
koordynatyPierwszego = znajdzKoordynatyZnaku(tekstJawny.at(x), tablicaSzyfru);
koordynatyDrugiego = znajdzKoordynatyZnaku(tekstJawny.at(x + 1), tablicaSzyfru);
if (koordynatyPierwszego == nullptr || koordynatyDrugiego == nullptr) {
cout << "NIE ZNALEZIONO ZNAKU W TABLICY! - Zakonczenie pracy" << endl;
return "";
}
//Pierwszy przypadek
if (koordynatyPierwszego->x == koordynatyDrugiego->x) {
//Jesli znaki sa w tej samej kolumnie zamieniamy je na znaki znajdujace sie nizej
//Dzialanie modulo 5 jest potrzebne, aby uchronic sie od wyjscia poza zakres tablicy
//w przypadku znaku bedacego ostatnim znakiem w kolumnie
tekstZaszyfrowany += tablicaSzyfru[koordynatyPierwszego->x][(koordynatyPierwszego->y + 1) % 5];
tekstZaszyfrowany += tablicaSzyfru[koordynatyDrugiego->x][(koordynatyDrugiego->y + 1) % 5];
}
//Drugi przypadek
else if (koordynatyPierwszego->y == koordynatyDrugiego->y) {
//Jesli znaki sa w tym samym wierszu zamieniamy je na znaki znajdujace znajdujace sie po prawej
//Dzialanie modulo 5 jest potrzebne, aby uchronic sie od wyjscia poza zakres tablicy
//w przypadku znaku bedacym ostatnim znakiem w wierszu
tekstZaszyfrowany += tablicaSzyfru[(koordynatyPierwszego->x + 1) % 5][koordynatyPierwszego->y];
tekstZaszyfrowany += tablicaSzyfru[(koordynatyDrugiego->x + 1) % 5][koordynatyDrugiego->y];
}
//Pozostale przypadki
else {
//Szukamy znakow na przecieciu wiersza znaku pierwszego z kolumna drugiego oraz
//przeciecia wiersza drugiego z kolumna pierwszego
tekstZaszyfrowany += tablicaSzyfru[koordynatyDrugiego->x][koordynatyPierwszego->y];
tekstZaszyfrowany += tablicaSzyfru[koordynatyPierwszego->x][koordynatyDrugiego->y];
}
}
return tekstZaszyfrowany;
}
Java
private static String szyfrowanie(String tekstJawny, char[][] tablicaSzyfru) {
SimpleEntry<Integer, Integer> koordynatyPierwszego;
SimpleEntry<Integer, Integer> koordynatyDrugiego;
String tekstZaszyfrowany = "";
//Rozpoczynamy szyfrowanie zakladajac parzysta liczbe znakow w tekscie jawnym
for (int x = 0; x < tekstJawny.length(); x += 2) {
//Wyszukiwanie koordynatow obu znakow digrafu
koordynatyPierwszego = znajdzKoordynatyZnaku(tekstJawny.charAt(x), tablicaSzyfru);
koordynatyDrugiego = znajdzKoordynatyZnaku(tekstJawny.charAt(x + 1), tablicaSzyfru);
if (koordynatyPierwszego == null || koordynatyDrugiego == null) {
System.out.println("NIE ZNALEZIONO ZNAKU W TABLICY! - Zakonczenie pracy");
return "";
}
//Pierwszy przypadek
if (koordynatyPierwszego.getKey() == koordynatyDrugiego.getKey()) {
//Jesli znaki sa w tej samej kolumnie zamieniamy je na znaki znajdujace sie nizej
//Dzialanie modulo 5 jest potrzebne, aby uchronic sie od wyjscia poza zakres tablicy
//w przypadku znaku bedacego ostatnim znakiem w kolumnie
tekstZaszyfrowany += tablicaSzyfru[koordynatyPierwszego.getKey()][(koordynatyPierwszego.getValue() + 1) % 5];
tekstZaszyfrowany += tablicaSzyfru[koordynatyDrugiego.getKey()][(koordynatyDrugiego.getValue() + 1) % 5];
}
//Drugi przypadek
else if (koordynatyPierwszego.getValue() == koordynatyDrugiego.getValue() ) {
//Jesli znaki sa w tym samym wierszu zamieniamy je na znaki znajdujace znajdujace sie po prawej
//Dzialanie modulo 5 jest potrzebne, aby uchronic sie od wyjscia poza zakres tablicy
//w przypadku znaku bedacym ostatnim znakiem w wierszu
tekstZaszyfrowany += tablicaSzyfru[(koordynatyPierwszego.getKey() + 1) % 5][koordynatyPierwszego.getValue()];
tekstZaszyfrowany += tablicaSzyfru[(koordynatyDrugiego.getKey() + 1) % 5][koordynatyDrugiego.getValue()];
}
//Pozostale przypadki
else {
//Szukamy znakow na przecieciu wiersza znaku pierwszego z kolumna drugiego oraz
//przeciecia wiersza drugiego z kolumna pierwszego
tekstZaszyfrowany += tablicaSzyfru[koordynatyDrugiego.getKey()][koordynatyPierwszego.getValue()];
tekstZaszyfrowany += tablicaSzyfru[koordynatyPierwszego.getKey()][koordynatyDrugiego.getValue()];
}
}
return tekstZaszyfrowany;
}
Python
def szyfrowanie(text, tab):
coordsFirst = Point(0, 0)
coordsSecond = Point(0, 0)
encryptedText = ""
for x in range(0, len(text), 2): #Rozpoczynamy szyfrowanie zakladajac parzysta liczbe znakow w tekscie jawnym
coordsFirst = findCoords(text[x], tab) #Wyszukiwanie koordynatow obu znakow digrafu
coordsSecond = findCoords(text[x + 1], tab)
if coordsFirst == None or coordsSecond == None:
print("NIE ZNALEZIONO ZNAKU ", text[x], " W TABLICY! - Zakonczenie pracy")
return ""
if coordsFirst.x == coordsSecond.x: #Pierwszy przypadek
encryptedText += tab[coordsFirst.x][coordsFirst.y + 1] #Jesli znaki sa w tej samej kolumnie zamieniamy je na znaki znajdujace sie nizej
encryptedText += tab[coordsSecond.x][(coordsSecond.y + 1) % 5] #Dzialanie modulo 5 jest potrzebne, aby uchronic sie od wyjscia poza zakres tablicy
else: #Drugi przypadek; Jesli znaki sa w tym samym wierszu zamieniamy je na znaki znajdujace znajdujace sie po prawej
if coordsFirst.y == coordsSecond.y: #Dzialanie modulo 5 jest potrzebne, aby uchronic sie od wyjscia poza zakres tablicy
encryptedText += tab[(coordsFirst.x + 1) % 5][coordsFirst.y]
encryptedText += tab[(coordsSecond.x + 1) % 5][coordsSecond.y]
else: #Pozostale przypadki
encryptedText += tab[coordsSecond.x][coordsFirst.y] #Szukamy znakow na przecieciu wiersza znaku pierwszego z kolumna drugiego oraz
encryptedText += tab[coordsFirst.x][coordsSecond.y] #przeciecia wiersza drugiego z kolumna pierwszego
return encryptedText
Funkcja odszyfrowywania odwraca kolejność działań. Całość programu ma więc postać:
C++
//program wykonujacy
//szyfrowanie i deszyfrowanie Playfair
//Jan Żwirek
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
//Struktura przechowująca pozycje znaku
struct point {
int x;
int y;
};
void przygotowanie(string &klucz, string &tekstJawny);
void generowanieTablicy(string klucz, char tablicaSzyfru[5][5]);
string szyfrowanie(string tekstJawnym, char tablicaSzyfru[5][5]);
string odszyfrowywanie(string tekstZaszyfrowany, char tablicaSzyfru[5][5]);
void printTab(char tab[5][5]);
point* znajdzKoordynatyZnaku(char znak, char tablica[5][5]);
int main() {
string klucz, tekst, tekstZaszyfrowany;
char tablicaSzyfru[5][5];
cout << "Podwaj klucz i tekst jawny bez liczb oraz znakow specjalych!" << endl;
cout << "Wprowadz klucz: ";
std::getline(std::cin, klucz);
cout << "Wprowadz tekst do zaszyfrowania: ";
std::getline(std::cin, tekst);
cout << "\nTekst jawny: " << tekst << endl;
cout << "Klucz: " << klucz << endl;
przygotowanie(klucz, tekst);
generowanieTablicy(klucz, tablicaSzyfru);
tekstZaszyfrowany = szyfrowanie(tekst, tablicaSzyfru);
cout << "Tekst zaszyfrowany: " << tekstZaszyfrowany << endl;
cout << "Tekst odszyfrowany: " << odszyfrowywanie(tekstZaszyfrowany, tablicaSzyfru) << endl;
}
void przygotowanie(string &klucz, string &tekstJawny) {
if (klucz.length() == 0) {
klucz = "binary";
}
if (tekstJawny.length() == 0) {
tekstJawny = "programowanie";
}
//Usuniecie spacji
klucz.erase(std::remove(klucz.begin(), klucz.end(), ' '), klucz.end());
tekstJawny.erase(std::remove(tekstJawny.begin(), tekstJawny.end(), ' '), tekstJawny.end());
//Zmiana wszystkich liter na male
transform(klucz.begin(), klucz.end(), klucz.begin(), ::tolower);
transform(tekstJawny.begin(), tekstJawny.end(), tekstJawny.begin(), ::tolower);
//zamiana liter j na i
replace(klucz.begin(), klucz.end(), 'j', 'i');
replace(tekstJawny.begin(), tekstJawny.end(), 'j', 'i');
//Jesli liczba liter jest nieparzysta dodajemy 'z' do tekstu jawnego
if (tekstJawny.length() % 2 != 0) {
tekstJawny += 'z';
}
}
void generowanieTablicy(string klucz, char tablicaSzyfru[5][5]) {
string kontrolny = "";
string alfabet = "abcdefghiklmnopqrstuvwxyz";
int x = 0, y = 0;
size_t pozycja;
//Korzystajac z zaawansowanej petli przechodzimy przez kolejne znaki w kluczu
for (char znak : klucz) {
//Sprawdzamy czy dodany znak znajduje się już w tablicy
pozycja = kontrolny.find(znak);
//Jesli nie dodajemy do tablicy i stringa kontrolnego
if (pozycja == string::npos) {
if (y == 5) {
//Jesli tekscie jawnym znajduja sie inne znaki oprocz liter
//wielkosc tablicy zostanie przekroczona - program nie moze wykonac swojego dzialania
cout << "BLAD PODCZAS SZYFROWANIA! - Za duza ilosc znakow w tablicy" << endl;
return;
}
//Dodajemy znak do kontrolnego stringa i tablicy
kontrolny += znak;
tablicaSzyfru[x][y] = znak;
x++;
//Jesli doszlismy do konca wiersza przechodzimy do kolejnego
if (x == 5) {
x = 0;
y++;
}
}
}
for (char znak : alfabet) {
pozycja = kontrolny.find(znak);
if (pozycja == string::npos) {
if (y == 5) {
cout << "BLAD PODCZAS SZYFROWANIA! - Za duza ilosc znakow w tablicy" << endl;
return;
}
kontrolny += znak;
tablicaSzyfru[x][y] = znak;
x++;
if (x == 5) {
x = 0;
y++;
}
}
}
cout << "Tablica szyfrowania:" << endl;
printTab(tablicaSzyfru);
}
string szyfrowanie(string tekstJawny, char tablicaSzyfru[5][5]) {
char pierwszyZnak, drugiZnak;
point* koordynatyPierwszego;
point* koordynatyDrugiego;
string tekstZaszyfrowany = "";
//Rozpoczynamy szyfrowanie zakladajac parzysta liczbe znakow w tekscie jawnym
for (int x = 0; x < tekstJawny.length(); x += 2) {
//Wyszukiwanie koordynatow obu znakow digrafu
koordynatyPierwszego = znajdzKoordynatyZnaku(tekstJawny.at(x), tablicaSzyfru);
koordynatyDrugiego = znajdzKoordynatyZnaku(tekstJawny.at(x + 1), tablicaSzyfru);
if (koordynatyPierwszego == nullptr || koordynatyDrugiego == nullptr) {
cout << "NIE ZNALEZIONO ZNAKU W TABLICY! - Zakonczenie pracy" << endl;
return "";
}
//Pierwszy przypadek
if (koordynatyPierwszego->x == koordynatyDrugiego->x) {
//Jesli znaki sa w tej samej kolumnie zamieniamy je na znaki znajdujace sie nizej
//Dzialanie modulo 5 jest potrzebne, aby uchronic sie od wyjscia poza zakres tablicy
//w przypadku znaku bedacego ostatnim znakiem w kolumnie
tekstZaszyfrowany += tablicaSzyfru[koordynatyPierwszego->x][(koordynatyPierwszego->y + 1) % 5];
tekstZaszyfrowany += tablicaSzyfru[koordynatyDrugiego->x][(koordynatyDrugiego->y + 1) % 5];
}
//Drugi przypadek
else if (koordynatyPierwszego->y == koordynatyDrugiego->y) {
//Jesli znaki sa w tym samym wierszu zamieniamy je na znaki znajdujace znajdujace sie po prawej
//Dzialanie modulo 5 jest potrzebne, aby uchronic sie od wyjscia poza zakres tablicy
//w przypadku znaku bedacym ostatnim znakiem w wierszu
tekstZaszyfrowany += tablicaSzyfru[(koordynatyPierwszego->x + 1) % 5][koordynatyPierwszego->y];
tekstZaszyfrowany += tablicaSzyfru[(koordynatyDrugiego->x + 1) % 5][koordynatyDrugiego->y];
}
//Pozostale przypadki
else {
//Szukamy znakow na przecieciu wiersza znaku pierwszego z kolumna drugiego oraz
//przeciecia wiersza drugiego z kolumna pierwszego
tekstZaszyfrowany += tablicaSzyfru[koordynatyDrugiego->x][koordynatyPierwszego->y];
tekstZaszyfrowany += tablicaSzyfru[koordynatyPierwszego->x][koordynatyDrugiego->y];
}
}
return tekstZaszyfrowany;
}
string odszyfrowywanie(string tekstZaszyfrowany, char tablicaSzyfru[5][5])
{
char pierwszyZnak, drugiZnak;
point* koordynatyPierwszego;
point* koordynatyDrugiego;
string tekstJawny = "";
//Rozpoczynamy szyfrowanie zakladajac parzysta liczbe znakow w tekscie jawnym
for (int x = 0; x < tekstZaszyfrowany.length(); x += 2) {
//Wyszukiwanie koordynatow obu znakow digrafu
koordynatyPierwszego = znajdzKoordynatyZnaku(tekstZaszyfrowany.at(x), tablicaSzyfru);
koordynatyDrugiego = znajdzKoordynatyZnaku(tekstZaszyfrowany.at(x + 1), tablicaSzyfru);
if (koordynatyPierwszego == nullptr || koordynatyDrugiego == nullptr) {
cout << "NIE ZNALEZIONO ZNAKU W TABLICY! - Zakonczenie pracy" << endl;
return "";
}
//Pierwszy przypadek
if (koordynatyPierwszego->x == koordynatyDrugiego->x) {
//Jesli znaki sa w tej samej kolumnie zamieniamy je na znaki znajdujace sie wyzej
//Jesli znak znajduje sie na poczatku kolumny, bierzemy ostatni znak z tej kolumny
if (koordynatyPierwszego->y - 1 < 0) {
tekstJawny += tablicaSzyfru[koordynatyPierwszego->x][4];
}
else {
tekstJawny += tablicaSzyfru[koordynatyPierwszego->x][koordynatyPierwszego->y - 1];
}
if (koordynatyDrugiego->y - 1 < 0) {
tekstJawny += tablicaSzyfru[koordynatyDrugiego->x][4];
}
else {
tekstJawny += tablicaSzyfru[koordynatyDrugiego->x][koordynatyDrugiego->y - 1];
}
}
//Drugi przypadek
else if (koordynatyPierwszego->y == koordynatyDrugiego->y) {
//Jesli znaki sa w tym samym wierszu zamieniamy je na znaki znajdujace znajdujace sie po lewej
//Jesli znak znajduje sie na poczatku wiersza, bierzemy ostatni znak z tego wiersza
if (koordynatyPierwszego->x - 1 < 0) {
tekstJawny += tablicaSzyfru[4][koordynatyPierwszego->y];
}
else {
tekstJawny += tablicaSzyfru[koordynatyPierwszego->x - 1][koordynatyPierwszego->y];
}
if (koordynatyDrugiego->x - 1 < 0) {
tekstJawny += tablicaSzyfru[4][koordynatyDrugiego->y];
}
else {
tekstJawny += tablicaSzyfru[koordynatyDrugiego->x - 1][koordynatyDrugiego->y];
}
}
//Pozostale przypadki
else {
//Szukamy znakow na przecieciu wiersza znaku pierwszego z kolumna drugiego oraz
//przeciecia wiersza drugiego z kolumna pierwszego
tekstJawny += tablicaSzyfru[koordynatyDrugiego->x][koordynatyPierwszego->y];
tekstJawny += tablicaSzyfru[koordynatyPierwszego->x][koordynatyDrugiego->y];
}
}
return tekstJawny;
}
void printTab(char tab[5][5]) {
cout << endl;
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
cout << tab[j][i] << " | ";
}
cout << endl;
}
cout << endl;
}
point* znajdzKoordynatyZnaku(char znak, char tablica[5][5]) {
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (tablica[j][i] == znak) {
point* koordynaty = new point;
koordynaty->x = j;
koordynaty->y = i;
return koordynaty;
}
}
}
return nullptr;
}
Java
package matura;
import java.util.AbstractMap.SimpleEntry;
import java.util.Scanner;
public class Main {
private static String prepare(String wyraz) {
//Usuniecie spacji
wyraz = wyraz.replaceAll(" ", "");
//Zmiana wszystkich liter na male
wyraz = wyraz.toLowerCase();
//zamiana liter j na i
wyraz = wyraz.replaceAll("j", "i");
return wyraz;
}
private static String przygotowanieKlucza(String wyraz) {
if (wyraz.length() == 0) {
wyraz = "binary";
}
return prepare(wyraz);
}
private static String przygotowanieTekstuJawnego(String wyraz) {
if (wyraz.length() == 0) {
wyraz = "programowanie";
}
wyraz = prepare(wyraz);
if(wyraz.length() % 2 != 0) {
wyraz = wyraz + "z";
}
return wyraz;
}
private static void generowanieTablicy(String klucz, char[][] tablicaSzyfru) {
String kontrolny = "";
String alfabet = "abcdefghiklmnopqrstuvwxyz";
int x = 0, y = 0;
int pozycja;
//Korzystajac z zaawansowanej petli przechodzimy przez kolejne znaki w kluczu
for (char znak : klucz.toCharArray()) {
//Sprawdzamy czy dodany znak znajduje się już w tablicy
pozycja = kontrolny.indexOf(znak);
//Jesli nie dodajemy do tablicy i stringa kontrolnego
if (pozycja == -1) {
if (y == 5) {
//Jesli tekscie jawnym znajduja sie inne znaki oprocz liter
//wielkosc tablicy zostanie przekroczona - program nie moze wykonac swojego dzialania
System.out.println("BLAD PODCZAS SZYFROWANIA! - Za duza ilosc znakow w tablicy");
return;
}
//Dodajemy znak do kontrolnego stringa i tablicy
kontrolny += znak;
tablicaSzyfru[x][y] = znak;
x++;
//Jesli doszlismy do konca wiersza przechodzimy do kolejnego
if (x == 5) {
x = 0;
y++;
}
}
}
for (char znak : alfabet.toCharArray()) {
pozycja = kontrolny.indexOf(znak);
if (pozycja == -1) {
if (y == 5) {
System.out.println("BLAD PODCZAS SZYFROWANIA! - Za duza ilosc znakow w tablicy");
return;
}
kontrolny += znak;
tablicaSzyfru[x][y] = znak;
x++;
if (x == 5) {
x = 0;
y++;
}
}
}
System.out.println("Tablica szyfrowania:");
printTab(tablicaSzyfru);
}
private static void printTab(char[][] tablicaSzyfru) {
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
System.out.print(tablicaSzyfru[j][i] + " | ");
}
System.out.println();
}
}
private static SimpleEntry<Integer, Integer> znajdzKoordynatyZnaku(char znak, char[][] tablica) { //wykorzystujemy istniejaca juz klase SimpleEntry z biblioteki java.util.AbstractMap
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (tablica[j][i] == znak) {
SimpleEntry<Integer, Integer> koordynaty = new SimpleEntry<Integer, Integer>(j, i);
return koordynaty;
}
}
}
return null;
}
private static String szyfrowanie(String tekstJawny, char[][] tablicaSzyfru) {
SimpleEntry<Integer, Integer> koordynatyPierwszego;
SimpleEntry<Integer, Integer> koordynatyDrugiego;
String tekstZaszyfrowany = "";
//Rozpoczynamy szyfrowanie zakladajac parzysta liczbe znakow w tekscie jawnym
for (int x = 0; x < tekstJawny.length(); x += 2) {
//Wyszukiwanie koordynatow obu znakow digrafu
koordynatyPierwszego = znajdzKoordynatyZnaku(tekstJawny.charAt(x), tablicaSzyfru);
koordynatyDrugiego = znajdzKoordynatyZnaku(tekstJawny.charAt(x + 1), tablicaSzyfru);
if (koordynatyPierwszego == null || koordynatyDrugiego == null) {
System.out.println("NIE ZNALEZIONO ZNAKU W TABLICY! - Zakonczenie pracy");
return "";
}
//Pierwszy przypadek
if (koordynatyPierwszego.getKey() == koordynatyDrugiego.getKey()) {
//Jesli znaki sa w tej samej kolumnie zamieniamy je na znaki znajdujace sie nizej
//Dzialanie modulo 5 jest potrzebne, aby uchronic sie od wyjscia poza zakres tablicy
//w przypadku znaku bedacego ostatnim znakiem w kolumnie
tekstZaszyfrowany += tablicaSzyfru[koordynatyPierwszego.getKey()][(koordynatyPierwszego.getValue() + 1) % 5];
tekstZaszyfrowany += tablicaSzyfru[koordynatyDrugiego.getKey()][(koordynatyDrugiego.getValue() + 1) % 5];
}
//Drugi przypadek
else if (koordynatyPierwszego.getValue() == koordynatyDrugiego.getValue() ) {
//Jesli znaki sa w tym samym wierszu zamieniamy je na znaki znajdujace znajdujace sie po prawej
//Dzialanie modulo 5 jest potrzebne, aby uchronic sie od wyjscia poza zakres tablicy
//w przypadku znaku bedacym ostatnim znakiem w wierszu
tekstZaszyfrowany += tablicaSzyfru[(koordynatyPierwszego.getKey() + 1) % 5][koordynatyPierwszego.getValue()];
tekstZaszyfrowany += tablicaSzyfru[(koordynatyDrugiego.getKey() + 1) % 5][koordynatyDrugiego.getValue()];
}
//Pozostale przypadki
else {
//Szukamy znakow na przecieciu wiersza znaku pierwszego z kolumna drugiego oraz
//przeciecia wiersza drugiego z kolumna pierwszego
tekstZaszyfrowany += tablicaSzyfru[koordynatyDrugiego.getKey()][koordynatyPierwszego.getValue()];
tekstZaszyfrowany += tablicaSzyfru[koordynatyPierwszego.getKey()][koordynatyDrugiego.getValue()];
}
}
return tekstZaszyfrowany;
}
private static String odszyfrowywanie(String tekstZaszyfrowany, char[][] tablicaSzyfru)
{
SimpleEntry<Integer, Integer> koordynatyPierwszego;
SimpleEntry<Integer, Integer> koordynatyDrugiego;
String tekstJawny = "";
//Rozpoczynamy szyfrowanie zakladajac parzysta liczbe znakow w tekscie jawnym
for (int x = 0; x < tekstZaszyfrowany.length(); x += 2) {
//Wyszukiwanie koordynatow obu znakow digrafu
koordynatyPierwszego = znajdzKoordynatyZnaku(tekstZaszyfrowany.charAt(x), tablicaSzyfru);
koordynatyDrugiego = znajdzKoordynatyZnaku(tekstZaszyfrowany.charAt(x + 1), tablicaSzyfru);
if (koordynatyPierwszego == null || koordynatyDrugiego == null) {
System.out.println("NIE ZNALEZIONO ZNAKU W TABLICY! - Zakonczenie pracy");
return "";
}
//Pierwszy przypadek
if (koordynatyPierwszego.getKey() == koordynatyDrugiego.getKey()) {
//Jesli znaki sa w tej samej kolumnie zamieniamy je na znaki znajdujace sie wyzej
//Jesli znak znajduje sie na poczatku kolumny, bierzemy ostatni znak z tej kolumny
if (koordynatyPierwszego.getValue() - 1 < 0) {
tekstJawny += tablicaSzyfru[koordynatyPierwszego.getKey()][4];
}
else {
tekstJawny += tablicaSzyfru[koordynatyPierwszego.getKey()][koordynatyPierwszego.getValue() - 1];
}
if (koordynatyDrugiego.getValue() - 1 < 0) {
tekstJawny += tablicaSzyfru[koordynatyDrugiego.getKey()][4];
}
else {
tekstJawny += tablicaSzyfru[koordynatyDrugiego.getKey()][koordynatyDrugiego.getValue() - 1];
}
}
//Drugi przypadek
else if (koordynatyPierwszego.getValue() == koordynatyDrugiego.getValue()) {
//Jesli znaki sa w tym samym wierszu zamieniamy je na znaki znajdujace znajdujace sie po lewej
//Jesli znak znajduje sie na poczatku wiersza, bierzemy ostatni znak z tego wiersza
if (koordynatyPierwszego.getKey() - 1 < 0) {
tekstJawny += tablicaSzyfru[4][koordynatyPierwszego.getValue()];
}
else {
tekstJawny += tablicaSzyfru[koordynatyPierwszego.getKey() - 1][koordynatyPierwszego.getValue()];
}
if (koordynatyDrugiego.getKey() - 1 < 0) {
tekstJawny += tablicaSzyfru[4][koordynatyDrugiego.getValue()];
}
else {
tekstJawny += tablicaSzyfru[koordynatyDrugiego.getKey() - 1][koordynatyDrugiego.getValue()];
}
}
//Pozostale przypadki
else {
//Szukamy znakow na przecieciu wiersza znaku pierwszego z kolumna drugiego oraz
//przeciecia wiersza drugiego z kolumna pierwszego
tekstJawny += tablicaSzyfru[koordynatyDrugiego.getKey()][koordynatyPierwszego.getValue()];
tekstJawny += tablicaSzyfru[koordynatyPierwszego.getKey()][koordynatyDrugiego.getValue()];
}
}
return tekstJawny;
}
public static void main(String[] args){
String tekstJawny = "";
String klucz = "";
Scanner sc = new Scanner(System.in);
System.out.println("Program szyfrujacy metoda PlayFair.");
System.out.println("Podaj klucz (bez polskich znakow, cyfr i znakow specjalnych):");
klucz = sc.nextLine();
System.out.println("Podaj tekst do zaszyfrowania (bez polskich znakow, cyfr i znakow specjalnych):");
tekstJawny = sc.nextLine();
System.out.println("Klucz: " + klucz);
System.out.println("Tekst do szyfrowania: " + tekstJawny);
klucz = przygotowanieKlucza(klucz);
tekstJawny = przygotowanieTekstuJawnego(tekstJawny);
char[][] tab = new char[5][5];
generowanieTablicy(klucz, tab);
String tekstZaszyfrowany = szyfrowanie(tekstJawny, tab);
String tekstOdszyfrowany = odszyfrowywanie(tekstZaszyfrowany, tab);
System.out.println("Tekst zaszyfrowany: " + tekstZaszyfrowany);
System.out.println("Tekst odszyfrowany: " + tekstOdszyfrowany);
sc.close();
}
}
Python
class Point():
x = 0
y = 0
def __init__(self, a, b):
self.x = a
self.y = b
def findCoords(znak, tab):
for i in range(5):
for j in range(5):
if tab[j][i] == znak:
p = Point(j, i)
return p
return None
def prepareWord(word):
word = str(word)
word = word.replace(" ", "")
word = word.lower()
word.replace("j", "i")
return word
def prepareKey(key):
if len(key) == 0:
key = "binary"
return prepareWord(key)
def prepareText(text):
if len(text) == 0:
key = "programowanie"
text = prepareWord(text)
if len(text) % 2 != 0:
text = text + "z"
return text
def printTab(tab):
print()
for x in range(5):
for y in range(5):
print(tab[x][y], end=" | ")
print()
print()
def generate(key, tab):
kontrolny = ""
alfabet = "abcdefghiklmnopqrstuvwxyz"
x = 0
y = 0
pozycja = 0
for znak in key: # Korzystajac z petli przechodzimy przez kolejne znaki w kluczu
pozycja = kontrolny.find(znak) # Sprawdzamy czy dodany znak znajduje się już w tablicy
if pozycja == -1: # Jesli nie dodajemy do tablicy i stringa kontrolnego
if y == 5: # Jesli tekscie jawnym znajduja sie inne znaki oprocz liter
print("BLAD PODCZAS SZYFROWANIA! - Za duza ilosc znakow w tablicy")
return # wielkosc tablicy zostanie przekroczona - program nie moze wykonac swojego dzialania
kontrolny += znak
tab[x][y] = znak
x += 1
if x == 5:
x = 0
y += 1
for znak in alfabet:
pozycja = kontrolny.find(znak)
if pozycja == -1:
if y == 5:
print("BLAD PODCZAS SZYFROWANIA! - Za duza ilosc znakow w tablicy")
return
kontrolny += znak
tab[x][y] = znak
x += 1
if x == 5:
x = 0
y += 1
print("Tablica szyfrowania:")
printTab(tab)
def szyfrowanie(text, tab):
coordsFirst = Point(0, 0)
coordsSecond = Point(0, 0)
encryptedText = ""
for x in range(0, len(text), 2): #Rozpoczynamy szyfrowanie zakladajac parzysta liczbe znakow w tekscie jawnym
coordsFirst = findCoords(text[x], tab) #Wyszukiwanie koordynatow obu znakow digrafu
coordsSecond = findCoords(text[x + 1], tab)
if coordsFirst == None or coordsSecond == None:
print("NIE ZNALEZIONO ZNAKU ", text[x], " W TABLICY! - Zakonczenie pracy")
return ""
if coordsFirst.x == coordsSecond.x: #Pierwszy przypadek
encryptedText += tab[coordsFirst.x][coordsFirst.y + 1] #Jesli znaki sa w tej samej kolumnie zamieniamy je na znaki znajdujace sie nizej
encryptedText += tab[coordsSecond.x][(coordsSecond.y + 1) % 5] #Dzialanie modulo 5 jest potrzebne, aby uchronic sie od wyjscia poza zakres tablicy
else: #Drugi przypadek; Jesli znaki sa w tym samym wierszu zamieniamy je na znaki znajdujace znajdujace sie po prawej
if coordsFirst.y == coordsSecond.y: #Dzialanie modulo 5 jest potrzebne, aby uchronic sie od wyjscia poza zakres tablicy
encryptedText += tab[(coordsFirst.x + 1) % 5][coordsFirst.y]
encryptedText += tab[(coordsSecond.x + 1) % 5][coordsSecond.y]
else: #Pozostale przypadki
encryptedText += tab[coordsSecond.x][coordsFirst.y] #Szukamy znakow na przecieciu wiersza znaku pierwszego z kolumna drugiego oraz
encryptedText += tab[coordsFirst.x][coordsSecond.y] #przeciecia wiersza drugiego z kolumna pierwszego
return encryptedText
def odszyfrowanie(encrypted, tab):
first = Point(0, 0)
second = Point(0, 0)
finalText = ""
for x in range(0, len(encrypted), 2):
first = findCoords(encrypted[x], tab)
second = findCoords(encrypted[x+1], tab)
if first == None or second == None:
print("NIE ZNALEZIONO ZNAKU ", encrypted[x], " W TABLICY! - Zakonczenie pracy")
return ""
if first.x == second.x:
if first.y - 1 < 0:
finalText += tab[first.x][4]
else:
finalText += tab[first.x][first.y-1]
if second.y - 1 < 0:
finalText += tab[second.x][4]
else:
finalText += tab[second.x][second.y - 1]
else:
if first.y == second.y:
if first.x - 1 < 0:
finalText += tab[4][first.x]
else:
finalText += tab[first.x - 1][first.y]
if second.x - 1 <0:
finalText += tab[4][second.y]
else:
finalText += tab[second.x - 1][second.y]
else:
finalText += tab[second.x][first.y]
finalText += tab[first.x][second.y]
return finalText
print("Program szyfrujacy metoda Playfair")
print("Podaj klucz (bez polskich znakow, cyfr i znakow specjalnych):")
klucz = input()
print("Podaj tekst do zaszyfrowania (bez polskich znakow, cyfr i znakow specjalnych):")
tekstJawny = input()
print("Klucz " + klucz)
print("Tekst do szyfrowania " + tekstJawny)
klucz = prepareKey(klucz)
tekstJawny = prepareText(tekstJawny)
tablica = [[0 for x in range(5)] for y in range(5)]
generate(klucz, tablica)
encrypted = szyfrowanie(tekstJawny, tablica)
print("Tekst zaszyfrowany: " + encrypted)
print("Tekst odszyfrowany: " + odszyfrowanie(encrypted, tablica))
Podsumowanie
Szyfry to zagadnienie ciekawe same w sobie, lecz również przydatne w nauce do matury z informatyki. Jeśli chcecie powiększyć swoją wiedzę informatyczną i przygotować się jak najlepiej do matury, zapraszamy Was do naszej grupy Facebookowej, którą znajdziecie po kliknięciu w poniższą grafikę:

Chcę wam również pogratulować, ponieważ właśnie poznaliście zasadę działania szyfru Playfaira oraz jego implementację. Dobrnęliście także do końca tego obszernego tekstu. Do zobaczenia niedługo!


