- CS-EJ4404
- 6. Lohkosalaimen käyttö
- 6.3 Lohkosalaimen lohkojenketjutus
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.
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.
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.
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
.
Ensimmäinen selväkielen lohko \(P_1\) pitää sisällään merkit
KAHV
.Tavuiksi muunnettuna lohkon
KAHV
ascii-merkit ovat0x4B414856
.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.
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.
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.
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.
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.
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
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.