TTKK / Tietoliikenne / J.Koskinen : Tietoturvallisuuden perusteet

1. viikko, ke 1.9.1999

Viruksista

Yleinen pahojen (malicious) ohjelmien jaottelu: Jaottelua ei kannata ymmärtää kovin jyrkkänä, sillä esimerkiksi viruksen tehtävänä voi olla Troijan hevosen asentaminen. Troijan hevosen tehtävänä puolestaan voi olla salaluukun avaaminen tai loogisen pommin räjäyttäminen. Yhtenä jaotteluperusteena voisi olla myös, leviääkö ohjelma vai ei, ja jos leviää, tekeekö se sen itsenäisesti. Jäljempänä virusten luokittelussa esiintyy yhtenä erottelevana piirteenä isäntäolion luonne.

Oma luokkansa leviäjinä ja vahingon aiheuttajina ovat väärennetyt virusvaroitukset ('hoax'it), jotka kuuluvat samaan luokkaan ketjukirjeiden kanssa. Viruksista yms. on syytä olla sen verran perillä, ettei harhaudu levittämään tällaisia varoituksia, puhumattakaan siitä että ryhtyy johonkin niissä neuvotuista varotoimista.

Viruksen elinkaaressa voidaan erotella seuraavanlaisia vaiheita.

Jaotellaan virukset ensinnäkin kolmeen päätyyppiin sen mukaan missä ne "asuvat": Muita piirteitä, joilla viruksia voi luokitella (eivät toisensa poissulkevia):

Intermezzo: (Symmetrinen) salakirjoitus

Salakirjoituksen idea on yksinkertainen: lähettäjä panee viestin "lukkoon" avaimella ja vastaanottaja avaa sen samanlaisella avaimella. Muut eivät saa viestiä selville koska heillä ei ole avainta ja lukitusalgoritmi on niin monimutkainen ettei avainta voi keksiä eikä lukkoa muutenkaan saa murretuksi missään järkevässä ajassa.

Yleinen mekaanisiin lukkoihinkin pätevä periaate on, että algoritmia ei voi olettaa salaiseksi, ainoastaan avain on salainen. Itsensä kryptannut piilovirus joutuu kuitenkin jättämään paitsi purkualgoritmin myös avaimen selväkielisenä johonkin kohtaan tartuttamaansa koodia (tai ainakin osoitteen, josta avain löytyy).

Esimerkki 1. Viesti eli selväteksti (plaintext) p = jono bittejä (keksitään luennolla), avain k = 0110101.... (kuulijoiden valitsema jatko), kryptoteksti c lasketaan biteittäin XOR-summana: c = p XOR k = .... . Selväteksti saadaan tästä takaisin helposti XOR-operaation laskusääntöjen perusteella:

c XOR k = (p XOR k) XOR k = p XOR (k XOR k) = p XOR 0-jono = p.

Tämä (ja muunnelmat) on ainoa täysin turvallinen salausalgoritmi, "one-time pad". Avain on satunnainen ja sen pituus on suurempi kuin viestin.

Esimerkki 2. Pitkää avainta on hankala käsitellä. Samaa lyhyttä avainta, esim. k1 = 0110101 voisi tietysti toistaa, jolloin k olisi 0110101 0110101 0110101 0110101 ... . Jos viestin ajatellaan koostuvan samanmittaisista lohkoista p = p1p2p3..., muodostuu kryptotekstistä c=c1c2c3... sellainen, että c1 XOR c2 = p1 XOR p2 jne. Avaimen vaikutus eliminoituu siis täysin pareittain XOR-summatuista kryptolohkoista. Kryptoanalyytikolta ei kulu kauaakaan selvittää selvätekstiä p tilastollisilla analyyseilla, sillä varsinkin luonnollisen kielisissä viesteissä on runsaasti redundanssia - eli sitä samaa "ylimäärätietoa", jonka ansiosta luennoitsijan taululle kirjoittamasta tekstistä saa yleensä selvää, vaikka mistään yksittäin nähdystä kirjaimesta ei ehkä saisikaan, jos muut on pyyhitty pois sen ympäriltä.

