Kryptoanalyysitehtävät

Tällä sivulla on kolme tehtäväkokonaisuutta, joissa analysoimme eri salatekstejä ja yritämme selvittää aiemmin opituilla työkaluilla:

  1. mitä salainta on käytetty

  2. mitä avainta on käytetty

  3. mikä on ollut selväkielinen teksti

Salatekstit on muodostettu selväteksteistä siten, että selvätekstiä on tarvittaessa toistettu niin pitkään, että lähtötekstiin on saatu kerättyä 10 000 merkkiä. Tällöin kaikki salatut lähtötekstit ovat yhtä pitkiä, eikä salakirjoituksen pituudesta pysty päättelemään mikä on ollut alkuperäinen kirjoitus.

Seuraavan koodisolun ajaminen tulostaa kaikki mahdolliset selvätekstit:

Inactive
from xip import lue_tiedosto_merkkijonoksi

# Funktio näyttää saatavilla olevien tekstitideostojen nimet ja indeksit
lue_tiedosto_merkkijonoksi()

Salattu teksti on siis yksi näistä. Jos funktiolle antaa indeksin, se palauttaa tekstitiedoston sisällön. Voit siis tulostaa jonkin tiedoston sisällön esimerkiksi ajamalla seuraavaa koodia:

Inactive
from xip import lue_tiedosto_merkkijonoksi

# Kun funktiolle antaa indeksin, palauttaa se kyseisen tekstisisällön
# Seuraavassa näytetään printtaamalla haettu tekstisisältö

print(lue_tiedosto_merkkijonoksi(0))

Tehtävässä käytetty salain on joko Atbash, Caesar tai Vigenère. Joudumme siis kokeilemaan eri salaimia selvittääksemme, millä salaimella teksti on salattu.

Harjoitellaan vielä analysointia selväkielisellä tekstillä. Hyvä käytäntö on katsoa heti aluksi kahta erilaista histogrammia:

  • Eniten esiintyvä merkki ensin:

Inactive
from xip import lue_tiedosto_merkkijonoksi
from xip import laske_frekvenssit
from xip import näytä_kirjainjakauma

frekvenssi_kirjaimet, frekvenssi_prosentit = laske_frekvenssit(lue_tiedosto_merkkijonoksi(0))
näytä_kirjainjakauma(frekvenssi_kirjaimet, frekvenssi_prosentit, "Salakirjoitus esiintymistiheyden mukaan", vain_aineisto=True)
  • Merkit aakkosjärjestyksessä:

Inactive
from xip import tekstin_frekvenssi_aakkosjärjestyksessä
from xip import lue_tiedosto_merkkijonoksi

tekstin_frekvenssi_aakkosjärjestyksessä(selväteksti=lue_tiedosto_merkkijonoksi(0), otsikko="Salateksti aakkosjärjestyksessä")

Ensimmäinen analysointitehtävä

Tutkitaan ensimmäistä salakirjoitusta. Ladataan salakirjoitus ja tehdään sille ensin frekvenssianalyysi.

Inactive
# Tuodaan tarvittavat kirjastot
from xip import laske_frekvenssit
from xip import näytä_kirjainjakauma
from xip import tekstin_frekvenssi_aakkosjärjestyksessä

# Tuodaan salakirjoitus
from xip import freq_testi_a
salateksti = freq_testi_a()

frekvenssi_kirjaimet, frekvenssi_prosentit = laske_frekvenssit(salateksti)
näytä_kirjainjakauma(frekvenssi_kirjaimet, frekvenssi_prosentit, "Salakirjoitus esiintymistiheyden mukaan", vain_aineisto=True)
tekstin_frekvenssi_aakkosjärjestyksessä(selväteksti=salateksti, otsikko="Salateksti aakkosjärjestyksessä")
näytä_kirjainjakauma()

