Lohkosalain ECB-moodissa

Lohkosalain toimii siis siten, että alkuperäinen selväkielinen informaatio \(P\) lohkotaan tietyn kokoisiksi lohkoiksi \(P_1, P_2, \cdots, P_n\) . AES-salaimen lohkon koko on 128 bittiä. Avaimen pituus voi AES-standardin mukaisesti olla joko 128, 192 tai 256 bittiä. Lohkon koko ja avaimen koko kannattaa siis mieltää toisistaan erillisinä asioina.


Yksinkertaistettu esimerkki koodikirjasta

Alla esitetään yksinkertaisten kuvien avulla, miten lohkosalain toimii koodikirja-moodissa (engl. electronic code-book) eli ECB-moodissa.

  • Enkoodattava tai dekoodattava data jaetaan lohkoihin.

  • Enkoodauksessa selväkieliset lohkot \(P_1, P_2, P_3\) prosessoidaan erikseen.

  • Tällöin salaimelle annetaan ensin lohko \(P_1\) ja avain \(K\).

  • Näillä sisäänmenon arvoilla salain laskee ensimmäisen salatekstin \(C_1\).

  • Operaatio toistetaan kaikille lohkoille, ja lopuksi meillä on salateksti joka on muodostettu kolmesta lohkosta \(C_1C_2C_3\).

Käytetään 8-bittistä lohkosalainta ECB-moodissa siten, että selväkielinen viesti on \(P\) = KAHVI. Tällöin lohkomme viestin \(P_1\) = K , \(P_2\) = A jne. ensimmäisen kuvan esittämällä tavalla.

../_images/l5_ecb_mode.png

Saamme enkoodauksessa muodostettua salatekstin \(C_1C_2C_3C_4C_5\) .

../_images/l5_ecb_mode_kahvi.png

ECB-moodissa dekoodaus, eli purku, tapahtuu myös lohkoittain. Tästä ei ole erillistä kuvaa, koska tilanne on niin yksinkertainen. Selväteksti ja salateksti vain vaihtavat paikkaa kuvien osoittamissa tilanteissa.


Vastaa edellisen tekstin avulla seuraaviin väittämiin.

Valitse oikea vaihtoehto.

Valitse oikea vaihtoehto.



Yksinkertainen esimerkki AES-koodikirjasta

Ennen kuin käytämme salainta datalla jossa on yli 128 bittiä ja joka pitää jakaa lohkoihin. Käytetään seuraavaksi salainta yhteen lohkoon mahtuvalla viestillä ”KAHVI”. Itse asiassa viesti ”KAHVI” ei edes täytä lohkoa, joten viestin perään laitetaan merkkejä, jotka tunnistetaan myöhemmin täytemerkeiksi. Tätä datan täydentämistä lohkon kokoiseksi kutsutaan päddäykseksi.

Seuraavaksi käytämme oikeaa AES-salainta yllä kuvatussa ECB-moodissa. ECB-moodissa yhden lyhyen viestin salaaminen toimii hyvin.

Ennen kuin alat perehtyä koodiin, tutustu alla olevaan videoon.

Esimerkeissä salaimet on luotu Pythonin cryptography -kirjastolla. Kirjaston käyttö edellyttää sen toiminnan läpikotaista tuntemista. Siksi kirjastossa olevien funktioiden nimessä esiintyy määre hazmat eli vaarallinen materiaali. Tällä korostetaan sitä, että näiden kirjastofunktioiden käytön kanssa pitää olla erityisen huolellinen.

Tällä kurssilla emme suorita kaikkia tarvittavia tarkistuksia annetulle datalle, vaan käytämme kirjastoa varsin huolettomasti. Esimerkiksi datan esikäsittely ja lohkominen tehdään tavalla, joka ei ole kryptografisesti turvallista. Samoin jätämme huomioimatta kaikki kirjaston antamat virheilmoitukset.

Esimerkeillä demonstroidaan miten oikeaa kirjastoa voi käyttää, mutta tämä ei ole riittävä opetus kryptografisesti turvallisten ratkaisujen tuottamiseksi!

Otamme käyttöön salaimeen liittyvät kirjastot ja kerromme ympäristölle, että lohkosalaimessamme on sisäisesti 128-bitin lohkot.