Esimerkki 3. Jotain muuntelua voisi järjestää avaimelle k1 = 0110101, jotta äskeiseltä ongelmalta vältyttäisiin. Muodostetaanpa "pseudoavain" k = k1k2k3... seuraavasti: ki+1 = luvun a * ki seitsemän alinta bittiä, missä a on jokin k1:stä riippuva luku, vaikkapa a = k1. Saadaan k = 53, (2809 ==>) 121, (6413 ==>) 13, (699 ==>) 49, ... eli binäärijonona k = 0110101 1111001 0001101 0110001 ... . Seitsemän alimman bitin ottamisen voisi ilmaista hienommin jakojäännöksenä modulo 128 (=27). Vastaava menettely tulee aikanaan esille näennäissatunnaislukujen muodostamisessa ja modulaarinen aritmetiikka monessa muussakin yhteydessä.

Äskeinen avainta "venyttävä" salausperiaate on esimerkki vuokryptauksesta (stream cipher). Käytännössä venytysperiaatteen pitää olla mutkikkaampi (avainvuo, "key stream" vaikeammin arvattavissa) ja lähtökohtana olevan avaimen tietenkin paljon pitempi (esim 128 bittiä).

Virusten torjunta

Virustorjuntaakin voidaan tarkastella aiemmin esillä olleen vaihejaon mukaisesti: Välttäminen - estäminen - havaitseminen - toipuminen - korjaaminen. Kaksi ensimmäistä vaihetta ovat vastaavia kuin biologisten virustenkin tapauksessa: "pysyttele vain kotona" ja "pidä huolta hygieniasta". Vaiheena 2 alunperin mainittu 'pelottaminen' ei tietenkään päde kumpaankaan virusmaailmaan sen jälkeen kun virus on lähtenyt leviämään.

Jos (tietokone)virus on päässyt tekemään tihutyönsä, toipumista on enää lisätuhojen ja leviämisen estäminen, käytännössä siis uuden käynnistymisen tai ainakin aktivoitumisvaiheen ehkäisy. Se tapahtuu yleensä samalla kun jäljet korjataan eli viruksen saastuttamat tai tuhoamat tiedostot palautetaan varmuuskopioista ja kun itse virus alkajaisiksi siivotaan tiedostoista, joihin se on tarttunut. Tämän voivat torjuntaohjelmat usein tehdä ilman että tiedostoa, siis esim. ohjelmaa täytyy asentaa uudelleen. Viruksen mahdollisesti ylikirjoittama koodi luonnollisesti menetetään, esim. makrovirus on voinut ottaa jonkin dokumenttiin alunperin kuuluneen makron paikan.

Haastavin torjuntavaihe on virusten havaitseminen: Viruksen etsintäkeinoja voidaan jaotella seuraaviin sukupolviin:

  1. perinteinen skannaus etsii tunnettuja viruksia hakemalla niiden (pääpiirteissään vakiomuotoista) koodia tiedostoista;
  2. kehittyneempi skannaus käyttää heuristiikkoja, joilla tunnistetaan viruksille yleisemminkin tyypillisiä koodin osia. On myös mahdollista löytää (piiloviruksen) salausavain ja paljastaa virus purkamalla sen salaus.
  3. muistinvarainen ohjelma voi seurata muiden ohjelmien toimia ja havaita viruksen sille ominaisen käytöksen perusteella.
  4. neljännen polven menetelmät ovat monipuolisia yhdistelmiä, joissa on myös torjuntaominaisuuksia.
Harjoitus: 1. Onko näissä jotain "jälkeä" niistä suojamenetelmistä, joita viime kerran lopuksi yleisesti lueteltiin? 2. Piiloviruksen salausavain on satunainen bittijono. Miten sellaista voisi muka etsiä? Vastaus: etsitäänkin kryptauksen purkualgoritmia.

Virusten havaitsemiseen voidaan myös käyttää yleistä ohjelmistojen eheystarkastusta, joka tarkistaa aika ajoin, ovatko ohjelmatiedostoista (ja käynnistyssektorista) lasketut tarkistussummat samat kuin alkuperäiset, jotka on laskettu (toivottavasti) ennen mahdollista tartuntaa ja jotka ovat tallessa (toivottavasti kirjoitussuojatusti).

