Stránka sa načítava, prosím čakajte…
© 2005 – 2024 Roman Horváth, všetky práva vyhradené. Dnes je 23. 4. 2024.
Dátum: 8. 8. 2021, pred tromi rokmi
Ukážka vzhľadu aplikácie po spustení.
~
import knižnica.*; import static knižnica.Svet.*; import java.util.Arrays; /** * Toto šifrovanie používa tabuľku povolených znakov a heslo. Správa aj heslo * smú obsahovať len znaky, ktoré sú uvedené v tabuľke povolených znakov. * Okrem tabuľky ide o jeden z najjednoduchších spôsobov šifrovania: heslo * určuje o koľko znakov sa majú posúvať znaky v zašifrovanej správe. Prvý * znak hesla určuje posun prvého znaku správy, druhý druhého a tak ďalej. * Znaky hesla sa používajú cyklicky, to znamená, že ak má heslo napríklad * päť znakov, tak šiesty znak správy je posúvaný opäť podľa prvého znaku * hesla a tak ďalej. */ public class MojaŠifra extends GRobot { /** * Tabuľka povolených znakov správy a hesla. Pri štarte aplikácie je * zotriedená, inak by nebola použiteľná, pretože na rýchlejšie * vyhľadávanie v nej používame binárne vyhľadávanie. */ public final static char[] tabuľka = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ',', '.', ';', ':', '-', '*', '/', '+', 'a', 'á', 'ä', 'b', 'c', 'č', 'd', 'ď', 'e', 'é', 'f', 'g', 'h', 'i', 'í', 'j', 'k', 'l', 'ľ', 'ĺ', 'm', 'n', 'ň', 'o', 'ó', 'ô', 'p', 'q', 'r', 'ŕ', 's', 'š', 't', 'ť', 'u', 'ú', 'v', 'w', 'x', 'y', 'ý', 'z', 'ž', 'A', 'Á', 'Ä', 'B', 'C', 'Č', 'D', 'Ď', 'E', 'É', 'F', 'G', 'H', 'I', 'Í', 'J', 'K', 'L', 'Ľ', 'Ĺ', 'M', 'N', 'Ň', 'O', 'Ó', 'Ô', 'P', 'Q', 'R', 'Ŕ', 'S', 'Š', 'T', 'Ť', 'U', 'Ú', 'V', 'W', 'X', 'Y', 'Ý', 'Z', 'Ž', ' '}; // Atribúty na uloženie hesla, nespracovanej správy a spracovanej správy. // Ak šifrujeme, tak nespracovaná správa je nezašifrovaná správa // a spracovaná je zašifrovaná. Ak dešifrujeme, tak je to naopak. private String heslo = "heslo", nespracovaná = ""; private final StringBuffer spracovaná = new StringBuffer(); // Tlačidlá na ovládanie aplikácie: private final Tlačidlo zadajHeslo = new Tlačidlo("Zadaj heslo"); private final Tlačidlo šifruj = new Tlačidlo("Šifruj"); private final Tlačidlo dešifruj = new Tlačidlo("Dešifruj"); private MojaŠifra() { super(400, 200, "Šifrovanie"); // Úprava písma vnútornej konzoly (na spestrenie): // strop.písmo("Cambria", 12); // Výpis pôvodnej tabuľky (na účely ladenia): // vypíšRiadok(tabuľka); // Aby bola tabuľka použiteľná, musí byť zotriedená: Arrays.sort(tabuľka); // Pretože na vyhľadávanie prislúchajúceho znaku v nej používame // binárne vyhľadávanie. // Výpis zotriedenej tabuľky (na účely ladenia): // vypíšRiadok(tabuľka); // Vizuálne nastavenia prvkov a aplikácie: skry(); zadajHeslo.skoč(0, 30); šifruj.skoč(-70, -30); dešifruj.skoč(+70, -30); zbaľ(); } // Metóda slúžiaca na šifrovanie textu. private void šifruj() { // Vymažeme spracovanú správu: spracovaná.setLength(0); // Zistíme dĺžku nespracovanej správy (aby sme ju nemuseli zisťovať // pri každej iterácii cyklu for): int dĺžka = nespracovaná.length(); // Zistíme dĺžku hesla (aby sa nám ľahšie počítalo): int dĺžkaHesla = heslo.length(); // V cykle zašifrujeme každý znak správy (pričom výsledok ukladáme // do spracovanej správy). for (int i = 0; i < dĺžka; ++i) { // Najskôr prečítame znak nespracovanej správy: int znak = Arrays.binarySearch(tabuľka, nespracovaná.charAt(i)); // Pre istotu overíme, či bol nájdený v tabuľke povolených znakov: if (znak < 0) throw new RuntimeException("Neplatný znak správy."); // Overenie síce v rámci tejto aplikácie vykonávame vždy pri // zadávaní správy aj hesla (s pomocou metódy jeKorektné), // ale to overenie slúži len na rýchle informovanie // používateľa, čiže jeho účelom je zabezpečenie // používateľského komfortu. // // Na tomto mieste (pri šifrovaní a rovnako aj pri // dešifrovaní) musíme urobiť overenie v každom prípade, // pretože heslo nemusí pochádzať od používateľa. Môže // pochádzať z iného zdroja. Bez tohto overenia by táto // metóda nebola bezpečná a univerzálna. int posun = Arrays.binarySearch(tabuľka, heslo.charAt(i % dĺžkaHesla)); // Overenie toho, či je znak hesla platným znakom (čiže či je // v tabuľke povolených znakov): if (posun < 0) throw new RuntimeException("Neplatný znak hesla."); // Overovanie platnosti znakov hesla na tomto mieste je menej // efektívne, pretože po prejdení všetkých znakov hesla sú // ďalšie kontroly zbytočné… Skutočný zmysel má len prvá // kontrola. Táto kontrola by sa dala presunúť do samostatného // cyklu pred začiatkom šifrovania. // Do spracovanej správy pridáme znak nespracovanej správy // posunutý o hodnotu znaku hesla: spracovaná.append(tabuľka[((znak + posun) % tabuľka.length)]); } } // Metóda slúžiaca na dešifrovanie textu. private void dešifruj() { // (Rovnaké procesy ako pri šifrovaní.) spracovaná.setLength(0); int dĺžka = nespracovaná.length(); int dĺžkaHesla = heslo.length(); for (int i = 0; i < dĺžka; ++i) { // (Rovnaké procesy ako pri šifrovaní.) int znak = Arrays.binarySearch(tabuľka, nespracovaná.charAt(i)); if (znak < 0) throw new RuntimeException("Neplatný znak správy."); int posun = Arrays.binarySearch(tabuľka, heslo.charAt(i % dĺžkaHesla)); if (posun < 0) throw new RuntimeException("Neplatný znak hesla."); // Aj pri dešifrovaní pridáme do spracovanej správy znak // nespracovanej správy posunutý o hodnotu znaku hesla, // ale spätne: spracovaná.append(tabuľka[((tabuľka.length + znak - posun) % tabuľka.length)]); } } // Súkromná metóda slúžiaca na overenie korektnosti hesla a správy. // Na korektné fungovanie algoritmu je nevyhnutné, aby heslo aj správa // obsahovali iba znaky uvedené v tabuľke povolených znakov. private static boolean jeKorektné(String veta) { if (veta.isEmpty()) return false; for (int i = veta.length() - 1; i >= 0; --i) if (Arrays.binarySearch(tabuľka, veta.charAt(i)) < 0) return false; return true; } /** Reakcia na voľbu (stlačenie) niektorého z tlačidiel. */ @Override public void voľbaTlačidla() { // Ak bolo zvolené tlačidlo „Zadaj heslo“: if (zadajHeslo.aktivované()) { // Premenná opakuj musí byť deklarovaná pred cyklom do-while, // inak by nemohla byť použitá v podmienke cyklu: boolean opakuj; // Uloženie starého hesla do dočasnej premennej: String zmena = heslo; do { // „Reset“ premennej opakuj na false (predpokladáme, že // opakovanie nebude treba, ale ak sa niečo pokazí, premennú // nastavíme na true a cyklus sa tým zopakuje): opakuj = false; // Upravíme reťazec hesla v dočasnej premennej: zmena = upravReťazec(zmena, "Zadaj heslo", "Zmena hesla"); // Ak používateľ zadávanie nezrušil… if (null != zmena) { // … overí sa platnosť hesla. Ak je heslo vyhovujúce, // uloží sa. Ak nie, vyžiada sa opakované zadanie. if (jeKorektné(zmena)) heslo = zmena; else { chyba("Heslo obsahuje nepovolený znak."); opakuj = true; // (Poznámka: Pôvodné heslo sme vložili do // dočasnej premennej pred cyklom, takže v ďalšej // iterácii sa bude upravovať nová verzia, ktorá // nevyhovela – používateľ sa bude môcť opraviť.) } } } while (opakuj); } // Ak bolo zvolené tlačidlo „Šifruj“: else if (šifruj.aktivované()) { // Premenná opakuj musí byť deklarovaná pred cyklom do-while, // inak by nemohla byť použitá v podmienke cyklu: boolean opakuj; // Predvolíme zadanie prázdnej správy: String správa = ""; do { // „Reset“ premennej opakuj na false (predpokladáme, že // opakovanie nebude treba, ale ak sa niečo pokazí, premennú // nastavíme na true a cyklus sa tým zopakuje): opakuj = false; // Upravíme aktuálnu správu – pri prvej iterácii je prázdna, // pri každej ďalšej naposledy zadaná: správa = upravReťazec(správa, "Zadaj otvorený text", "Šifrovanie"); // Ak používateľ zadávanie nezrušil, pokračujeme ďalšími // kontrolami: if (null != správa) { // Overenie korektnosti správy (či obsahuje len povolené // znaky): if (jeKorektné(správa)) { // Do premennej nespracovaná uložíme zadanú verziu // správy… nespracovaná = správa; try { // … a pokúsime sa ju zašifrovať: šifruj(); upravReťazec(spracovaná.toString(), "", "Zašifrovaná správa"); } catch (RuntimeException e) { // V prípade vzniku akejkoľvek chyby ju vypíšeme // v dialógu, ale zadanie už neopakujeme: chyba(e.getMessage()); } } else { // Ak správa obsahovala nepovolený znak, oznámime to // používateľovi a vyžiadame opakovanie zadania: chyba("Správa obsahuje nepovolený znak."); opakuj = true; } } } while (opakuj); } // Ak bolo zvolené tlačidlo „Dešifruj“: else if (dešifruj.aktivované()) { // Premenná opakuj musí byť deklarovaná pred cyklom do-while, // inak by nemohla byť použitá v podmienke cyklu: boolean opakuj; // Predvolíme zadanie prázdnej správy: String správa = ""; do { // „Reset“ premennej opakuj na false (predpokladáme, že // opakovanie nebude treba, ale ak sa niečo pokazí, premennú // nastavíme na true a cyklus sa tým zopakuje): opakuj = false; // Upravíme aktuálnu správu – pri prvej iterácii je prázdna, // pri každej ďalšej naposledy zadaná: správa = upravReťazec(správa, "Zadaj zašifrovaný text", "Dešifrovanie"); // Ak používateľ zadávanie nezrušil, pokračujeme ďalšími // kontrolami: if (null != správa) { // Overenie korektnosti správy (či obsahuje len povolené // znaky): if (jeKorektné(správa)) { // Do premennej nespracovaná uložíme zadanú verziu // správy… nespracovaná = správa; try { // … a pokúsime sa ju dešifrovať: dešifruj(); upravReťazec(spracovaná.toString(), "", "Dešifrovaná správa"); } catch (RuntimeException e) { // V prípade vzniku akejkoľvek chyby ju vypíšeme // v dialógu, ale zadanie už neopakujeme: chyba(e.getMessage()); } } else { // Ak správa obsahovala nepovolený znak, oznámime to // používateľovi a vyžiadame opakovanie zadania: chyba("Správa obsahuje nepovolený znak."); opakuj = true; } } } while (opakuj); } } /** Hlavná metóda. */ public static void main(String[] args) { // Načítanie konfigurácie a spustenie aplikácie… použiKonfiguráciu("MojaŠifra.cfg"); new MojaŠifra(); } }
Ukážky výsledkov
Heslo: | heslo |
---|---|
Pôvodná správa: | Roman |
Zašifrovaná správa: | č,8Ť5 |
Heslo: | činčila |
---|---|
Pôvodná správa: | Babka išla večer na návštevu. |
Zašifrovaná správa: | ,ŕžTŕlŕó-Žč7 JN3nWŕlŽr7icť:.Ľ |
Tipy na testovanie a zlepšovanie
- Skúste dešifrovať správu so zlým heslom.
- Ak „odrežme“ iba jeden (posledný) znak hesla, tak sa začiatok správy dešifruje korektne – tu sa samo naznačuje slabé miesto šifrovania.
- Ak heslo úplne „pomiešame“ (alebo len pridáme znak na začiatok), výsledok bude nečitateľný.
- Tipy:
- Môžete šifrovať správu viacerými heslami – dá sa doprogramovať, aby to bolo jednoduchšie, napríklad šifrovanie vetou, pričom každé slovo by bolo samostatné heslo, ale pamätajte – čím dlhšie heslo, tým lepšie.
- Môžete pridať do tabuľky šifier viac znakov, aj keď ich nikdy nepoužijete, zmení sa tým spôsob premiešania, ale pozor, čím viac znakov pridáte, tým viac sa priblížite ku štandardu ASCII/Unicode a to tiež nie je dobré.