Inactive
# Kryptografia kirjaston sivut <url> https://cryptography.io/en/latest/hazmat/primitives/symmetric-encryption/ </url>

# Otetaan käyttöön salaimet, salain algoritmit ja salaimien käyttömoodit
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

# Otetaan käyttöön lohkon täydennys, eli päddäys.
from cryptography.hazmat.primitives import padding

#Asetetaan päddäykselle  koko, joka vastaa AES lohkon kokoa eli 128-bittiä.
lohko_bitteinä = 128
lohko_tavuina = lohko_bitteinä//8

# Luodaan päddäyksen tuottaja sekä päddäyksen poistaja
täydennä_päddäys = padding.PKCS7(lohko_bitteinä).padder()
poista_päddäys = padding.PKCS7(lohko_bitteinä).unpadder()

print("Kirjastot otettu käyttöön.")

Nämä toiminteet tuodaan tulevissa koodisoluissa osittain kirjastojen kautta. Tässä selitys mitä juuri teimme:

  • Ensimmäiseksi tuomme käyttöön Cipher-salaimen sekä sen käyttämät algoritmit algorithms ja näiden eri käyttömoodit modes.

  • Seuraavaksi otetaan käyttöön päddäys tuomalla kirjastosta funktio padding.

  • Tämän jälkeen määrittelemme, että salaimemme toimii 128-bittisillä lohkoilla

  • Lopuksi luodaan olio, joka päddää ja toinen olio, joka poistaa päddäyksen

Seuraavaksi teemme 128-bittisen avaimen etukäteen annetusta suuresta luvusta. Luvussa on 2048 bittiä eli sen koko on 256 x 8 bittiä.

AES-lohkosalain tukee muitakin avaimen pituuksia (192 ja 256 bittiä). Voit halutessasi myöhemmin kokeilla myös niiden toimintaa.

Inactive
# Käytetään kaikissa esimerkeissä lähtökohtana suurta 2048 bittistä lukua
suuri_luku = b"S\xef8\x8e\xc8\xddff\xf4\x81\xc7 '2\x97\x88\x86\t3\x12\xfbTI5FQ\x05$P\xe85o\\a\xae\x80i=U\x16\t3\xc0i\xbd\xee\xcd\xc0\\\xf6\x13\x0f\xe8jK\x0e\xd9\xf8\xab\xbc\r!0d?\nv\xad\x06\x83\x01,\x83\xf9%\xa8n4\x12\xb3gU\x12\xda\xecw!\xf2O\xb5\r\x1e\xdd\xf0\xa2H5\xe9\xf2\x81\xd4B\x91\xf7r\xfaI!d\xf7\xfa\xafW\xce\xb2\x00x]\xb2[\xf5@:\x07\x9d\x9db\xca\xa8?Ue3G\xe1YVh\x80\x051g\x00\x07hQ\xc4\xf3K\x1b\x0f\\\x08\xfe\x19&6\xb2\x14\xcb\x90\xfd\xfdq+\xd6X\xa5\xc6Q\x84`U\x13\xee#Y\xb2\xdf8\x7fJ8l\x8bV\x89>\xe9\xc7\x83/\xdf\xf7(\x8b\xc0\xb3\xf8\xe11\x04\xcb\x99\x96[\xbdN\x8d\x8d-\xaa\x03\x90*m\xc3\xa1\x08\x91\x17\xd96^9#iX\xfc\xef \xdd\xd1\xcd\xff\xedY\x98\xbaA\xf2g\xbf\xb7q\xb4^\xa5\xc8\xd4\xcb\xd9\x0eZb\xf8"

# Otetaan käyttöön suuren luvun 16 ensimmäistä tavua, eli 128-bittiä.
avain = suuri_luku[:16]
print("Salainen avain luotu tavumuodossa ja se on:",avain)
print("Avain heksana: ", avain.hex())

Seuraavaksi kokeillaan, miten päddäys toimii kun selväkielenä on lyhyt teksti ”KAHVI”.

Päddäys pitää tehdä oikein. Väärin suoritettu päddäys aiheuttaa ongelmia ja mahdollisesti voi avata oven sivukanavahyökkäyksille. Käytämme padding-funktiota, joka toimii seuraavasti:

  • Jos lohkon täyttämiseen tarvitaan yksi tavu, päddäykseen käytetty tavu on 0x01.

  • Jos lohkon täyttämiseen tarvitaan kaksi tavua, päddäys on 0x0202.

  • Näin päddäys toimii aina korkeintaan 15 tavuun asti, jolloin päddäys olisi 0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F.

  • Jos pädderille annetaan tyhjä tai 16 tavulla jaollinen luku, päyddäys tapahtuu arvolla 0x10.

Alla olevissa koodeissa ei enää toisteta samoja kommentteja kuin aikaisemmissa koodikentissä.

Inactive
from cryptography.hazmat.primitives import padding
lohko_bitteinä = 128
lohko_tavuina = lohko_bitteinä//8
täydennä_päddäys = padding.PKCS7(lohko_bitteinä).padder()

# Luodaan lyhyt informaatio jolla kokeillaan päddäystä
selväkieli = "KAHVI"

# Muutetaan selväkieli tavumuotoon `bytes()`, tämä data tulkitaan vain bitteinä ja tavuina.
selväkieli_tavuina = bytes(selväkieli, 'UTF-8')

# Pädätään viesti:
# Pädderille sanotaan aina operaatioiden lopuksi .finalize()
pädätty_selväkieli=täydennä_päddäys.update(selväkieli_tavuina) + täydennä_päddäys.finalize()

# Näytetään data.
print("Selväkieli         :  ", selväkieli)
print("Pädätty selväkieli :", pädätty_selväkieli)
print("Selväkieli heksana :", selväkieli_tavuina.hex())
print("Pädätty    heksana :", pädätty_selväkieli.hex())

Edellisen solun tulostamassa tiedossa näkyy seuraavaa seikat:

  • Selväkieli on ”KAHVI”.

  • Pädätty selväkieli sisältää päddäyksen jossa kirjaimien ”KAHVI” perässsä on 0x0b-arvoja.

  • Pädätty selväkieli tulostetaan heksadesimaalisina tavuina. Tämä on yleinen käytäntö datan kanssa, koska esimerkiksi päddäysarvoa 0x0b vastaisi ascii-taulukossa vertikaalinen tabulointi, joka ei tulostettaessa erottuisi selkeästi.

Seuraava tehtävä vaatii pientä koodin muokkaamista. Sitä kannattaa kokeilla, vaikka koodaus ei olisikaan verissä.


Muuta edellisessä koodisolussa olevaa selväkieltä ”KAHVI” ja vastaa seuraaviin väittämiin.

Valitse oikea vaihtoehto.

Valitse oikea vaihtoehto.


Seuraavissa koodikentissä on havainnollistava esimerkki siitä, miten myöhemmin luomme tarvittaessa salain-olion, joka tarjoaa käyttöön enkryptaus- ja dekryptaus-oliot. Tällä kurssilla sinun ei tarvitse tietää mitä ohjelmoinnin oliot ovat.

  • Tuomme käyttöön salaimen Cipher.

  • Valitsemme algoritmeista AES-algoritmin ja annamme sille avaimen.

  • Kerromme, että salaimen toimintamoodi on ECB- eli koodikirja-moodi.

Tämän jälkeen salaimella luodaan salaus- ja purkuolioista instanssit eli ilmentymät. Salauksen suorittaa encryptor()-instanssi ja salauksen purun decryptor()-instanssi. On hyvä huomata, että salaimen algoritmi toimintamoodi avaimineen on määritelty ennen kuin otamme salaimen enkoodauksen ja dekoodauksen käyttöön.

Inactive
from xip import alusta_t601
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

avain, _, _, _, _, _ = alusta_t601()

# Luodaan AES-ECB lohkosalain käyttäen 128-bittistä avainta.
aes_ecb_salain = Cipher(algorithms.AES(avain), modes.ECB())

# Luodaan enkryptaus, eli salaava toiminne
enkryptaus = aes_ecb_salain.encryptor()

# Luodaan dekryptaus, eli salauksen purkava toiminne
dekryptaus = aes_ecb_salain.decryptor()

print("Salain ja sen enkoodauksen ja dekoodauksen tuottavat osat alustettu.")