Yksi uudentyyppinen menetelmä on ajaa tarkistettavaa ohjelmaa emuloimalla CPU:ta ohjelmallisesti. Varsinainen prosessori ei joudu alttiiksi. Jos ohjelma sisältää itsensä salanneen viruksen, salauksen purku tapahtuu viruksen omaa rutiinia käyttäen. Tämän jälkeen emulointia kontrolloiva ohjelma löytää viruksen skannatessaan emuloitavaa koodia.

Digitaalinen immuunijärjestelmä, IBM:n kehittämä prototyyppi (vrt. artikkeli Scientific Americanissa marraskuussa 1997):

  1. Jokaisessa PC:ssä on viruksia havaitseva ohjelmisto, joka lähettää kopion epäilyttävästä ohjelmasta (kyseisen aliverkon) hallintakoneeseen,
  2. joka salaa näytteen ja lähettää sen edelleen virusten analysointikoneelle,
  3. joka luo (emulointi- tms.) ympäristön, jossa tartunnan saanut ohjelma voidaan ajaa turvallisesti. Kone muodostaa sitten ohjeet, joilla virus voidaan tunnistaa ja poistaa ohjelmasta.
  4. Ohjeet lähetetään takaisin hallintakoneeseen,
  5. joka lähettää ne tartunnan saaneeseen koneeseen sekä muihin saman verkon koneisiin.
  6. Uusi virus otetaan huomioon päivityksissä (="vasta-aineissa") jotka lähetetään immuunijärjestelmän tilaajille.
Mikäli koneen muistissa on virus silloin, kun viruksentorjuntaohjelmia aletaan ajaa, se voi tarttua torjuntaohjelmiin ja muuttaa niiden toimintaa siten, ettei virusta havaitakaan. Tämän ehkäisemiseksi - jos epäilee virusta PC:ssä, pitäisi ensimmäiseksi käynnistää kone uudelleen kirjoitussuojatulta levykkeeltä, joka on varmuudella puhdas. Useat virustorjuntaohjelmat tarkastavat kuitenkin ensin itsensä tarkistussumman avulla ja varoittavat käyttäjää, jos eivät "koe olevansa kunnossa".

Seuraavaksi tutustutaan lähemmin tarkistussumman ideaan. Viruksiin ei varsinaisesti enää palata näillä sivuilla, mutta kurssin aineistoksi sopii hyvin TKK:n virusopas (elokuulta 1998). LUE siitä ainakin luvut 2 ja 5. Opas sisältää linkkejä, joiden takaa voi hakea lisätietoja. Oppaan liitteenä on myös lueteltu TKK:lta löytyneitä viruksia. Tampereen yliopistosta puolestaan löytyy virustutkimusyksikkö.

Monipuolista virustietoutta löytyy myös artikkelista "Vircing" the InVircible, jonka tarkoituksena on osoittaa, miten kehno virustorjuntaohjelma InVircible oikeastaan on.

Intermezzo: Tarkistussumma ja yksisuuntainen tiivistefunktio

Tarkistussumma (checksum) on erikoistapaus tiivistefunktiosta (hash function), joka puolestaan on aivan eri asia kuin "kompressio"-tiivistäminen, jossa alkuperäinen tieto voidaan palauttaa joko täysin (ZIP, GIF ym.) tai likimääräisesti (JPEG ym.)

Tutuin esimerkki tarkistussummasta on henkilötunnuksen viimeinen merkki, joka on laskettu muista merkeistä. Vastaava merkitys on pankkisiirron viitenumeron viimeisellä numeromerkillä. Tällaisten tarkistussummien tarkoituksena on näppäily- ym. virheiden havaitseminen.

