RSA
RSA šifra bola svojho času prevratný vynález. Vytvorili ju autori Rivest, Shamir a Adleman, takže názov je vytvorený z ich mien. Prečo je taká prelomová, vysvetlím na príklade.
Substitučné šifry sú fajn, ale bežne sa veľmi nepoužívajú. Dôvod je, samozrejme, spojený s ich bezpečnosťou. Jednorazová správa, ktorú si vymenia dve osoby, ktoré sa vopred zoči-voči dohodli na šifrovacom kľúči, je zabezpečená naozaj dobre. V iných situáciách už to tak nemusí byť.
Príklad použitia
Predstavme si hypotetickú situáciu. Starosta mesta pošle svojho špióna, aby sa infiltroval k nepriateľovi. Bude od neho chcieť dostávať veľa správ v priebehu možno až niekoľkých rokov. V tomto čase sa špión nemôže vracať do svojho mesta, aby si preberal nové šifrovacie kľúče, používať dlhodobo ten istý je nebezpečné a posielať kľúče po tretej osobe tiež nebude dobrý nápad.
Riešením je asymetrické šifrovanie. Aby sme pochopili, čo je asymetrické šifrovanie, vysvetlím najprv opačný pojem. Symetrické šifrovanie je také, pri ktorom vieme zo šifrovacieho kľúča ľahko odvodiť dešifrovací. Pozrite si, napríklad, stránku Šifry dole, kde vieme ľahko z kľúča pre Vigenèrovu šifru odvodiť opačný kľúč. Takže, ak niekto vie, ako bola správa zašifrovaná, dokáže ju aj ľahko dešifrovať. Naopak asymetrické šifrovanie, ktorého najznámejším príkladom je RSA šifra, má tú vlastnosť, že aj keď každý dokáže správu zašifrovať, rozšifrovať ju dokáže len ten, kto šifru vytvoril. Dešifrovací kľúč sa nedá odvodiť z kľúča šifrovacieho.
Konkrétne, pri RSA šifre máme dva kľúče, ktoré môže poznať hocikto – verejný kľúč a spoločný kľúč, ktorý v reálnych situáciách býva až niekoľko sto-ciferné číslo. Tieto dva kľúče úplne stačia k zašifrovaniu správy. Tretí -dešifrovací kľúč sa nazýva súkromným a tento pozná iba jediná osoba.
Špión: Mám novinky.
Starosta: 19, 10602637.
Špión: huhuk dudox ibiqp tvvcj srggx.
Ako špión zašifroval svoju správu? Podľa spoločného kľúča zistil, že môže zašifrovať štvor- až päťpísmenkové správy. Takže svoju správu rozdelil na Garma,donuž,nemá,gene,rálov. Každý kúsok správy zašifroval napríklad pomocou aplikácie nižšie na tejto stránke.
Starosta použije svoj súkromný kľúč 143557, ktorý nikdy nikomu neukázal a správu rozšifruje.
Tvorba kľúčov pre RSA šifru
Z dôvodu bezpečnosti je ideálne, ak vieme pred každou poslanou správou vytvoriť nové kľúče tak, ako to urobil starosta v našom príklade. Základom sú veľké prvočísla. Čím väčšie, tým lepšie. Na ich hľadanie poslúži nasledujúca aplikácia. Stačí zadať nepárne číslo menšie ako päťdesiata tretia mocnina dvoch, čo je asi 9 biliárd (15 núl za deviatkou). Toto obmedzenie je tu z technických dôvodov. Chceme totiž získať výsledok v rozumnom čase. Aplikácia nájde najbližšie prvočíslo menšie od zadaného čísla. Zaujímavé čítanie o prvočíslach nájdete tu.
Prvočísla:
/*pomocna funkcia - najde najmensieho neparneho delitela*/
function delitel(n){
let j= Math.floor(Math.sqrt(n));
if (j%2===0){j=j-1;}
let d=1;
for(let i=3; iMath.pow(2,53)-1)||(n%2===0))
{alert("Číslo musí byť nepárne a nie viac ako 16miestne!");}
else{
let p=1;
for (let i=n; i>=1; i-=2){
if(delitel(i)===1){p=i; break;}}
const delV= document.getElementById ("delitelV");
delV.textContent+= p+", ";}
}
const del= document.getElementById ("delitel");
del.addEventListener("click",delitel1);
//funkcia rozsireny eulerov algoritmus ax=1 mod m
function euler(a0,m0){
const a= BigInt(a0);
const m= BigInt(m0);
let pom1=1n;
let pom2= -m/a;
let u=0n;
let podiel= -pom2;
let zvysok= m % a;
let delitel=a;
for(let i=0n; i=lambda){alert("Skús iný verejný kľúč.");}
else {
if(euler(e, lambda)<0n){
vysledok= euler(e,lambda)+lambda;} else{vysledok= euler(e,lambda);}
}
return vysledok;}
Do okienok dole zadajte tri prvočísla. Z prvých dvoch sa vytvorí spoločný kľúč. Tieto majú byť čo možno najväčšie. Tretie prvočíslo bude verejným kľúčom. Toto prvočíslo nemusí a ani nemá byť príliš veľké. Nezľaknite sa, ak vás program vyzve na zmenu tohto verejného kľúča. Dôvod nájdete nižšie v poznámkach.
Prvočíslo 1:
Prvočíslo 2:
Verejný kľúč:
Spoločný kľúč:
Verejný kľúč:
Súkromný kľúč:
function spolocny(){ const prv1= document.getElementById ("p1"); const p1= prv1.value; const prv2= document.getElementById ("p2"); const p2= prv2.value; const ver = document.getElementById("verejny"); const verejny= ver.value;
if(p1>=Math.pow(2,53) || p2>=Math.pow(2,53) || verejny>=Math.pow(2,53) || verejny%2===0|| delitel(verejny)!==1 || p1%2===0 || delitel(p1)!==1 || p2%2===0 || delitel(p2)!==1){alert("Prvočísla 1 a 2 a aj verejný kľúč majú byť prvočísla! Over si ich tu na stránke vyššie.");}
else
{
const spol = document.getElementById ("spolocny");
spol.textContent="Spoločný kľúč: "+BigInt(p1)*BigInt(p2);
const verejnyP= document.getElementById ("verejnyP");
verejnyP.textContent="Verejný kľúč: "+verejny;
const sukromnyP= document.getElementById("sukromnyP");
sukromnyP.textContent="Súkromný kľúč: "+sukrKluc(p1,p2,verejny);
}}
const kluce = document.getElementById ("kluce");
kluce.addEventListener("click", spolocny);
RSA šifrovanie
Z predchádzajúcej aplikácie si treba uložiť tri kľúče - dva sa zverejnia, tretí zostane utajený. Prvočísla, z ktorých vznikol spoločný kľúč, pre istotu úplne zabudneme. Nasledujúca aplikácia už priamo šifruje správu vo forme čísla alebo vo forme reťazca z písmen, ktoré program prevedie na číslo. V oboch prípadoch môžeme šifrovať iba správy menšie ako spoločný kľúč.
function pismenoNaCislo(pismeno){
switch(pismeno){
case "A": case "a": case "Á": case "á": case "ä": case "Ä": return 0;
case "b": case "B": return 1;
case "c": case "C": case "č": case "Č": return 2;
case "d": case "D": case "ď": case "Ď": return 3;
case "e": case "E": case "é": case "É": return 4;
case "f": case "F": return 5;
case "g": case "G": return 6;
case "h": case "H": return 7;
case "i": case "I": case "í": case "Í": return 8;
case "j": case "J": return 9;
case "k": case "K": return 10;
case "l": case "L": case "ĺ": case "Ĺ": case "ľ": case "Ľ": return 11;
case "m": case "M": return 12;
case "n": case "N": case "ň": case "Ň": return 13;
case "o": case "O": case "ó": case "Ó": case "ô": case "Ô": return 14;
case "p": case "P": return 15;
case "q": case "Q": return 16;
case "r": case "R": case "ŕ": case "Ŕ": case "ř": case "Ř": return 17;
case "s": case "S": case "š": case "Š": return 18;
case "t": case "T": case "ť": case "Ť": return 19;
case "u": case "U": case "ú": case "Ú": return 20;
case "v": case "V": return 21;
case "w": case "W": return 22;
case "x": case "X": return 23;
case "y": case "Y": case "ý": case "Ý": return 24;
case "z": case "Z": case "ž": case "Ž": return 25;
default : return NaN;
}}
function cisloNaPismeno(cislo){switch(cislo){
case 0: return "A";
case 1: return "B";
case 2: return "C";
case 3: return "D";
case 4: return "E";
case 5: return "F";
case 6: return "G";
case 7: return "H";
case 8: return "I";
case 9: return "J";
case 10: return "K";
case 11: return "L";
case 12: return "M";
case 13: return "N";
case 14: return "O";
case 15: return "P";
case 16: return "Q";
case 17: return "R";
case 18: return "S";
case 19: return "T";
case 20: return "U";
case 21: return "V";
case 22: return "W";
case 23: return "X";
case 24: return "Y";
case 25: return "Z";
default: return "chyba";
}}
Kľúč (verejný alebo súkromný):
Spoločný kľúč:
Výstup:
Pri tomto spoločnom kľúči možno posielať ľubovoľné -písmenkové správy. Ak je prvé písmenko zo začiatku abecedy, možno aj o jedno písmenko dlhšie.
//sifrujem vyuziva umocnovanie podla mocniny v dvojkovej sustave function sifrujem(text, kluc, spolocny) { let pole=[]; while (kluc>0n){pole.push(kluc & 1n); kluc>>=1n;} let pom= text; let sucin= 1n; for(let i=0; i= spolocnyK))){ const vystup = document.getElementById ("vystup"); const text2= BigInt(text); vystup.value= sifrujem(text2,kluc,spolocnyK);}
//ak vstup je slovo, najprv urcim, ci nie je pridlhe else { let slovo= text.trim(); let pismena= slovo.split(''); for(let i=0; i=0;i--){ if (isNaN(pismena[i])){alert("Môžeš použiť iba písmená. Žiadne iné znaky!"); break;} else {cislo+= BigInt(pismena[i])*mocnina; mocnina= mocnina*26n;}} if(cislo 0n) { pocetPismen1= pocetPismen1+1n; temp = temp / 26n; } let pocetPismen= Number(pocetPismen1);
let pismenaV= [];
pismenaV.length= pocetPismen;
let delenec= cisloV;
for(let i=0; i 0n) {
label= label+1n;
temp2 = temp2 / 26n;
}
const label1= document.getElementById ("label");
label1.textContent= Number(label)-1;
const vystup = document.getElementById ("vystup");
vystup.value= pismenaV.join('');
}
else {
alert("Neplatný vstup. Ak zadávaš číslo, musí byť menšie ako spoločný kľúč, teda "+spolocnyK+". Ak zadávaš slovo, musí byť po prevode na číslo tiež menšie ako "+spolocnyK+". Tvoje slovo je rovné "+cislo+". Skús nájsť väčšie kľúče.");}
}}
const sifruj = document.getElementById ("sifruj");
sifruj.addEventListener("click", sifrujF);
Poznámky
- Bezpečnosť RSA šifry je založená na nemožnosti nájsť v dostupnom čase prvočísla, z ktorých vznikol spoločný kľúč. Výpočtovo je to podobné ako Nájdi prvočíslo. Už 15-miestne zadania chvíľu trvajú. Ak vynásobíme dve takéto čísla, dostaneme až 30-miestne číslo. Nájsť jeho delitele netrvá dvakrát toľko, ale približne 1 000 000 000 000 000-krát toľko. Čiže, ak nájsť deliteľa 15-miestneho čísla trvá 1 sekundu, nájsť deliteľa 30-miestneho čísla by trvalo asi 31 miliárd rokov. 😱Vážne, prepočítajte si to sami, ak neveríte. Obyčajný smartfón, na ktorom tieto výpočty pravdepodobne vykonávate, ale nie je vrchol súčasnej technológie, takže 30-miestny spoločný kľúč v súčasnosti nemožno považovať za bezpečný.
- Nájdi prvočísla funguje tak, že testuje deliteľnosť daného čísla všetkými nepárnymi číslami od 3 až do odmocniny z tohto čísla. Ak žiadneho deliteľa nenájde, výsledkom je dané číslo. Ak nájde deliteľa, zmení zadané číslo na číslo o dve menšie (aby bolo stále nepárne). Toto robí, až kým nenájde prvočíslo.
- Hľadanie kľúčov je matematicky trošku komplikovanejšie, ale zato technicky rýchlejšie. Preto tu pracujem aj s väčšími číslami. Vy zadáte tri prvočísla ideálne získané v predchádzajúcom kroku. Program prvé dve vynásobí (tu môže vzniknúť viac ako 16miestne číslo) - to bude spoločný kľúč, tretie prvočíslo bude verejný kľúč. Výpočet súkromného čísla vo veľmi zjednodušenej podobe prebieha asi takto: najprv vypočítame najmenší spoločný násobok čísel p-1 a q-1, kde p a q sú prvočísla, z ktorých vznikol spoločný kľúč. Ak prvočísla boli 7 a 13, nsn(6,12) = 12. Verejný kľúč musí byť s týmto násobkom nesúdeliteľný, preto vás niekedy program vyzve na výber iného verejného kľúča. Navyše by nemal byť väčši ako tento nsn. V našom minipríklade môžeme ako verejný kľúč použiť iba 5, 7 alebo 11. Potom určíme x ako to číslo, ktoré po vynásobení verejným kľúčom dá zvyšok 1 po delení spomínaným najmenším spoločným násobkom. Ak nsn bolo 12 a verejný kľúč 5, súkromný bude tiež 5, pretože 5 ∙ 5 = 25 a to dáva zvyšok 1 po delení dvanástimi. Z tohto krátkeho vhľadu vyplývajú dve dôležité veci. Po prvé, súkromný kľúč sa nedá vypočítať, ak nevieme, z ktorých prvočísel vznikol spoločný kľúč. Po druhé súkromný a verejný kľúč sú navzájom zameniteľné, takže je na nás, ktorý zverejníme a ktorý zostane utajený. (Ak zašifrujeme správu súkromným kľúčom, verejným ju môžeme odšifrovať.)
- Pri samotnom šifrovaní používam niekoľko matematických trikov, takže výpočty sú naozaj rýchle. Program rozoznáva, či je vstup číslo alebo nie. Číslo šifruje tak, že ho umocní na verejný kľúč a nájde zvyšok výsledku po delení spoločným kľúčom. Pri samotnom umocňovaní používam podobný princíp ako v tomto príspevku na blogu. Dešifrovanie prebieha presne tak isto ako šifrovanie, ibaže vy namiesto verejného kľúča vložíte súkromný.
- Šifrovanie slova prebieha tak, že slovo je zakódované do jedného čísla v 26tkovej číselnej sústave s ciframi A=0, B=1, ... Z=25. Je to výhodnejšie ako šifrovať každé písmeno zvlášť, pretože dĺžka jednotlivo šifrovanej správy môže byť rôzne veľká. Vyplýva z toho ale jeden dôsledok, na ktorý treba myslieť. Nesmieme posielať slovo začínajúce písmenom A, pretože to sa zakóduje ako číslo typu 0105 = 105, takže to A na začiatku sa stratí. Preto špión v úvodnom príklade nerozdelil slovo generalov na gener,alov, ale na gene,ralov.