Seuraavaksi suoritamme salauksen. Haemme alustuskirjastosta avaimen ja ”KAHVI”-sanan, jossa on mukana päddäys. Salain luodaan koodisolussa uudestaan varmuuden vuoksi.

Inactive
from xip import alusta_t601
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

avain, pädätty_kahvi, _, _, _, _ = alusta_t601()

aes_ecb_salain = Cipher(algorithms.AES(avain), modes.ECB())
enkryptaus = aes_ecb_salain.encryptor()

# Suoritetaan lyhyen viestin salaus
kahvi_salakielellä = enkryptaus.update(pädätty_kahvi) + enkryptaus.finalize()

# Näytetään miltä näyttää salakielinen viesti
print("Salakielinen viesti on:",kahvi_salakielellä)
print("Salakieli heksana: ", kahvi_salakielellä.hex())

Tämän jälkeen luonnollisesti puramme äsken salatun viestin. Avain ja salattu viesti ”KAHVI” haetaan varmuuden vuoksi alustusfunktiolla. Luomme myös tässä solussa uuden salaimen, joka purkaa annetun informaation.

Inactive
from xip import alusta_t601
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

avain, _, _, kahvi_salakielellä, _, _ = alusta_t601()

aes_ecb_salain = Cipher(algorithms.AES(avain), modes.ECB())
dekryptaus = aes_ecb_salain.decryptor()

purettu_salakieli = dekryptaus.update(kahvi_salakielellä)+dekryptaus.finalize()

# Näytetään purettu salakieli
print("Purettu salakieli jossa päddäys:", purettu_salakieli)
print("Purettu pädätty salakieli heksa:", purettu_salakieli.hex())

Lopuksi poistamme puretusta informaatiosta päddäyksen ja muunnamme tavumuodon takaisin tekstiksi, koska tiedämme alkuperäisen informaation olleen tekstiä.

Inactive
from xip import alusta_t601
from cryptography.hazmat.primitives import padding

_, _, _, _, _, purettu_salakieli = alusta_t601()

lohko_bitteinä = 128
lohko_tavuina = lohko_bitteinä//8
poista_päddäys = padding.PKCS7(lohko_bitteinä).unpadder()

# Poistetaan päddäys puretusta tavukoodista
purettu_salakieli_tavuina = poista_päddäys.update(purettu_salakieli) + poista_päddäys.finalize()

# Näytetään saatu tieto
print("Purettu salakieli tavuina:", purettu_salakieli_tavuina)
print("Purettu salakieli heksana:", purettu_salakieli_tavuina.hex())

purettu_salakieli_tekstinä = purettu_salakieli_tavuina.decode()

print("Purettu viesti tekstinä  :", purettu_salakieli_tekstinä)

Näin olemme suorittaneet ensimmäisen kokonaisen kierroksen lohkosalausta yhdelle vajaalle lohkolle. Teimme siis seuraavat asiat:

  • Loimme salattavan viestin KAHVI.

  • Muutimme salattavan viestin tavumuotoon

  • Päddäsimme viestin niin, että se täytti yhden AES-lohkosalaimen lohkon.

  • Suoritimme salauksen AES-koodikirjasalaimella käyttäen 128-bittistä avainta. Tällöin ajoimme 10-kierrosta AES-permutaatio-substituutioverkolla kuten edellisessä osiossa kuvattiin.

  • Tulostimme salauksen tuloksen eri muodoissa. Tästä näemme, että lohko on todellakin salattu.

  • Purimme salatun viestin, jolloin ajoimme taas 10-kierrosta AES-permutaatio-substituutioverkkoa purkaaksemme salakielen.

  • Lopuksi poistimme päddäyksen ja muutimme tavumuodossa olevan tiedon tekstimuotoon.


Vastaa edellisten esimerkkien ja koodien avulla seuraaviin väittämiin.

Valitse kaikki oikeat vaihtoehdot.


Seuraavat kysymykset vaativat koodin muokkaamista. Voit käyttää seuraavaa koodisolua tehtävän tekemiseen. Siinä on aika paljon alustuksia valmiina, mutta aivan kaikkia tarpeellisia osia siinä ei ole.

Inactive
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding

# Käytetään kaikissa esimerkeissä lähtökohtana suurta 2048 bittistä lukua
suuri_luku = b"S\xef8\x8e\xc8\xddff\xf4\x81\xc7 '2\x97\x88\x86\t3\x12\xfbTI5FQ\x05$P\xe85o\\a\xae\x80i=U\x16\t3\xc0i\xbd\xee\xcd\xc0\\\xf6\x13\x0f\xe8jK\x0e\xd9\xf8\xab\xbc\r!0d?\nv\xad\x06\x83\x01,\x83\xf9%\xa8n4\x12\xb3gU\x12\xda\xecw!\xf2O\xb5\r\x1e\xdd\xf0\xa2H5\xe9\xf2\x81\xd4B\x91\xf7r\xfaI!d\xf7\xfa\xafW\xce\xb2\x00x]\xb2[\xf5@:\x07\x9d\x9db\xca\xa8?Ue3G\xe1YVh\x80\x051g\x00\x07hQ\xc4\xf3K\x1b\x0f\\\x08\xfe\x19&6\xb2\x14\xcb\x90\xfd\xfdq+\xd6X\xa5\xc6Q\x84`U\x13\xee#Y\xb2\xdf8\x7fJ8l\x8bV\x89>\xe9\xc7\x83/\xdf\xf7(\x8b\xc0\xb3\xf8\xe11\x04\xcb\x99\x96[\xbdN\x8d\x8d-\xaa\x03\x90*m\xc3\xa1\x08\x91\x17\xd96^9#iX\xfc\xef \xdd\xd1\xcd\xff\xedY\x98\xbaA\xf2g\xbf\xb7q\xb4^\xa5\xc8\xd4\xcb\xd9\x0eZb\xf8"

# TODO ota 256 bittiä suuresta luvusta.
avain = ...

# Luodaan AES-ECB lohkosalain käyttäen 256-bittistä avainta.
aes_ecb_salain = Cipher(algorithms.AES(avain), modes.ECB())
enkryptaus = aes_ecb_salain.encryptor()
dekryptaus = aes_ecb_salain.decryptor()

lohko_bitteinä = 128

täydennä_päddäys = padding.PKCS7(lohko_bitteinä).padder()
poista_päddäys = padding.PKCS7(lohko_bitteinä).unpadder()

# TODO aseta salakieleksi AURINKO
salakieli = ....

# TODO tämän jälkeen voit tehdä tehtävänannon mukaisia askeleita ja tulostuksia

Vastaa seuraaviin väittämiin edellisten esimerkkien ja koodiesimerkkien avulla. Voit muokata yllä olevan koodisolun sisältöä vapaasti ja tehdä siinä kokeiluja.

Tässä tehtävässä joudut katsomaan ja ehkä muokkaamaan annettuja koodeja. Valitse kaikki oikeat vaihtoehdot.

Kopioi aiemmista soluista tarvittavat koodit ja muuta avain 256-bittiseksi, eli avain = pitkä_avain[:32]. Käytä viestinä AURINKO ja vastaa tehtävään. Valitse kaikki oikeat vaihtoehdot.



Esimerkki - Lohkottaminen

Edellisessä esimerkissä salasimme yhden ainoan sanan. Todellisuudessa on yleensä tarve salata tietoa, jonka koko on suurempi kuin lohkosalaimen lohkon koko. Tällöin tieto joudutaan jakamaan lohkoihin, jotka salataan. Viimeistä lohkoa lukuun ottamatta kaikki lohkot sisältävät 128 bittiä. Tällöin vain viimeinen lohko täydennetään eli päddätään.

Seuraavassa esimerkissä Alice salaa saamansa kakkureseptin lähettääkseen sen Bobille. Kakkuresepti on alun perin Martoilta peräisin.

Koodissa luodaan apufunktioita, joilla luetaan tekstitiedosto ja pystytään näyttämään se. Lisäksi funktio päddää viimeisen lohkon.

Inactive
# Funktio palauttaa tavu-muodosa luetun tiedoston.
def lue_binääri_tiedosto(tiedostonnimi):
    with open(tiedostonnimi, 'rb') as file:
        sisältö_tavuina = file.read()

    return sisältö_tavuina