Yksinumeroinen tarkistussumma voitaisiin periaatteessa laskea vaikkapa summaamalla kaikki numeromerkit ja ottamalla tulokseksi summan viimeinen numero. Näin lasketaan esim. pariteettibitti. Yleensä tarkistussumman algoritmi on monimutkaisempi, eikä kyse enää ole pelkästä summaamisesta. Esimerkiksi CRC:n (eli Cyclic Redundancy Check-menetelmän) ideana on lisätä bittilohkon perään tietty määrä (16 tai 32) bittejä siten, että tulos on jaollinen annetulla kiinteällä luvulla. Jos vastaanottaja ei saa jakoa tasan lohkossa tai tarkistussummassa (eli FCS:ssä, Frame Check Sekvenssissä) on tapahtunut muutos.

Seuraavaksi esiteltävä yksisuuntainen tiivistäminen lisää tarkistusominaisuuteen kryptograafista kätkemistä, joka on tarpeen, jottei esim. virus voisi viilata saastuttamaansa tiedostoa sellaiseksi, että se tuottaisi saman tarkistussumman kuin alkuperäinenkin.

Yksisuuntaisen tiivistefunktion (one-way hash function) tarkoitus on tuottaa viestistä (yleisemmin merkkijonosta) kiinteän mittainen, lyhyt "tiivistelmä", joka edustaa koko viestiä sikäli, että on vaikea löytää mitään muuta viestiä, jolla olisi samanlainen tiiviste. Koska tiivisteen pituus on tyypillisesti 128 tai 160 bittiä ja viesti voi olla miten pitkä hyvänsä, on tietenkin olemassa runsaasti viestejä, joista tulee sama tiiviste, mutta oleellista on, ettei yhtään niistä pysty löytämään. Tiivisteestä (hash) käytetään myös nimityksiä 'digital fingerprint' tai 'message digest' (MD).

Tiivistefunktiolta H edellytetty yksisuuntaisuus merkitsee siis sitä, että kun on annettu h, ei voida millään kohtuullisella vaivalla löytää x:ää, jolle olisi H(x)=h. Usein vaaditaan enemmän: ei saisi löytyä yhtään paria viestejä jotka "törmäävät" eli tiivistyvät samaksi h:ksi - joko niin että vaatimus koskee mitä tahansa h:ta tai niin että mitään annettua x:ää kohti saa löytyä (eri) y:tä, joka toteuttaisi ehdon H(x)=H(y).

Yleinen yksisuuntaisen tiivistämisen periaate: käytetään "kutistusfunktiota" (compression function (!)), jolle syötetään iteratiivisesti aiempi kutistustulos ja seuraava viestilohko (kumpikin esim. 128 bittiä). Alussa tarvitaan alustusvektori (siis "nollas" kutistustulos) ja viestin täydennys lohkon monikerran mittaiseksi (täydennystä voidaan tehdä myös lohkokohtaisesti). Useimmiten viestin loppuun liitetään sen pituus. Kutistusvaiheen jälkeen voidaan tehdä vielä jokin toisenlainen muunnos.

Tunnetuimmat (yksisuuntaiset) tiivistealgoritmit kuuluvat MD4-perheeseen, jonka kehitystä (joka tapahtui 1990-luvun alkupuoliskolla) kuvaa seuraava kaavio:

MD4 --> MD5 ----->  SHA --> SHA-1
 | \___________
 |             \
ext-MD4 ---->  RIPEMD   ------->    RIPEMD-160
(Erikoinen kryptosysteemi, joka nopeuttaa tarkistussumman laskentaa: Incremental cryptography with application to virus protection (Bellare & Micciancio, joilta myös A New Paradigm for Collision-Free Hashing: Incrementality at Reduced Cost, 1996 ) )

Esimerkki: välimieshyökkäys DH-protokollaa vastaan

Viimeksi jo nähtiin hieman, millaisia hyökkäyksiä voi olla tietojärjestelmiä vastaan. Otetaan nyt yksi konkreettinen esimerkki joka osoittaa teoreettisestikin miten hankalan aihepiirin kanssa olemme tekemisissä.

Salakirjoituksen periaatteista tuli edellä jo esille se, että siihen tarvitaan jokin osapuolten tuntema yhteinen salaisuus, avain, jota ei kukaan muu tiedä. Avain on tyypillisesti bittijono, jolla voi olla pituutta esim. 64 tai 128, ja sen voi yhtä hyvin tulkita kokonaisluvuksi. Avaimesta sopiminen on hankalaa: sitä ei voi lähettää suojattomassa tietoliikennekanavassa eikä sitä toisaalta voi salata koska ei ole vielä salausavainta.