Näyttää siltä, että Ö-kirjain esiintyy salakirjoituksessa useimmiten. Edellisistä osioista muistamme, että Atbash-salain korvaa suomen aakkosissa A-kirjaimen Ö-kirjaimeksi. Kokeillaan onneamme - olisiko kyseessä Atbash-salain.

Inactive
# Tuodaan tarvittavat kirjastot
from xip import laske_frekvenssit
from xip import näytä_kirjainjakauma
from xip import tekstin_frekvenssi_aakkosjärjestyksessä
from xip import atbash

# Tuodaan salakirjoitus
from xip import freq_testi_a
salateksti = freq_testi_a()

otsikko = "<Atbash>"
atbash_purettu = atbash(salateksti)

frekvenssi_kirjaimet, frekvenssi_prosentit = laske_frekvenssit(atbash_purettu)
näytä_kirjainjakauma(frekvenssi_kirjaimet, frekvenssi_prosentit, "Purettu teksti esiintymistiheyden mukaan", vain_aineisto=True)

Tulos näyttää lupaavalta ja jakauma noudattaa aika hyvin suomen kielen kirjainjakaumaa. Koska meillä on vain 12 mahdollista lähdetiedostoa, voimme tulostaa jokaisesta tiedostosta ensimmäiset 80 merkkiä ja verrata niitä purettuun informaatioon.

Inactive
# Tuodaan tarvittavat kirjastot
from xip import lue_tiedosto_merkkijonoksi
from xip import atbash

# Tuodaan salakirjoitus
from xip import freq_testi_a
salateksti = freq_testi_a()

atbash_purettu = atbash(salateksti)

# Tulostetaan jokaisen mahdollisen lähtötiedoston alku
for i in range(12):
   teksti = lue_tiedosto_merkkijonoksi(i)[:80]
   print(f"Indeksi {i}, alku: {teksti}")

print("")
# Lopuksi tulostetaan purettu teksti
print("Atbash purettu:   {}".format(atbash_purettu[:80]))

Bingo! Löysimme yhden tekstin, joka täsmää purkamaamme informaatioon. Voit vastasta analyysin perusteella seuraaviin kysymyksiin.

Edellä löysime salaimen, avaimen ja alkuperäisen tekstin. Valitse alta oikeat vaihtoehdot. Huomaa vastausyritysten rajoitettu määrä.

Salain on:

Avain on:

Alkuperäisen tekstin indeksi on:


Toinen analysointitehtävä

Tutkitaan seuraavaksi toista salakirjoitusta. Olemme saaneet selville, että henkilö X on lähettänyt henkilölle Y viestin, jonka salauksen haluamme purkaa. Katsotaan ensin miltä sen histogrammi näyttää.

Inactive
# Tuodaan tarvittavat kirjastot
from xip import laske_frekvenssit
from xip import näytä_kirjainjakauma
from xip import tekstin_frekvenssi_aakkosjärjestyksessä

# Tuodaan salakirjoitus
from xip import freq_testi_b
salateksti = freq_testi_b()

frekvenssi_kirjaimet, frekvenssi_prosentit = laske_frekvenssit(salateksti)
näytä_kirjainjakauma(frekvenssi_kirjaimet, frekvenssi_prosentit, "Salakirjoitus esiintymistiheyden mukaan", vain_aineisto=True)
tekstin_frekvenssi_aakkosjärjestyksessä(selväteksti=salateksti, otsikko="Salateksti aakkosjärjestyksessä")
näytä_kirjainjakauma()

Tarkastellaan jakaumaa hieman yksityiskohtaisemmin:

  • Tämän viestin kirjainjakauma ei näytä olevan Atbash-salaimesta, koska Ö-kirjaimella ei ole suurinta frekvenssiä.

  • Kuvaajasta, jossa frekvenssit ovat aakkosjärjestyksessä, voimme nähdä ettei kirjainjakauma ole tasainen, vaan salakirjoituksessa on puuttuvia kirjaimia.

  • Vigenère-salain tuottaa yleensä lähes kaikille kirjaimille edes muutaman esiintymän eikä se siksi vastaa tämän salakirjoituksen profiilia.

