Ohjelmistojen rakentaminen Koodikirjastot Tehtävänanto Antti Juustila <antti.juustila@oulu.fi> Versio 1.0.3 tiistai 31. toukokuuta 2016 Tässä tehtävänannossa olevat ohjeet olettavat että työskentelet *nix -ympäristössä ja modulissa käytettävät boost ja jsoncpp -kirjastot on asennettu annettujen ohjeiden mukaisesti ja toimivat. Annetut makefile:t on testattu toimivaksi Ubuntussa sekä Mac OS X:ssä. Suosittelen kurssin Windows -käyttäjille työskentelyä VirtualBox:ssa Ubuntua käyttäen. Nämä saat ilmaiseksi ja niiden asentaminen on helppoa. Annettu koodi tulee jaettavaksi Moodleen ellei aloitusseminaarissa toisin kerrota. Tehtävän saa tehdä yksin tai parityönä. Loppuseminaarissa viimeistellään töitä, laaditaan kokemusraportti ja käydään läpi aikaansaatuja toteutuksia. EasyCryptoLib Tutustukaa annettuun koodiin. Koodi sisältää kaksi komponenttia: EasyCryptoLib -kirjasto Client Kirjasto tukee tekstin salaamista (encrypt) ja salatun tekstin purkamista (decrypt) selväkieliseksi. Ohjelma (client) joka käyttää kirjastoa tekstin salaamiseen. Sivu 1 / 6
Kirjasto koostuu useasta lähdekooditiedostosta: makefile EasyCryptoLib.hpp EasyCryptoLibBad.hpp EasyCryptoLib.cpp EasyCryptoLibBad.cpp EasyCryptoLibPriv.hpp EasyCryptoPrivMatrix.hpp ja.cpp EasyCryptoPrivReverse.h pp ja.cpp Käännöstiedosto jolla kirjaston voi kääntää antamalla komennon make. Huom: makefile on muokattava omaan kehitysympäristöön sopivaksi ennen kääntämistä. Kirjaston ohjelmointirajapinta. Kirjastoa hyödyntävä ohjelmaa kehitettäessä tarvitaan tämä otsikkotiedosto ja käännetty dynaaminen kirjasto (.so,.dll tai.dylib, riippuen kehitysympäristöstä). Esimerkki huonosta rajapintatoteutuksesta. Tämän rajapinnan huonot puolet demonstroidaan aloitusseminaarissa. Demoa lukuunottamatta tällä rajapinnalla ei kurssilla ole muuta käyttöä. Hyvän ohjelmointirajapinnan (EasyCryptoLib.hpp) toteutus. Tätä tiedostoa ei anneta kirjastoa käyttävän ohjelmien ohjelmoijille. Kuten edellinen, mutta huonon kirjastorajapinnan EasyCryptoLibBad.hpp toteutus. Demoa lukuunottamatta tällä rajapinnalla ei kurssilla ole muuta käyttöä. Yksittäisen salaus- ja purkumetodin toteutuksen rajapinta. Ei osa kirjaston julkista rajapintaa. Yksittäiset salaus/purkumetodit toteuttavat tämän rajapinnan. Matriisisalausmenetelmän toteutus joka toteuttaa EasyCryptoLibPriv -rajapinnan. Nämä tiedostot eivät ole osa kirjaston julkista rajapintaa. Käänteissalausmenetelmän toteutus joka toteuttaa EasyCryptoLibPriv -rajapinnan. Nämä tiedostot eivät ole osa kirjaston julkista rajapintaa. Muokkaa makefile sopimaan omaan kehitysympäristöösi: install: -osiossa, katso että hakemistot johon kirjaston julkinen rajapinta eli otsikkotiedostot ja dynaaminen kirjasto asennetaan on oikea. Otsikkotiedostojen hakemisto on yleensä joko /usr/include tai /usr/local/include Dynaamisen kirjaston hakemisto on /usr/lib tai /usr/local/lib Käännä EasyCryptoLib -kirjasto makefile:n sisältämässä hakemistossa antamalla komento make. Katso että kääntäminen onnistui ilman virheitä. Seuraavaksi, kirjasto asennetaan muiden sovellusten käytettäväksi kopiomalla otsikkotiedosto system headers -hakemistoon ja kirjasto em. lib hakemistoon. Asenna kirjasto antamalla komento make install. Tämä yleensä vaatii admin -oikeudet, joten tällöin suorita komento sudo make install. Mac OS X:ssä /usr/lib ja /usr/include -hakemistoihin ei voi asentaa tietoturvasyistä, joten joudut käyttämään hakemistoja /usr/local/lib ja /usr/local/include. Pohdi seuraavia kysymyksiä, tutkien koodia ja makefile:ä: mistä tietää että koodin kääntämisen jälkeen syntyy dynaaminen kirjasto? miten kirjaston julkinen rajapinta muodostuu? mikä on osa kirjaston julkista rajapintaa ja mikä ei? mitkä asiat vaikuttavat julkisen rajapinnan suunnitteluun ja toteuttamiseen? Sivu 2 / 6
CryptoClientConsole Seuraavaksi voit kääntää ja kokeilla konsolipohjaista ohjelmaa CryptoClientConsole -hakemistossa joka hyödyntää edellä käännettyä EasyCryptoLib -kirjastoa. Huomaa, että kirjastoa käyttävä ohjelma ei näe mitään muuta kuin kirjaston kaksi julkista otsikkotiedostoa ja itse dynaamisen kirjaston,.so -tiedoston. Kirjaston sisäinen toteutus (muut lähdekooditiedostot) jää siis tälle asiakasohjelmalle täysin tuntemattomaksi, joka tietysti on tarkoituskin. Katso ohjelman main.cpp -tiedostoa (ainoa ohjelmakooditiedosto): #include <EasyCryptoLib.hpp> #include <EasyCryptoLibBad.hpp> Asiakasohjelma näkee siis vain nämä kaksi otsikkotiedostoa ja includeaa ne väkästen välissä: <> eli järjestelmän jaettujen otsikkotiedostojen hakemistoista, ei hapsujen välissä (kehittäjän omista projektien hakemistoista). Tämä hakemisto on makefile:n perusteella /usr/local/include Tutustu ohjelman makefile:en. Huomaa, että ohjelma ei sisällä salauskirjaston cpp-tiedostoja eikä muita otsikkotiedostoja. Ainoastaan main.cpp tiedosto mainitaan. Kirjasto näkyy ohjelmalle siis vain julkisen otsikkotiedoston ja binäärisen dynaamisen kirjaston kautta. Muokkaa jälleen makefile omaan ympäristöösi sopivaksi: Varmista että linkität ohjelman oikeaan EasyCryptoLib -dynaamiseen kirjastoon oikeassa polussa, muokkaamalla LIBS -polkua. Käännä client -ohjelma komennolla make. Suorita ohjelma ja testaa sen toiminnallisuutta. Nyt olet kääntänyt dynaamisen kirjaston ja hyödyntänyt sen ohjelmointirajapintaa, API:a, sen otsikkotiedoston kautta. Olet myös oppinut miten kirjasto julkistetaan antamalla sen julkinen ohjelmointirajapinta (otsikkotiedosto) ja itse dynaaminen kirjasto muiden ohjelmien käyttöön. Aloitusseminaarin demonstraation kautta olet myös ymmärtänyt julkisen rajapinnan toteutuksen tärkeyden kirjaston muutosten hallinnan näkökulmasta. Pohdi aloitusseminaarin alustuksen, demon ja tutustumasi lukupaketin (Martin Reddy: API Design for C++) perustella miten hyvä ja huono kirjastorajapinta eroavat toisistaan. Tarkastele myös rajapintojen virheenhallintaa ja pohdi niiden eroja. HUOM: Tästä eteenpäin, harjoitustyössä ei tarvitse, kannata tai saa käyttää EasyCryptoLibBad -rajapintaa. Voit siis poistaa kyseisen luokan.hpp ja.cpp -tiedostot kirjastosta. Muista myös poistaa tiedoston maininta makefile:stä. Jos haluat vielä käyttää konsolisovellusta esimerkiksi testaamiseen, kommentoi sen lähdekoodista kohdat jotka käyttävät EasyCryptoLibBad -rajapintaa. Harjoitustyö Modulin harjoitustyössä jatkamme dynaamisten kirjastojen lisäksi muunlaisten ohjelmointirajapintojen parissa. Suunnittelet ja toteutat rajapinnan jolla EasyCryptoLib -kirjastoa voidaan käyttää verkon yli. Samalla tutustut uusiin muihin kirjastoihin: boost -kirjasto, jota käytetään mm. verkkotoiminnallisuuden toteuttamiseksi; jsoncpp -kirjasto, jota käytetään JSON -pohjaisen viestirajapinnan toteuttamiseksi salausserverin (EasyCryptoServer) ja client ohjelman (EasyCryptoClient) välille. Sivu 3 / 6
Saat osan EasyCryptoServer ja EasyCryptoClient -sovellusten lähdekoodista valmiina. Toteutat ohjelmiin ne osat joilla: client ja server kommunikoivat toistensa kanssa lähettämällä JSON -muotoisia datagrammeja UDP-protokollan päällä hyödyntäen boost -kirjaston asio -modulia; suunnittelet JSON -viestit joilla client ja server viestivät toistensa kanssa; toteutat JSON -viestirakenteiden mukaisten viestien laatimisen ja purkamisen sekä clientin että serverin päässä, hyödyntäen jsoncpp -kirjastoa. Lopullinen ohjelman rakenne tulee näyttämään oheisen UML:n käyttöönottokaavion esittämältä. Vasemmalla client -ohjelma, joka hyödyntää boost:ia verkkotoiminnallisuuden toteuttamiseen ja jsoncpp:tä viestirakenteiden luomiseen ja purkamiseen. Oikealla server, joka vastaavasti hyödyntää boost:ia ja jsoncpp:tä, ja lisäksi EasyCryptoLib -kirjastoa. Tutustu ohjelmien lähdekooditiedostoihin sekä makefile:ihin. Pohdi miten eri kirjastojen (EasyCryptoLib, boost, jsoncpp) käyttäminen näkyy clientissa ja serverissä; niiden lähdekooditiedostoissa ja makefile:issä. Huomaa, että joudut muuttamaan makefile:ssä mainittujen otsikkotiedostojen ja kirjastojen polkuja ottaen huomioon sen miten olet asentanut boost:n ja jsoncpp:n omassa kehitysympäristössäsi! Huomaa, että et saa lisätä mitään EasyCryptoLib -kirjaston lähdekooditiedostoja serverin makefile:en tai sisällyttää muuten lähdekoodia toteutukseen. Voit käyttää serverin toteutuksessa vain kirjaston julkista rajapintaa, eli EasyCryptoLib.hpp ja libeasycrypto.so -tiedostoja /usr/local/ include ja /usr/local/lib -hakemistoista. Tehtävänanto 1. Suunnittele tarvittavat JSON -viestit (protokolla) sekä viestien rakenteet joilla mahdollistat client -ohjelman rakentamisen joka pystyy hyödyntämään salauskirjastoa. Ota huomioon se, että clienti pitää pystyä yhdistämään UDP-protokollalla lähettämänsä salauspyyntö serverille, serverin myöhemmin lähettämään vastaukseen. Miten tämä tapahtuu? Varsinkin huomioitaessa se että client voi lähettää peräkkäin useita Sivu 4 / 6
salauspyyntöjä ennen kuin serveri ehtii vastata niihin. Salaaminen ja sen purkaminen on siis asynkronista toimintaa. Ota huomioon myös se, että client-toteutus ei tiedä minkälainen serveri vastaa palvelupyyntöihin ja mitä salausmenetelmiä serveri mahdollisesti tukee. Clientin on saatava tämä jotenkin selville ja hyödynnettävä tätä tietoa. Hyödynnä JSON -validaattoreita kun suunnittelet viestien rakennetta. Esim. http://jsonlint.com 2. Suunnittele protokolla ja viestirakenne sellaiseksi, että se ottaa huomioon tulevaisuuden muutostarpeet: 1. On oltava mahdollista lisätä kirjastoon uusia salausmenetelmiä 2. On oltava mahdollista muuttaa olemassaolevia salausmentelmiä (esim. virheenkorjaus, parantaminen) 3. On oltava mahdollista asentaa palvelin niin että se tukee vain tiettyjä salausmenetelmiä, ei kaikkia mahdollisia joita joku palvelin saattaa tukea. 3. Toteuta annetun koodin pohjalta sekä client että server hyödyntäen jsoncpp ja boost -kirjastoja sekä EasyCryptoLib -kirjastoa 4. Testaa client ja server -toteutuksia siten että salauskirjaston hyödyntäminen verkon yli on mahdollista. 5. Toteuta kirjastoon ja serveriin tuki uudelle salausmenetelmälle ja sitä hyödyntävä uusi client-ohjelma (tai uusi versio siitä) siten, että vanha client -ohjelma toimii edelleen uudenkin serverin kanssa. Testaa myös että uusi client -ohjelma toimii myös vanhan serverin kanssa. Tässä siis käytännössä testaat, onko suunnittelmasi JSON -pohjainen API (protokolla ja viestirakenne) hyvä yhteensopivuusmielessä, eli osasitko suunnitella APIn tulevaisuuden muutostarpeita ajatellen. 6. Vaihtoehtoinen tehtävä: Toteuta salauskirjasto siten että se toimii plugin -arkkitehtuurin mukaisesti, hyödyntäen Boost 1.61:n boost.dll -arkkitehtuuria. Tutoriaali: http://www.boost.org/doc/libs/1_61_0/doc/html/boost_dll/tutorial.html Toteuta kukin salausmenetelmä (reverse, matrix, ) omana plugin -dll:nään. Kirjasto lataa plugin -dll:t muistiin tietystä asennushakemistosta (esim /usr/local/lib/ easycrypt)ja käyttää niitä salaamiseen. Testaa uutta toteutusta kopioimalla ja poistamalla plugin.dll (.so,.dylib) -tiedostoja asennushakemistosta Mielellään toteutettuna siten että plugin -muutokset tulevat voimaan ilman että serveriä pitää käynnistää uudelleen. Kuudes tehtävä on vaihtoehtoinen. Jos toteutat ja testaat tehtävän mallikkaasti muiden tehtävien lisäksi, modulista tulee kiitettävä arvosana 5. Valmiina annettava koodi on saatavilla opettajan osoittamassa paikassa. Tutustu annettuun koodiin ja kääntämisessä tarvittaviin makefile:ihin. Tee makefile:ihin edellisten esimerkkien mukaiset tarvittavat muutokset omaan ympäristöösi sopiviksi. Vaikka ohjelmat mahdollisesti kääntyvät ilman muutoksia, ne eivät ainakaan tee mitään järkevää. Toteuta koodin kommenteissa osoitettuihin paikkoihin tarpeelliset osiot jotta saat luotua tehtävänannossa vaaditut asiat. Testaa client- ja server -ohjelmia. Voit suorittaa testit yhdellä koneella käynnistämällä serverin omassa terminaali-ikkunassa ja clientin toisessa, IP-osoitteen ollessa localhost eli 127.0.0.1. Toki testaaminen useammalla koneella oikeasti verkon yli on aina jännempää. Moodle -ympäristön keskusteluosio on käytössä toteutukseen liittyen ongelmien ratkaisuun ja muihin kysymyksiin. Palauta toimivat kirjasto, client sekä server -komponentit BitBucketin työtilaasi kuten kurssilla on ohjeistettu, deadlineen mennessä. Sivu 5 / 6
Huolehdi että käyttämäsi makefile:t tulevat myös repositoryyn, lähdekooditiedostojen lisäksi Huolehdi että binääritiedostot eivät tule repositoryyn Testaa että repositorystä haettu ohjelma kääntyy neitseellisessä ympäristössä (eli että repository sisältää kaiken mitä pitääkin, muttei mitään muuta) Huolehdi siitä että päivität tarvittaessa kirjaston API:n dokumentaationkin. Happy coding! Sivu 6 / 6