# Funktio lukee tiedoston, jakaa sen lohkoiksi
# Ja päddää viimeiseen lohkon sisältämään 128-bittiä.
# Jos näytä_tiedosto parametri on True, näytetään tiedoston sisältö
# Oletus nyt on että lohkon koko on 128-bittiä
def lue_tiedosto_ja_esikäsittele(tiedostonnimi, lohkon_koko=128, näytä_tiedosto=False):

    # Jos haluamme näyttää tekstitiedoston sisällön
    if näytä_tiedosto:
        with open(tiedostonnimi, 'r', encoding='UTF-8') as file:
            tekstiä = file.readlines()

        print("".join(tekstiä))

    # Luetaan tavuina tiedosto sisään
    tavu_data = lue_binääri_tiedosto(tiedostonnimi)

    # Määritellään lohkon koko tavuina
    lohko_tavuina = lohkon_koko//8

    # Tehdään paikka lohkoille
    lohkot = []

    # Suoritetaan lohkominen
    for i in range(0,len(tavu_data), lohko_tavuina):
        lohkot.append(tavu_data[i:i+lohko_tavuina])

    # Suoritetaan päddäys viimeiselle lohkolle
    päddää = padding.PKCS7(lohkon_koko).padder()
    lohkot[-1] = päddää.update(lohkot[-1])+päddää.finalize()

    # Palautetaan tavumuodossa olevat lohkot, joista viimeinen on lavennettu 128-bittiseksi
    return lohkot

print("Apufunktiot on luotu!")

Nyt lataamme reseptin tiedostosta ja pyydämme, että funktio näyttää tiedoston sisällön.

Inactive
from xip import alusta_t602

lue_tiedosto_ja_esikäsittele = alusta_t602()

lohko_bitteinä = 128
lohko_tavuina = lohko_bitteinä//8

tiedosto = './Tekstit/kakkuresepti.txt'
lohkot_tavuina = lue_tiedosto_ja_esikäsittele(tiedosto, lohko_bitteinä, näytä_tiedosto=True)

Näyttää hyvältä, pystymme lukemaan tiedoston ja näyttämään sen sisällön.

Luodaan vielä apufunktio, jolla voidaan joko salata tai purkaa informaatiota AES:n lohkosalaimella koodikirja- eli ECB-moodissa. Myöhemmin tuomme tämän saman funktion kirjastosta, mutta voit katsoa alemmassa koodisolussa, mitä funktio tekee.

Inactive
# Funktio suorittaa tavutiedolle joko salauksen tai purun annetulla avaimella.
# Jos purku=False, niin funktio enkoodaa.
# Jos purku=True, niin funktio dekoodaa.
def salaa_ja_pura(tavutieto, avain, purku=False):
    # Luodaan AES-ECB lohkosalain käyttäen 128-bittistä avainta.
    aes_ecb_salain = Cipher(algorithms.AES(avain), modes.ECB())

    # luodaan joko enkryptaus tai dekryptaus
    if purku:
        operaatio = aes_ecb_salain.decryptor()
    else:
        operaatio = aes_ecb_salain.encryptor()

    # Katsotaan kuinka monta lohkoa pitää prosessoida.
    lohkoja = len(tavutieto)

    # Tehdään tila käsitellylle datalle.
    käsitellyt = []

    for i, lohko in enumerate(tavutieto):
        if i != lohkoja:
            käsitellyt.append(operaatio.update(lohko))
        else:
            käsitellyt.append(operaatio.update(lohko)+operaatio.finalize())

    return käsitellyt

print("Funktio joka toteuttaa enkoodauksen ja dekoodauksen luotu!")

Nyt voimme salata Marttojen loistavan kakkureseptin. Haemme kirjastosta tekstin esikäsiteltynä (tavumuotoon). Se on lohkottu salaimen lohkon kokoisiksi paloiksi muuttujaan lohkot_tavuina-muuttujaan.

Inactive
from xip import alusta_t603

avain, lohkot_tavuina, salaa_ja_pura = alusta_t603()

# Salataan resepti
salatut_lohkot=salaa_ja_pura(lohkot_tavuina, avain)
print("Salaus suoritettu! Seuraavassa salattu informaatio lohkoina:")