Nerokas ratkaisu tarjoutuu potenssiin korottamisen laskusäännöistä ja siitä että logaritmin laskeminen modulaarisessa eli kokonaislukuaritmetiikassa on erittäin vaikeaa. Unohdetaan tässä vaiheessa aritmetiikan modulaarisuus ja keskitytään vain perusideaan:

Kun osapuolet A ja B haluavat generoida yhteisen avaimen, he sopivat kantaluvusta g, jonka ei tarvitse olla salainen. Kumpikin valitsee sitten satunnaisen luvun; olkoon A:n luku x ja B:n luku y. Kumpikin pitää oman lukunsa salassa, mutta A lähettää B:lle luvun gx ja B lähettää A:lle luvun gy. Yhteisenä avaimena A:lla ja B:llä on nyt luku (gy)x = (gx)y. Jotta joku muu saisi selville saman luvun, hänen pitäisi siis luvuista gx ja gy laskea luku gxy. Tätä varten hyökkääjäkin tarvitsisi jomman kumman luvuista x ja y, eli hän joutuisi laskemaan logaritmin luvusta gx tai gy. Koska kyseessä on todellisuudessa diskreetti logaritmi modulaarisessa aritmetiikassa (modulina yhteisesti sovittu suuri alkuluku), ei tämä käy päinsä missään kohtuullisessa ajassa.

Oletetaan, että hyökkääjä C kaappaa A:n ja B:n toisilleen lähettämät viestit (esim. tietoverkon reitittimessä) ja vaihtaa kummankin tilalle luvun gz, missä z on C:n keksimä luku. Nyt A laskee itselleen avaimen gxz ja B avaimen gyz eivätkä ne ole samat. Tämäpä ei haittaa C:tä, sillä C tuntee molemmat nämä avaimet ja pystyy A:n ja B:n "välimiehenä" jatkossa purkamaan A:n viestistä salauksen avaimella gxz ja lähettämään sen edelleen B:lle avaimella gyz salattuna - ja vastaavasti B:ltä A:n suuntaan. Tämän "palvelun" avulla C saa siis selville kaikki luottamukselliseksi tarkoitetut viestit A:n ja B:n välillä ja voi halutessaan tietysti muuttaakin niitä, eivätkä A ja B osaa epäillä mitään.

Tässä luonnosteltu Diffie-Hellmanin avaintenvaihtoprotokolla (vuodelta 1976) tarvitsee siis lisäksi osapuolten autentikoinnin, jotta C ei pääse väliin. Kun se on hoidossa, järjestelmä onkin erittäin hyvä.

Välimies- eli "man-in-the-middle"-hyökkäys pitää ottaa huomioon kaikessa tietoliikenteen turvaamisessa. Edellä käsitelty eksponenttifunktio sen sijaan tarjoaa aiheen seuraavaan välisoittoon.

Intermezzo: Yksisuuntainen funktio

Salakirjoituksen pitäisi avainta tuntemattomalle merkitä muunnosta, jota ei voi kääntää ilman suunnatonta vaivaa. Kryptologiassa käytetään myös sellaisia muunnoksia eli funktioita, joita on lähes mahdoton kääntää, vaikka funktiossa ei olisi mitään salaista. Tämä vastaa siis sitä (onnetonta tilannetta), että kryptotekstiä ei voi purkaa, vaikka avain tunnettaisiin ja tiedettäisiin että on vain yksi selväteksti josta kryptoteksti voi olla peräisin. Tilanne on hieman erilainen kuin edellä käsitellyssä tiivistefunktiossa, joka on epäinjektiivinen eli kuvaa useita lähtöarvoja samaksi arvoksi.

Yksisuuntaisella funktiolla tarkoitetaan yleensä sellaista injektiivistä funktiota f, jolle arvon x laskeminen arvosta f(x) on käytännössä mahdotonta. Arvon f(x) laskeminen x:stä sen sijaan ei saa olla vaikeaa. Esimerkkejä yksisuuntaisista funktioista: