Tiivistefunktioiden toteutukset

Tässä osiossa käytämme eri tiivistefunktioita. Pääpaino on sellaisissa tiivistefunktioissa, joiden käyttöä suositellaan yhä.

Lisäksi osiossa mainitaan muutama historiallinen tiivistefunktio. Joidenkin tiivistefunktioiden käyttöä ei enää suositella, koska näille on kehitetty sellainen tapa löytää alkukuva, joka tuottaa törmäyksen.


Yleinen rakenne

Osa tiivistefunktioista hyödyntää lohkosalainta tiivisteen laskennassa.

Tiiviste lasketaan niin, että data paloitellaan tiivistefunktiolle sopivan kokoisiksi lohkoiksi. Esimerkiksi informaatio \(X\) voidaan lohkoa tiivistefunktiosta riippuen 64 bitin tai 1600 bitin prosessoitaviksi lohkoiksi.

Eräs klassinen tiivistefunktion toteutuksen rakenne on Merkle-Damgård-rakenne:

  • Informaatio, josta tiiviste lasketaan, paloitellaan lohkoiksi \(X_1, X_2, ..., X_n\) .

  • Ensimmäinen lohko \(X_1\) prosessoidaan esimerkiksi ketjutetulla lohkosalaimella, jonka avaimeksi annetaan alkuarvo \(IV\).

  • Näin tiivistefunktio on tuottanut ensimmäinen sisäisen tiivisteen \(H_1\).

  • Tämän jälkeen lohkosalaimen tuottamaa tiivistettä \(H_1\) käytetään seuraavan lohkon \(X_2\) avaimena.

  • Näin toimitaan aina viimeiseen lohkoon \(X_n\) asti.

  • Jos \(X_n\) ei riitä täyttämään lohkoa, siihen pädätään dataa, kuten lohkosalaimien yhteydessä olemme jo oppineet.

  • Kun tiivistefunktio tuottaa viimeisen ”kierrostiivisteen” \(H_n\), on se samalla myös lopullinen tiiviste \(H\), jonka tiivistefunktio palauttaa laskettuna informaatiolle \(X\) .


Vastaa tehtävään Merkle-Damgård-rakenteesta.

Valitse oikeat väittämät.


Lohkosalaimiin perustuvan toiminnan lisäksi on olemassa permutaatioon perustuvia tiivistefunktioita. Koska kyse on implementoinnin eroista, emme keskity nyt niihin syvällisemmin. Tärkeämpää on ymmärtää, miksi tiivisteet toimivat ja mitkä tiivistefunktiot ovat käytössä tällä hetkellä.

Käytämme esimerkeissämme informaationa viestiä. Viesti muunnetaan Pythonin tiivistefunktioille tavumuotoon. Pythonin tiivistefunktiot löytyvät kirjastosta hashlib.

Inactive
import hashlib

viesti="Olen maksanut Carolin syntymäpäiväkakun tarveaineet ja ne voi hakea lähikaupasta. Vakuutan tämän tiedon oikeaksi. Alice. "
tavu_viesti = viesti.encode()

# Näytetään viesti ja tavuviesti
print("Viestimme on:",viesti)
print("Tavuviesti  :",tavu_viesti)

Secure Hash Algorithms -perhe (SHA)

SHA-tiivisteet ovat laajassa käytössä. Nämä tiivistefunktiot on kilpailuttanut ja hyväksynyt käyttöön NIST eli Yhdysvaltojen National Institute of Standards and Technology.

NIST on standardisoinut SHA-1:n sekä nykyisin käytössä olevat SHA-2- sekä SHA-3-tiivistefunktiot. Tämän lisäksi NIST on standardisoinut lavennetun ulostulon tiivistefunktioita.


SHA-1

