Lohkosalaimen lohkojenketjutus

Jotta lohkosalain toimisi hyvin symmetrisessä lohkosalauksessa, otamme käyttöön salainlohkojen ketjutuksen (engl. Cipher Block Chaining eli CBC-moodin).

CBC-moodissa lohko toimii enkoodauksessa alla olevan kuvan mukaisesti.

../_images/l5_cbc_mode.png

Lohkosalain toimii CBC-moodissa seuraavalla tavalla:

  • Selväkielinen informaatio \(P\) lohkotaan salaimelle sopiviksi lohkoiksi \(P_1P_2P_3\).

  • Luodaan satunnainen kertakäyttöluku \(IV\).

  • Kertakäyttöluku \(IV\) ja ensimmäinen selväkielen lohko \(P_1\) tuottavat XOR-funktion avulla lohkolle sisään menevän salattavan datan.

  • Lohkosalain käyttää avainta \(K\).

  • Lohkosalain laskee saamastaan \(IV \oplus P_1\)-datasta avaimella enkoodatun lohkon \(C_1\).

  • \(C_1\) toimii kertakäyttölukuna seuraavalle lohkolle.

  • \(C_1\) ja seuraava selväkielen lohko \(P_2\) prosessoidaan XOR-funktiolla, mikä tuottaa seuraavan salaimelle menevän datalohkon.

  • Edellistä ketjutusta jatketaan, kunnes kaikki selväkielen lohkot on prosessoitu.

Salakielen laskettuja lohkoja siis käytetään kertakäyttölukuina, jolloin edellisen lohkon salaustulosta hyödynnetään salaimessa entropian lisäämiseksi.


os Alice nyt lähettää jotain salaamaansa tietoa Bobille, heillä on edelleenkin kummallakin tiedossa salainen avain. Tämän lisäksi, kun Alice lähettää salatun tiedon Bobille, hän lähettää myös salaamattomana käyttämänsä kertakäyttöluvun \(IV\). Tässä vaiheessa salainen avain on jo pitänyt jakaa Alicen ja Bobin välillä eri menetelmällä.

Kun salateksti dekoodataan, salain toimii alla olevan kuvan mukaisesti.