Tehdään olettama, että salakirjoitus on tuotettu Caesar-salaimella.

Meillä on kaksi vaihtoehtoa:

  1. Kokeillaan kaikki mahdolliset Caesar-salaimen avaimet ja tarkistetaan mikä niistä purkaa viestin.

  2. Hankitaan tietoa mahdollisista avaimista.

Kuinka ollakaan, vaihtoehto b) on ihan mahdollinen, koska sosiaalisesta mediasta pystymme hakemaan henkilöiden X ja Y syntymäpäivät (17. ja 11. päivä). Tämän lisäksi heidän kumppaneidensa syntymäpäivät löytyivät myös helposti sosiaalisesta mediasta (7. ja 15. päivä). Olemme saaneet rajattua mahdollista avainavaruutta valtavasti.

Inactive
# Tuodaan tarvittavat kirjastot
from xip import laske_frekvenssit
from xip import näytä_kirjainjakauma
from xip import tekstin_frekvenssi_aakkosjärjestyksessä
from xip import caesar
from xip import merkistot

# Kerrotaan että käytössä vain isot aakkoskirjaimet
isot, _ = merkistot(suomi=True)

# Tuodaan salakirjoitus
from xip import freq_testi_b
salateksti = freq_testi_b()

mahdolliset_avaimet = [7, 11, 15, 17]

for avain in mahdolliset_avaimet:
    otsikko = " | Caesar-salain, avain="+str(avain)
    caesar_purettu=caesar(salateksti, aakkosto=isot, avain=avain, purku=True)
    frekvenssi_kirjaimet, frekvenssi_prosentit = laske_frekvenssit(caesar_purettu)
    näytä_kirjainjakauma(frekvenssi_kirjaimet, frekvenssi_prosentit, otsikko, vain_aineisto=True)

näytä_kirjainjakauma()

Näistä neljästä avaimesta avain 17 tuottaa histogrammin, jossa A-kirjain on yleisin. Tehdään brute-force-testaus ja katsotaan, näyttääkö purettu teksti miltään kahdestatoista mahdollisesta lähtötekstistämme.

Inactive
# Tuodaan tarvittavat kirjastot
from xip import lue_tiedosto_merkkijonoksi
from xip import caesar
from xip import merkistot
from xip import freq_testi_b

# Kerrotaan että käytössä vain isot aakkoskirjaimet
isot, _ = merkistot(suomi=True)

# Tuodaan salakirjoitus
salateksti = freq_testi_b()

# Asetetaan avain
avain = 17

# Puretaan salateksti caesarilla avaimella 17
caesar_purettu=caesar(salateksti, aakkosto=isot, avain=avain, purku=True)

# Tulostetaan jokaisen mahdollisen lähtötiedoston alku
for i in range(12):
  teksti = lue_tiedosto_merkkijonoksi(i)[:80]
  print(f"Indeksi {i}, alku: {teksti}")

print("")
# Lopuksi tulostetaan purettu teksti
print("Casear avain={}:  {}".format(avain, caesar_purettu[:80]))

Jälleen kerran bingo! Nyt voimme vasata seuraaviin kysymyksiin.

Edellä selvitimme käytetyn salaimen ja löysimme alkuperäisen tekstin. Valitse alta oikeat vaihtoehdot. Huomaa vastausyritysten rajoitettu määrä.

Salain on:

Avain on:

Alkuperäisen tekstin indeksi on:


Kolmas analysointitehtävä

Kolmannen salakirjoituksen purkamista voivat yrittää ne, jotka haluavat kokeilla itse koodaamista. Aloitetaan analysoimalla kolmas salakirjoitus.

Inactive
# Tuodaan tarvittavat kirjastot
from xip import laske_frekvenssit
from xip import näytä_kirjainjakauma
from xip import tekstin_frekvenssi_aakkosjärjestyksessä