SHA-1 on jo vanhentunut, mutta katsotaan miten se toimii.

  • SHA-1 ottaa sisään informaation \(X\) ja pilkkoo sen 512 bitin lohkoihin.

  • Lohkot prosessoidaan ja tuloksena tulee sisäinen kierrostiiviste \(H_r\).

  • SHA-1 laskee jokaisella kierroksella sisäisesti 160-bittistä tiivistettä (5 x 32 bittiä).

  • Sisäinen tiiviste \(H_r\) ja viestilohko \(X_n\) syötetään lohkosalaimelle

  • Lohkosalain manipuloi bittejä jokaisen kierroksen aikana. Kierroksia on yhteensä 80.

Edellä kuvattua laskentaa toistetaan, kunnes kaikki informaation lohkot on prosessoitu. Tällöin lohkosalaimen ulostulosta saadaan varsinainen 160-bittinen tiiviste.

Käsittelimme edellisessä osiossa syntymäpäiväparadoksia. Tällöin oletamme, että 160-bittisen tiivisteen törmäysten sieto on suuruusluokkaa \(2^{80}\).

SHA-1-funktioille ei vieläkään ole olemassa käänteisfunktiota, mutta sille on keskitty tapa tuottaa törmäyksiä. Tutkijat pystyivät osoittamaan vuonna 2005, että SHA-1-tiivistefunktiolla törmäysten sieto on vain noin \(2^{62}\). Tämä on monta kertaluokkaa huonompi törmäysten sieto kuin mitä syntymäpäiväparadoksi antaa olettaa. Tutkijat siis löysivät tavan tuottaa alkukuvia, joista saadaan SHA-1-tiivistefunktiolla samoja tiivisteitä.

SHA-1-tiivistettä ei enää suositella käytettäväksi juuri tästä syystä.

Inactive
# Otetaan hash-kirjastot käyttöön
import hashlib

# Alustetaan viesti ja tavuviesti
from xip import alusta_730
viesti, tavu_viesti = alusta_730()

# Luodaan SHA-1 tiivistefunktio
sha1 = hashlib.sha1()

# Lasketaan tiiviste
sha1.update(tavu_viesti)

# Näytertään viesti ja tiivisteen tiedot
print("Viesti on:", viesti)
print("SHA1 tiiviste on", sha1.hexdigest())
print("Tiivisteen pituus bitteinä: {}".format(8*(sha1.digest_size)))

Vastaa kysymyksiin SHA-1-tiivistefunktiosta edeltävän tekstin ja koodisolujen perusteella.

Valitse oikea väittämä.

Valitse kaikki oikeat vaihtoehdot, kun salattava viesti on ”Olen maksanut Carolin syntymäpäiväkakun tarveaineet ja ne voi hakea lähikaupasta. Vakuutan tämän tiedon oikeaksi. Alice.



SHA-2

SHA-1:n tiiviste on 160-bittinen, kun taas SHA-2:lla on mahdollista tuottaa neljä eri pituista tiivistettä. SHA-2-variantteja kutsutaan niiden pituuksien mukaan nimillä: SHA-224, SHA-256, SHA-384 ja SHA-512. Nimissä olevat numerot tarkoittavat luonnollisesti tiivisteiden pituuksia.

SHA-2-tiivistefunktioita käytetään edelleen aktiivisesti.

SHA-2-tiivistefunktiot toimivat seuraavalla tavalla:

  • Salattava viesti lohkotaan 512 bitin lohkoihin.

  • Sisäisiä laskentakierroksia on 64.

  • SHA-256:ssa on kaksi eri sisäistä sananleveyttä. Sisäinen sananleveys bitteinä määrittää osaltaan tiiviestefunktion rakennetta.

  • SHA-256 ja SHA-224 käyttävät sisäisenä sananleveytenä 256 bittiä JA samaa laskentaydintä.

  • SHA-512 ja SHA-384 käyttävät sisäisesti vastaavasti 512-bittistä sananleveyttä JA samaa laskentaydintä.

  • SHA-224:ssä ja SHA-384:ssä ulostulo käytännössä supistetaan lyhyempään bittimäärään.

  • Vaikka SHA-224 ja SHA-384 käyttävät samaa laskentaydintä, lasketaan näissä sisäisesti eri alkuarvo \(IV\), jolloin tiivisteet ovat kokonaisuudessan erilaiset kuin täysimittaisten kerneleiden tuottamat tiivisteet.