for lohko in salatut_lohkot:
    print(lohko.decode('latin-1'))

Edellisen koodisolun tulostuksesta näemme, että tiedosto on salattu. Vaikuttaa hyvältä! Katsotaan, miten Bob purkaa tämän salatun tiedon.

Bob purkaa viestin

Alice välittää salatun viestin Bobille. Seuraavassa esimerkissä jätämme tiedostoon tallentamisen ja tiedostosta luvun väliin. Lähdemme siis liikkeelle tilanteesta, jossa Bob on ladannut salatun tiedoston koneelleen ja suorittanut salasanalle ja salaimen toimintamoodille samat alustukset kuin Alice.

Tämän jälkeen Bob purkaa salauksen käyttäen samaa avainta kuin Alice. Käyttämämme menetelmä on symmetrinen. Bob on alustanut avaimen ja salaimen toiminnan samalla tavalla kuin Alice.


Vastaa tekstin pohjalta seuraaviin väittämiin. Huomaathan, että tähän tehtävään voi yrittää vastata vain kerran!

Bobin avaimen täytyy olla:

Bobin salaimen täytyy olla:


Seuraavassa koodissa salauksen purku poistaa myös päddäyksen.

Inactive
from xip import alusta_t604

avain, salatut_lohkot, salaa_ja_pura = alusta_t604()

puretut_lohkot = salaa_ja_pura(salatut_lohkot, avain, purku=True)
print("Purku suoritettu")
print(puretut_lohkot)

Data on vieläkin lohkoina. Bobin täytyy yhdistellä lohkot, jotta informaatio tulee samaan muotoon kuin alkuperäinen viesti.

Inactive
# Tämä funktio yhdistelee lohkot tavuina.
# Jos merkistö on määritelty, palautetaan lohkot yhdistettynä merkeiksi muutettuna.
# Jos merkistöä ei ole määritelty, palautetaan yhdistetyt lohkot tavuina.
def yhdistele(lohkot, merkistö=None):

    tavut = bytes()
    for lohko in lohkot:
        tavut += lohko

    # Jos on pyydetty merkkikoodauksen purkua, palautetaan dekoodattu tavukoodi.
    if merkistö is None:
        return tavut
    else:
        return tavut.decode(merkistö)

print("Yhdistely-funktio luotu.")

Lopuksi Bob katsoo, millaisen reseptin Alice on lähettänyt hänelle salattuna.

Inactive
from xip import alusta_t605

puretut_lohkot, yhdistele = alusta_t605()

# Seuraavaksi yhdistämme lohkot ja dekoodamme tekstin 'UTF-8' merkistökoodauksella
purettu_viesti = yhdistele(puretut_lohkot, 'UTF-8')
print(purettu_viesti)

Lohkosalaimelle data pitää lohkottaa ja salaaminen suoritetaan lohkoittain.

Valitse oikeat vaihtoehdot.



Kuvan salaus AES-koodikirjalla

Vaikuttaa siltä, että meillä on hyvä tapa salata tietoa. Vai onko?

Bobin mielestä resepti näyttää hyvältä. Bob päättää lähettää Alicelle kuvan kakusta, josta on ollut puhetta aiemmin. Hän salaa kakun kuvan AES-salaimella, joka toimii ECB-moodissa.

Katsotaan aluksi, mikä on Bobin valitsema kuva mansikkakakusta.

Inactive
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

kuvatiedosto = './images/cake.png'

# Avataan kuva
plt.imshow(mpimg.imread(kuvatiedosto))

# Näytetään kuva
plt.show()

Seuraava koodisolu tekee vaadittavan esikäsittelyn, jotta voimme salata kuvan. Esikäsittely sisältää seuraavat toimenpiteet:

  • Tiedoston luku ja yhdistäminen salattaviksi tavuiksi.

  • Lohkominen salaimen lohkon kokoisiksi palasiksi.

  • Funktio palauttaa kuvan alkuperäisen muodon ja kuvatiedoston lohkottuna.

  • Tieto alkuperäisestä muodosta tarvitaan, koska salatussa tiedossa ei kerrota, millainen kuva on ollut alun perin.

Seuraava funktio tuodaan myöhemmin kirjastosta käyttöön.