from xip import freq_testi_c

# Tuodaan salakirjoitus
salateksti = freq_testi_c()

frekvenssi_kirjaimet, frekvenssi_prosentit = laske_frekvenssit(salateksti)
näytä_kirjainjakauma(frekvenssi_kirjaimet, frekvenssi_prosentit, "Salakirjoitus esiintymistiheyden mukaan", vain_aineisto=True)
tekstin_frekvenssi_aakkosjärjestyksessä(selväteksti=salateksti, otsikko="Salateksti aakkosjärjestyksessä")
näytä_kirjainjakauma()

Tiedämme, että samat henkilöt X ja Y ovat tämänkin viestin takana, mutta emme tiedä kumpi on salannut viestin. Lisäksi sosiaalisen median urkitamme on tuonut tietoomme sen, että henkilöillä X ja Y on ollut keväiset juhlat, joissa on toistuneet seuraavat asiat

  • Tarjolla on ollut hyvää ruokaa, jonka MAKU on sopinut hyvin suuhun

  • Tapahtumassa on ollut teemana tarinat, jotka alkavat sanoilla ”OLIPA KERRAN”

  • Loppuillasta saunasta on kantautunut iloinen laulu LIVET ÄR HÄRLIGT

Tällainen varsinaisesti kryptologiaan liittymätön taustatutkimus on osa tiedon hankintaa, joka ei kuulu lainkaan tälle kurssille. Hyödynnämme kuitenkin kerättyä tieto niin, että jos salain on Vigenère, voimme kokeilla seuraavia avaimia:

  • MAKU

  • OLIPAKERRAN

  • LIVETÄRHÄRLIGT

Seuraava koodisolu on alustettu kaikilla tarvittavilla funktioilla ja avaimilla. Sinun täytyy itse kirjoittaa koodi, joka käy eri salaimilla läpi eri avaimet. Tämän jälkeen arvioit, mikä näistä algoritmeista ja avaimista tuottaa jonkun lähdetiedostoista.

Inactive
# Tuodaan tarvittavat kirjastot
from xip import laske_frekvenssit
from xip import näytä_kirjainjakauma
from xip import tekstin_frekvenssi_aakkosjärjestyksessä
from xip import merkistot

# Otetaan käyttöön salaimet
from xip import atbash
from xip import caesar
from xip import vigenere

from xip import freq_testi_c

# Kerrotaan että käytössä vain isot aakkoskirjaimet
isot, _ = merkistot(suomi=True)

# Tuodaan salakirjoitus
salateksti = freq_testi_c()

caesar_avaimet = [7, 11, 15, 17]
vigenere_avaimet = ['MAKU', 'OLIPAKERRAN', 'LIVETÄRHÄRLIGT']

# Esimerkki miten käytetään eri salaimia purkaessa salatekstiä

atbash_purettu = atbash(salateksti)
caesar_purettu = caesar(salateksti, aakkosto=isot, avain=3, purku=True)
vigenere_purettu=vigenere(salateksti, aakkosto=isot, avain="OLENSALASANA", purku=True)

# TODO: Tutki salateksti ja tunnista, millä salaimella ja avaimella salateksti on tuotettu.

# TODO: Tunnista, mikä teksti on alunperin kyseessä.

Analysoi salateksti ja määritä millä salaimella ja avaimella se on tuotettu. Valitse alta oikeat vaihtoehdot. Huomaa vastausyritysten rajoitettu määrä.

Salain on:

Avain on:

Alkuperäisen tekstin indeksi on:


Frekvenssianalyysin yhteenveto

Tällä opetuskerralla olemme oppineet tutkimaan kryptoanalyysilla historiallisten Atbash-, Caesar- ja Vigenère-salaimien tuottamia salakieliä.

Seuraavaksi perehdymme satunnaisuuteen ja miten se liittyy kryptografiaan.

Palautusta lähetetään...