Katsotaan käytännössä, miltä SHA-2-tiivistet näyttävät.

Inactive
import hashlib
from xip import alusta_730
viesti, tavu_viesti = alusta_730()

# Luodaan SHA-2 tiivistefunktiot
sha224 = hashlib.sha224()
sha256 = hashlib.sha256()
sha384 = hashlib.sha384()
sha512 = hashlib.sha512()

# Lasketaan tiivisteet
sha224.update(tavu_viesti)
sha256.update(tavu_viesti)
sha384.update(tavu_viesti)
sha512.update(tavu_viesti)

# Näytetään tiivisteet
print("Viesti on", viesti)

print("SHA-224:", sha224.hexdigest())
print("Tiivisteen pituus bitteinä: {}\n".format(8*(sha224.digest_size)))

print("SHA-256:", sha256.hexdigest())
print("Tiivisteen pituus bitteinä: {}\n".format(8*(sha256.digest_size)))

print("SHA-384:", sha384.hexdigest())
print("Tiivisteen pituus bitteinä: {}\n".format(8*(sha384.digest_size)))

print("SHA-512:", sha512.hexdigest())
print("Tiivisteen pituus bitteinä: {}\n".format(8*(sha512.digest_size)))

Vastaa kysymyksiin SHA-2-tiivistefunktioista edeltävän tekstin ja koodisolun perusteella.

Valitse oikeat väittämät.

Valitse kaikki oikeat vaihtoehdot, kun salattava viesti on ”Olen maksanut Carolin syntymäpäiväkakun tarveaineet ja ne voi hakea lähikaupasta. Vakuutan tämän tiedon oikeaksi. Alice.


Edellinen tehtävä osoittaa, että tiivisteen tarkistaminen käsin on liian työlästä ja virheiden mahdollisuus on suuri. Käytännössä tiivisteiden oikeellisuuden tarkistaminen tehdään aina ohjelmallisesti.


SHA-3

SHA3-tiivistefunktiona toimii NIST:in 2007 järjestämän kilpailun voittoalgoritmi. Voittaneen tiivistefunktion nimi on KECCAK. Menetelmä kuuluu tiivistefunktioihin, joista käytetään englanniksi nimitystä sponge function. Suomeksi nimi voisi olla sienifunktio.

SHA-3 poikkeaa olennaisesti SHA-1:sta ja SHA-2:sta toiminnallisesti. SHA-3:n oletetaan olevan tällä hetkellä turvallisin käytettävissä oleva standardisoitu tiivistefunktio.

  • Informaatio jaetaan lohkoiksi.

  • Lohkot esikäsitellään ja päddätään 1600 bitin mittaisiksi.

  • Laskennassa on kaksi vaihetta: absorptio ja puristus/rutistaminen (engl. squeeze)

  • Nimet kuvaavat kuvitteellisesti tilannetta, jossa sienifunktion ”sieneen” imeytyy vettä (absorptio). Tämän jälkeen sientä puristetaan (squeeze), jolloin tiiviste valuu siitä ulos.

Informaation absorboiminen sienifunktioon (engl. absorption phase) tapahtuu seuraavasti:

  • SHA-3:n absorptiolaskennassa informaatio diffusoituu sisäiseen 1600 bitin sanaan.

  • Absorptiossa esikäsiteltyä informaatiolohkoa manipuloidaan 24 kertaa.

  • Tämän jälkeen tulosta hyödynnetään seuraavan informaatiolohkon käsittelyssä, jota myös manipuloidaan 24 kertaa.

  • Näin jatketaan, kunnes koko informaatio on prosessoitu KECCAK laskennalla.

  • Tätä absorptiolaskennan tulosta tai mitään välivaihetta ei ole tarkoitus pystyä lukemaan.

Tiivisteen ”puristaminen” sienifunktiosta:

  • SHA-3:n toisessa vaiheessa suoritetaan puristaminen (engl. squeeze phase)

  • Puristusvaiheessa aiemmin lasketusta absorboidusta 1600 bittisestä sanasta puristetaan ulos halutun mittainen tiiviste.

Tekninen, tarkempi kuvaus algoritmista on luettavissa Keccakin verkkosivuilla.

SHA-3-perheeseen kuuluu seuraavat funktiot:

  • Neljä tiivistefunktiota SHA3-224, SHA3-256, SHA3-384 ja SHA3-512.

  • Kaksi laajennettavan tiivisteen algoritmia SHAKE128 ja SHAKE256. Nämä kaksi algoritmia voivat tuottaa tiivisteitä, joiden pituuden voi valita.

  • Lyhenne SHAKE tulee sanoista Secure Hash Algorithm with Keccak.

Seuraavassa koodisolussa SHA-3-tiivisteet otetaan suoraan käyttöön. Teknisesti ilmaistuna käytämme siis Python kirjastofunktiota suoraan instanssi-olioina.

Inactive
# Otetaan suoraan kirjaston funktiot käyttöön
from hashlib import sha3_224, sha3_256, sha3_384, sha3_512, shake_128, shake_256

# Alustetaan viesti
from xip import alusta_730
viesti, tavu_viesti = alusta_730()

# Näytetään viesti
print("Viesti on:", viesti)

# Lasketaan ja näytetään yhdellä kertaa SHA-3 tiivisteet
print("Funktio     Tiiviste")
print("SHA3-224:", sha3_224(tavu_viesti).hexdigest())
print("SHA3-256:", sha3_256(tavu_viesti).hexdigest())
print("SHA3-384:", sha3_384(tavu_viesti).hexdigest())
print("SHA3-512:", sha3_512(tavu_viesti).hexdigest())