Inactive
# Tuodaan kirjastot jotta kuva voidaan lukea tiedoksi
from PIL import Image
import numpy as np

def lue_kuva(tiedosto, lohkon_koko=128, lohko_tavuina=16):
    kuva = np.asarray(Image.open(tiedosto))

    # Otetaan talteen kuvan alkuperäinen muoto
    muodot = kuva.shape

    # Litistetään kuva riviksi
    rivi_kuva = kuva.flatten()

    # Muunnetaan pikselit tavuiksi
    kuva_tavuina=rivi_kuva.tobytes()

    # Suoritetaan lohkominen
    kuva_lohkot = []
    for i in range(0,len(kuva_tavuina), lohko_tavuina):
        kuva_lohkot.append(kuva_tavuina[i:i+lohko_tavuina])

    return muodot, kuva_lohkot

print("Kuvan luku-funktio tuotettu!")

Sitten luetaan tiedosto ja salataan se. Lopuksi näytetään salattu kuva.

Inactive
import numpy as np
import matplotlib.pyplot as plt
from xip import alusta_t606

# Tuodaan funktiot ja avain
avain, lue_kuva, salaa_ja_pura, yhdistele = alusta_t606()

# Osoitetaan mikä tiedosto salataan
kuvatiedosto = './images/cake.png'

# Luetaan kuva lohkotuksi tavukoodiksi ja tallennetaan sen muoto
kuvan_muoto, lohkottu_kuva = lue_kuva(kuvatiedosto)

# Suoritetaan kuvan salaus
salattu_kuva = salaa_ja_pura(lohkottu_kuva, avain)

# Katsotaan miltä salattu kuva näyttää
salatut_yhdistetyt_lohkot=yhdistele(salattu_kuva)
salattu_pikselit=np.frombuffer(salatut_yhdistetyt_lohkot, dtype='uint8')

# Näytetään salattu kuva
plt.imshow(salattu_pikselit.reshape(kuvan_muoto))
plt.show()

Bob on hämmästynyt nähdessään salatun kuvan kakusta. Salatusta kuvasta pystyy näkemään kakun muodon ja sen, että kakussa on yksi kynttilä.

Vaikuttaa siltä, että lohkojen informaatio välittyy jollain tavalla selväkielestä salakieleen, vaikka jokainen lohko on salattu erillisinä datalohkoina hyvin. Tällöin vaatimus siitä, että salain tuottaa satunnaisen näköistä informaatiota ei toteudu.

Olemme aiemmin määritelleet, että hyvä salain tuottaa satunnaisen näköistä dataa. AES-salain kyllä tuottaa jokaisesta lohkosta satunnaisen näköistä dataa, mutta näyttää siltä, että selväkielen ja salakielen välillä on jokin riippuvuus.

ECB-moodi ei siis koskaan ole hyväksyttävä salaimen toimintamoodi!

Salain näyttää salaavan jokaisen erillisen lohkon hyvin. Informaatio, joka jakautuu useammalle lohkolle, paljastaa kuitenkin lohkosalaimen ECB-moodin heikkouden. Salatusta informaatiosta pystyy päättelemään salaamattoman informaation sisällön.

Valitse oikea vaihtoehto.

Yhteenveto

Nyt osaamme käyttää oikeaa AES-salainta ECB-moodissa. Osaamme myös täydentää eli päddätä viimeisen lohkon puuttuvilla merkeillä. Näimme myös esimerkeissä, että lohkominen ja lohkojen yhdistäminen on suoritettava lohkosalaimen ulkopuolella.

Varoitus

Kuvaesimerkki näyttää sen, ettei mitään lohkosalainta pidä käyttää ECB-moodissa. Esimerkeissämme käytimme AES-lohkosalainta, mutta ongelma koskee kaikkia lohkosalaimia, joita käytetään ECB-moodissa.

Seuraavaksi käytämme lohkosalainta yhdellä hyväksi todetulla tavalla. Vaikka muitakin lohkosalaimia on olemassa, jatkamme AES-salaimen käyttöä, koska se on lohkosalaimista yleisin. Tutustumme paremmin toimivaan moodiin, joka on nimeltään Cipher Block Chaining.

Palautusta lähetetään...