../_images/l5_cbc_mode_decrypt.png
  • Salakirjoitus \(C\) lohkotaan lohkosalaimelle sopiviksi osiksi \(C_1C_2C_3\).

  • Lohkosalain käyttää dekoodauksessa \(D\) avainta \(K\).

  • Salauksessa käytetty kertakäyttöluku \(IV\) annetaan dekooderille, jotta salaus voidaan purkaa.

  • Salain purkaa lohkon \(C_1\), mutta se ei vielä ole selväkieltä. Kutsutaan tätä ulostuloksi \(P'_1\).

  • Kertakäyttölukua \(IV\) käytetään dekoodatun lohkon ulostulossa, jossa se XOR-funktion jälkeen muodostaa lohkon ulostulosta \(P'_1\) ensimmäisen selväkielisen lohkon \(P_1\).

  • Lohkoa \(C_1\) käytetään toisen dekoodatun lohkon ulostulon \(P'_2\) kanssa, jossa se muodostaa XOR-funktiolla selväkielisen toisen lohkon \(P_2\).

  • Jokainen lohko prosessoidaan näin, kunnes kaikki lohkot on purettu.


Vastaa edellisten esimerkkien avulla seuraaviin väittämiin.

Valitse oikeat vaihtoehdot.



Esimerkki 32-bittisellä lohkosalaimella

Oletetaan, että meillä on käytössä lohkosalain, jonka lohkon koko on 32 bittiä. Käytämme tätä salainta CBC-moodissa eli ketjutamme salakieltä. Oheinen esimerkkikuva havainnollistaa, miten salaattaisiin osa tekstistä ”KAHVI CHARLOTASSA ON HYVÄÄ JA VAHVAA”.

Kuvassa tekstiä on näkyvissä viestin kolme ensimmäistä sanaa: KAHVI CHARLOTASSA ON.

../_images/l5_cbc_mode_kahvi.png
  • Ensimmäinen selväkielen lohko \(P_1\) pitää sisällään merkit KAHV.

  • Tavuiksi muunnettuna lohkon KAHV ascii-merkit ovat 0x4B414856.

  • Luomme satunnaisen 32-bittisen kertakäyttöluvun \(IV\).

  • Olkoon tämä esimerkin ”satunnainen” kertakäyttöluku nyt 0x0E5A62F8.

  • Lasketaan XOR eli \(IV \oplus P_1\), jonka tulokseksi tulee 0x451B2AAE.

  • Edellä laskettu 32-bittinen arvo on se, joka menee salaimelle salattavaksi lohkoksi.

  • Salain käyttää avainta ja tuottaa tulokseksi salatun lohkon \(C_1\).

  • Lohko \(P_2\) sisältää kirjaimet I CH.

  • \(C_1\) käytetään kertakäyttölukuna seuraavan lohkon ketjutuskäsittelyssä selväkielen lohkon \(P_2\) kanssa.

  • Näin seuraava salaimelle menevä salattava lohko on \(P_2 \oplus C_1\).

  • Jokainen lohko prosessoidaan näin, kunnes kaikki lohkot on salattu.


Dekoodatessa käytetään:

  • Salaista avainta.

  • Selväkielisenä välitettävää kertakäyttölukua \(IV\).

  • Salatekstistä \(C\) tuotettuja lohkoja \(C_1\)\(C_5\).

Seuraava kuva esittää, miten salakielen lohkoja käytetään.

../_images/l5_cbc_mode_kahvi_decrypt.png
  • Ensin salain laskee avainta käyttäen salatusta lohkosta \(C_1\) arvon \(P'_1\).

  • \(P_1\) lasketaan XOR-funktiolla \(IV \oplus P'_1\).

  • Salakielen lohko \(C_2\) dekoodataan muodostaen arvo \(P'_2\).

  • Salakielen lohkosta \(C_1\) muodostetaan \(P'_2\) kanssa XOR-funktiolla lohko \(P_2\).

  • Jokainen lohko prosessoidaan näin, kunnes kaikki lohkot on purettu.


Vastaa edellisten esimerkkien avulla seuraaviin väittämiin.

Valitse oikeat vaihtoehdot.



Oikea käyttöesimerkki CBC-moodista

Kokeillaan AES-salainta CBC-moodissa. Tässä vaiheessa tiedämme jo, että AES on yksi lohkosalaimen toteutustavoista.

Käytämme osin samoja funktioita, joita esittelimme edellisen ECB-moodin kanssa.

Seuraavassa koodilohkossa suoritetaan kaikki tarvittavat alustukset ja luodaan tarvittavat funktiot. Koodista on poistettu kaikki kommentit, mutta ne löytyvät tarvittaessa edellisen osion koodisoluista.

Kommentteja sisältävät kohdat pitävät sisällään uutta materiaalia.

Inactive
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from PIL import Image
import numpy as np
import os

def lue_kuva(tiedosto, lohkon_koko=128, lohko_tavuina=16):
    kuva = np.asarray(Image.open(tiedosto))
    muodot = kuva.shape
    rivi_kuva = kuva.flatten()
    kuva_tavuina=rivi_kuva.tobytes()
    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

# Lisätty lohkon_koko ja lohko_tavuina funktion kutsuun oletusarvoina.
def salaa_ja_pura_cbc(tavutieto, avain, IV=None, lohkon_koko=128, lohko_tavuina=16, purku=False):

    # Salatessa funktiolle ei anneta IV:tä eli ensimmäistä kertakäyttönumeroa.
    # Luodaan ensimmäinen kertakäyttönumero tietokoneen entropia-altaasta, joka on siis täysin satunnainen 16-tavuinen, eli 128-bittinen luku
    if IV is None:
        IV = os.urandom(lohko_tavuina)

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

    if purku:
        operaatio = aes_ecb_salain.decryptor()
    else:
        operaatio = aes_ecb_salain.encryptor()

    lohkoja = len(tavutieto)
    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())

    # Palautetaan sekä alkuarvo IV että käsitellyt data-lohkot jos enkoodaus
    if purku:
        return IV, käsitellyt
    else:
        return käsitellyt


def yhdistele(lohkot, merkistö=None):
    tavut = bytes()
    for lohko in lohkot:
        tavut += lohko

    if merkistö is None:
        return tavut
    else:
        return tavut.decode(merkistö)

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"

avain = suuri_luku[:16]

kuvatiedosto = './images/cake.png'

plt.imshow(mpimg.imread(kuvatiedosto))
plt.title("Kuva ennen salausta")
plt.show()

print("Tarvittavat funktiot ja avain luotu!")

Seuraavaksi salataan sama kuva kakusta, jonka salaukseen aikaisemmin käytettiin ECB-moodia.

Tällä kertaa AES-salain toimii CBC-moodissa. Kertakäyttöluku \(IV\) on täysin satunnainen ja tuotettu entropia-altaasta. \(IV\) voisi olla mikä tahansa satunnainen luku.

Katsotaan miten käy nyt, kun Bob salaa kuvan kakusta.

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

# Tuodaan funktiot kirjastosta
avain, kuvatiedosto, lue_kuva, salaa_ja_pura_cbc, yhdistele = alusta_t620()

# Luetaan kuvan tiedot
kuvan_muoto, lohkottu_kuva = lue_kuva(kuvatiedosto)

# Salataan kuva AES CBC:llä ja palautetaan IV sekä salattu informaatio
salauksen_IV, salattu_kuva = salaa_ja_pura_cbc(lohkottu_kuva, avain)

# Yhdistellään salatut lohkot
salatut_yhdistetyt_lohkot=yhdistele(salattu_kuva)

# Tulkitaan tavut etumerkittömiksi 8-bittisiksi kokonaislukuarvoiksi
salattu_pikselit=np.frombuffer(salatut_yhdistetyt_lohkot, dtype='uint8')

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

Kuvan pitäisi olla värikästä kohinaa. Tämän tuloksen perustella vaikuttaisi, että salaimemme toimii hyvin! Tällaisesta salatusta kuvasta kukaan sivullinen ei voi ymmärtää, että Bobin lähettämä kuva sisältää syntymäpäiväkakun.


Hieman vaativampi tehtävä

Vastataksesi kysymykseen 1 seuraavassa tehtävässä, joudut kirjoittamaan koodia edelliseen koodisoluun. Voit myös ehkä päätellä osan vastauksista tehtävää edeltävän tekstin perusteella.

Seuraava koodisolu puolestaan toimii perustana kysymykselle 2.

Inactive
from xip import alusta_t620
from xip import alusta_t603

avain, _, _, salaa_ja_pura_cbc, yhdistele = alusta_t620()
_, teksti_lohkoina, salaa_ja_pura_ecb = alusta_t603()

print(teksti_lohkoina)

# Tekstin salaus on tehty alle valmiiksi.

oikea_IV, salakirjoitus_a = salaa_ja_pura_cbc(teksti_lohkoina, avain)

# TODO 1 kokeile purkaa äsken salakirjoitettu viesti, tähän liittyy kysymyksiä.
# Muista salain tarvitsee IV=... ja purku=True parametrit


# TODO 2 vaihda IV (esimerkiksi salaa uudestaan ja ota uuden salauksen IV talteen)
# Yritä purkaa AES CBC:llä ``salakirjoitus_a`` käyttäen väärää IV:tä
# Yksi tapa saada aikaan nollavektori IV:lle on käyttää bytes(16)


# TODO 3 kokeile purkaa AEA-ECB:llä ``salakirjoitus_a``
# ECB haluaa ei tarvitse IV:tä mutta tarvitsee purku=True parametrin

Valitse alla olevista väittämistä kaikki, jotka pitävät paikkansa. Voit tarvittaessa lisätä koodiin printtauksia print(muuttujan_nimi) selvittääksesi oikeat vastaukset.

Tee muutoksia koodisoluun, jossa Bob onnistuu salaamaan kuvan kakusta. Valitse sitten alta oikeat vaihtoehdot.

Suorita tehtävää edeltävässä koodisolussa annetut tehtävät. Löydät tehtävät koodin kommenteista tunnisteilla TODO 1, TODO 2 ja TODO 3.

Kun käytät dekoodausta, muista välittää funktiokutsussa CBC-salaimelle arvo IV=oikea_IV ja kummallekin salaimelle (CBC ja ECB) parametri purku=True. Valitse sitten alta oikeat vaihtoehdot.



Yhteenveto

Nyt osaamme käyttää AES-salainta CBC-moodissa, joka on hyvä käyttömoodi määrämittaiselle informaatiolle.

Ymmärrämme myös, että kertakäyttöluvun \(IV\) on syytä olla satunnainen. Tiedämme myös, että salain tarvitsee purkua varten enkoodauksessa käytetyn kertakäyttöluvun, joten \(IV\) on välitettävä salatun viestin mukana vastaanottajalle. Yleensä \(IV\) välitetään osapuolten välillä selväkielisenä.

Seuraavaksi katsomme, miten sama AES-lohkosalain voidaan valjastaa toimimaan jonosalaimena. Tällöin voimme käyttää salainta esimerkiksi jatkuvan datavirran salaamiseen.

Palautusta lähetetään...