# Näytetään kolme eri mittaista SHAKE tiivistettä kummallakin SHAKE tiivistefunktiolla
print("\nSHAKE128")
print(" 64 bittiä:", shake_128(tavu_viesti).hexdigest(64//8))
print("136 bittiä:", shake_128(tavu_viesti).hexdigest(136//8))
print("520 bittiä:", shake_128(tavu_viesti).hexdigest(520//8))

print("\nSHAKE256:")
print(" 64 bittiä:", shake_256(tavu_viesti).hexdigest(64//8))
print("136 bittiä:", shake_256(tavu_viesti).hexdigest(136//8))
print("520 bittiä:", shake_256(tavu_viesti).hexdigest(520//8))

Vastaa kysymyksiin SHA-3-tiivistefunktioista edeltävän tekstin ja koodisolun perusteella.

Valitse oikeat väittämät.

Valitse kaikki oikeat vaihtoehdot, kun salattava viesti on ”Olen maksanut Carolin syntymäpäiväkakun tarveaineet ja ne voi hakea lähikaupasta. Vakuutan tämän tiedon oikeaksi. Alice.



Muita tiivistefunktioita

Vanhoja, ei suositeltavia tiivistefunktioita:

  • Ennen SHA-tiivistefunktioita käytössä oli laajalti MD-tiivistefunktioita (engl. message-digest). Niistä on olemassa useita variantteja.

  • SHA-1 suunniteltiin alunperin MD5-tiivisteen korvaajaksi. Mutta kuten jo aiemmin mainittiin, myös SHA-1 on vanhentunut, eikä sitä kannata käyttää.

NIST:in ohella on olemassa muita kryptografian vaikuttajia, jotka ovat määrittäneet tiivistefunktioita omaan käyttöönsä.

  • Kiinalla on käytössä SM3-tiivistefunktio.

  • Venäjän on mainittu käyttävän tiivistefunktionaan Streebog -tiivistefunktiota.

Tässä mainittujen lisäksi on olemassa useita eri käyttötarkoituksiin optimoituja tiivistefunktiota. Yksi tutustumisen arvoinen on BLAKE, josta on olemassa useita toteutuksia kuten BLAKE2 ja BLAKE3. Emme tutustu BLAKE-funktioiden toimintaan nyt tarkemmin, mutta näytämme seuraavassa koodisolussa demonstraation nimissä, että valmiin kirjaston käyttö on suoraviivaista.

Inactive
from hashlib import blake2b, blake2s
from xip import alusta_730

# Tuodaan viesti
viesti, tavu_viesti = alusta_730()

# Näytetään Blaken tiivisteet
print("Funktio    Tiiviste")
print("BLAKE2b:", blake2b(tavu_viesti).hexdigest())
print("BLAKE2b pituus : {} bittiä".format(2*blake2b(tavu_viesti).digest_size))

print("Funktio    Tiiviste")
print("BLAKE2s:", blake2s(tavu_viesti).hexdigest())
print("BLAKE2s pituus : {} bittiä".format(2*blake2s(tavu_viesti).digest_size))

Tiivisteiden tulevaisuus

Tällä hetkellä on käynnissä NIST:in järjestämä kryptografia-algoritmien kilpailu, joka alkoi jo vuonna 2016. Kilpailussa etsitään uusia algoritmeja, joiden käyttö turvaa tiedon salauksen, autenttisuuden ja eheyden myös kvanttitietokoneiden saavuttaessa riittävän kyvykkyyden. Näissä Post Quantum Cryptography (PQC) algoritmeissa tiivistefunktioilla on keskeinen rooli.

Kilpailussa on myös useita ehdotuksia digitaalisten allekirjoitusten algoritmeiksi, joihin myös nämä tiivistefunktiot tavallaan kuuluvat. Lue lisää aiheesta PQC-kilpailun sivulta.

Tässä osiossa on kuvattu useita tiivistefunktiota ja niiden ominaisuuksia. Kaikkiin tämän tehtävän kysymyksiin ei kuitenkaan löydy vastausta kurssin sivulta. Saatat siis joutua hakemaan lisätietoa itsenäisesti internetistä. Hyviä lähteitä on ainakin wikipediassa sekä Pythonin hashlib-koodikirjaston opassivuilla.

Valitse oikeat vaihtoehdot.

Valitse oikeat vaihtoehdot.


Yhteenveto

Vihje

Kun asetat johonkin järjestelmään salasanan, niin lasketaan antamastasi salasanasta tiiviste. Salasanasta laskettu tiiviste tallennetaan järjestelmään, mutta itse salasanaa ei koskaan tallenneta järjestelmään. Kirjautuessasi palveluun, järjestelmä laskee palveluun kirjautumisessa antamastasi salasanasta tiivisteen ja vertaa onko se sama kuin järjestelmään jo aiemmin tallennettu tiiviste. Tiivisteillä on siis tärkeä rooli monessa tietoturvan arkisessa osa-alueessa.

Nyt tiedämme, että on olemassa eri tiivistefunktioita. Tiedämme myös että niitä on kehitetty aikojen saatossa, jotta tiivisteiden törmäykset olisivat harvinaisempia ja itse tiivisteen laskenta olisi kryptografisesti turvallisempi.

On olemassa tiivistefunktioita, jotka tuottavat määrämittaisia tiivisteitä, esimerkiksi 224-, 256-, 384- ja 512-bittisiä tiivisteitä.

Tämän lisäksi on olemassa tiivistefunktioita, jotka pystyvät tuottamaan vapaamittaisia tiivisteitä. Laajennetun ulostulon funktiot (XOF) ovat myös siksi mielenkiintoisia, että niitä voi käyttää joskus satunnaislukugeneraattoreina.

Tärkeä tiivistefunktion käyttötapa on käyttää avainta tiivisteen kanssa. Tähän perehdytään tarkemmin seuraavassa osiossa.

Palautusta lähetetään...