• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Syllabus encryptie
 

Syllabus encryptie

on

  • 434 views

Syllabus cursus encryptie.

Syllabus cursus encryptie.

Projectopdracht voor de Hogeschool van Utrecht. Blijkbaar bedoeld naast het boek "Netwerkbeveiliging en cryptografie".

Statistics

Views

Total Views
434
Views on SlideShare
428
Embed Views
6

Actions

Likes
0
Downloads
4
Comments
0

1 Embed 6

https://twitter.com 6

Accessibility

Categories

Upload Details

Uploaded via as Microsoft Word

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Syllabus encryptie Syllabus encryptie Document Transcript

    • .. .. .. .. .. .. .. .. .. . Patrick Mackaaij, 1057782 Rick van Soest, 1059464 Freerk van Dijk, 1019472 Pieter de Boer, 1024975 Project 11, semester 6 . . Syllabus Encryptie . . . . . Aanvullende informatie bij het boek 1 . . .
    • Berichten in code en geheimschrift. Uit: Hoe werkt dat? The Readers’s Digest NV, Amsterdam, ISBN 90 6407 225 6 Aan de vooravond van de Japanse aanval op Pearl Harbor in december 1941 waarschuwde een schijnbaar onschuldig weerbericht, ‘Oostenwind regen, noordenwind bewolkt, westenwind helder’, de Japanse diplomaten overal ter wereld voor de naderende oorlog. van de Duitse oorlogsvloot konden begrijpen. Zelfs toen de Duitse Admiraliteit het verlies opmerkte, duurde het nog weken voordat zij elk Duits schip van een nieuw codeboek had weten te voorziet. Het verzenden van geheime informatie met gebruikmaking van geheimschrift neemt eveneens een belangrijke Deze boodschap was een van de plaats in. Bij eenvoudigste soorten van codering - geheimschrift zijn de een vooraf opgesteld bericht dat een echte letters van het speciale betekenis heeft voor de alfabet vervangen door ontvangers. andere letters of getallen of symbolen. Morse is eigenlijk ook Soortgelijke boodschappen werden een geheimschrift waarbij elke letter tijdens de Tweede Wereldoorlog in de vorm van combinaties van door de BBC verzonden naar het korte en lange signalen via de radio Franse verzet. Een zin als ‘Romeo (met piepsignalen), de telegraaf of omhelst Julia’ of ‘Benedictine is met seinlampen wordt verstuurd. Bij een zoete likeur’ kan van tevoren een andere vorm van geheimschrift afgesproken informatie bevatten wordt een zogenaamd ‘coderooster’ over het droppen van agenten of gebruikt. Het bericht ‘Vijandelijke voorraden. De eerste regel van een troepen landen 1 december’ kan in gedicht van de Franse schrijver Paul een rooster van pakweg zes Verlaine (‘De lange snikken van de kolommen worden weergegeven, herfstviolen’) bracht het verzet op de waarbij afwisselend van links naar hoogte van de naderende landingen rechts en van rechts naar links is op D-Day. geschreven. De letters worden dan weer in groepjes van zes Bij ingewikkelder codes zijn uitgeschreven, waarbij een diagonale woorden of hele zinnen vervangen lijn door het rooster wordt door andere woorden of zinnen. aangehouden: Verder kunnen onsamenhangende lettergroepen worden gebruikt om een heel woordenboek van woorden en zinnen te creëren. In de letters GYPHC kan bijvoorbeeld de opdracht ‘Zorg voor rugdekking’ schuilgaan. Met zulke groepjes van Het bericht dat wordt verzonden vijf letters, die slechts begrijpelijk zijn voor degene die ze in het juiste luidt dus: DNEELA JIPNEL EJIVKO ADCENN RETDEM codeboek kan opzoeken, kunnen BEENER. lange militaire berichten worden verzonden. Degene die het bericht ontvangt gebruikt eenzelfde rooster bij het Als een codeboek echter in handen van de vijand komt, kan belangrijke ontcijferen. informatie worden onderschept Het nadeel bij dit systeem is dat de zonder dat de verstuurder dat in de frequentie van letters en gaten heeft. In de Eerste lettercombinaties hetzelfde blijft als Wereldoorlog werd het codeboek in de gewone taal. De E is de meest van de Duitse Marine uit het wrak voorkomende letter in het van de lichte kruiser Magdeburg Nederlands, de Q komt zeer weinig gevist, waardoor de Engelsen een groot deel van de geheimste bevelen voor. Wie de code wil ontcijferen, 2 (of ‘BREKEN’), kan er dus van uitgaan dat de meest voorkomende letter voor de E staat. Tijdens de Tweede Wereldoorlog maakte de Duitse regering gebruik van een cryptografisch toestel dat Enigma heette. Telkens wanneer een bepaalde letter werd overgeseind, werd een andere sleutel gebruikt. Elke dag werd een nieuwe instelling gebruikt. Een ploeg Engelse wis- en taalkundigen van de universiteit wist echter in 1940 de code van Enigma te breken. Met de opkomst van de computer zijn de codes veel ingewikkelder geworden, veel moeilijker te breken. Bij complexe programma's worden duizenden berekeningen gebruikt, en zonder kennis van de volgorde van de sleutelopdrachten kost het duizenden jaren om ze te ontcijferen. Tekst bij de afbeelding rechtsbovenin: 'Eenmalig codeblok' Spionnen maken gebruik van kleine codeblokken om geheime boodschappen van hun opdrachtgevers te ontcijferen. Via de radio verzonden, gecodeerde instructies hebben betrekking op getallen van vijf cijfers op een bepaalde bladzijde van het blok. Als het bericht eenmaal ontvangen en ontcijferd is, scheuren ontvanger en verzenden de betreffende bladzijde uit hun blok.
    • Inhoudsopgave INHOUDSOPGAVE................................................................................................................................3 VOORWOORD........................................................................................................................................6 OVERIG CURSUSMATERIAAL...................................................................................................................6 1. INTRODUCTIE...................................................................................................................................7 1.1 WAT IS ENCRYPTIE?.........................................................................................................................7 1.2 WAAROM ENCRYPTIE?......................................................................................................................7 1.2.1 Integriteit, authenticatie...........................................................................................................8 1.3 HOE WERKT ENCRYPTIE?..................................................................................................................8 1.4 ASYMMETRISCH, SYMMETRISCH.......................................................................................................8 1.5 RANDOM GETALLEN.......................................................................................................................10 1.6 HOE WERKT EEN HACKER?.............................................................................................................10 1.7 WAT MAAKT EEN STERK ALGORITME?...........................................................................................12 1.8 HOE VEILIG IS ENCRYPTIE?.............................................................................................................12 1.9 ENCRYPTIE EN NETWERKEN............................................................................................................13 1.20 LITERATUUR.................................................................................................................................14 2. DES......................................................................................................................................................16 2.1 GLOBALE BESCHRIJVING VAN DE LESSTOF.....................................................................................16 2.2 GEDETAILLEERDE BESCHRIJVING VAN DE LESSTOF........................................................................16 3. AES......................................................................................................................................................17 3.1 WAT IS AES?..................................................................................................................................17 3.2 AAN WELKE EISEN MOET AES VOLDOEN?.....................................................................................17 3.3 WELKE ALGORITMEN BEHOREN TOT DE MOGELIJKHEDEN?...........................................................18 3.3.1 MARS......................................................................................................................................19 3.3.2 RC6.........................................................................................................................................19 3.3.3 Rijndael...................................................................................................................................19 3.3.4 SERPENT................................................................................................................................20 3.3.5 Twofish....................................................................................................................................20 3.4 VAN DES NAAR AES.....................................................................................................................20 3.5 LITERATUUR...................................................................................................................................21 4. IDEA....................................................................................................................................................23 4.1 BESCHRIJVING VAN DE LESSTOF.....................................................................................................23 4.2 AFKORTINGEN EN TERMEN UIT HET BOEK......................................................................................23 5. RSA......................................................................................................................................................24 5.1 BESCHRIJVING VAN DE LESSTOF.....................................................................................................24 5.2 AFKORTINGEN EN TERMEN UIT HET BOEK......................................................................................24 6. PGP......................................................................................................................................................26 6.1 BESCHRIJVING VAN DE LESSTOF.....................................................................................................26 6.2 AFKORTINGEN EN TERMEN UIT HET BOEK......................................................................................27 6.3 OPDRACHT PGP PERSONAL INSTALLATIE......................................................................................28 6.4 PGP VIRTUELE HARDDISK..............................................................................................................30 6.4.1 Virtuele harddisk (PGPdisk)...................................................................................................30 6.4.2 Installatie / gebruik van PGP disk..........................................................................................30 6.5 WAT MAAKT EEN GOEDE WACHTZIN?............................................................................................33 6.5.1 Formule Passphrase Security.................................................................................................34 6.6 TIPS UIT DE PGP FAQ....................................................................................................................36 6.6.1 Gebruik de omgevingsvariabele niet......................................................................................36 6.6.2 Randseed.bin is niet geïnfecteerd door een virus...................................................................36 3
    • 6.6.3 Verlies je sleutel en vergeet je wachtzin niet..........................................................................36 6.6.4 De PGP Developer Kit...........................................................................................................36 6.7 LITERATUUR...................................................................................................................................37 7. ENCRYPTIE IN JAVA MET JCA EN JCE...................................................................................39 7.1 BESCHRIJVING VAN DE LESSTOF.....................................................................................................39 7.2 INLEIDING OP JAVA.........................................................................................................................40 7.2.1 De gebruikte Java security API’s...........................................................................................40 7.2.2 JDK 1.3 ten opzicht van JDK 1.2.x.........................................................................................41 7.2.3 Practicumopdrachten.............................................................................................................41 7.2.4 Maak gebruik van een package..............................................................................................41 7.2.5 Standaard methoden...............................................................................................................41 7.2.6 Javacode in het Engels...........................................................................................................41 7.3 RANDOM GETALLEN.......................................................................................................................42 7.3.1 Random getallen met JDK......................................................................................................42 7.3.2 SecureRandom........................................................................................................................42 7.3.3 Self-seeding.............................................................................................................................42 7.3.4 Random data uit keyboard timing...........................................................................................43 7.3.4.1 Implementatie keyboard timer........................................................................................................43 7.3.4.2 Risico’s van de klasse seeder..........................................................................................................45 7.3.5 Implementatie van een progressbar........................................................................................46 7.3.6 Opdracht klasse seeder...........................................................................................................47 7.4 SLEUTELBEHEER.............................................................................................................................47 7.4.1 Werken met sleutels................................................................................................................47 7.4.2 Sleutels aanmaken: sleutelgeneratoren..................................................................................49 7.4.2.1 De sleutelpaargenerator..................................................................................................................49 7.4.2.2 De sleutelgenerator.........................................................................................................................50 7.4.2.3 Algoritmespecifieke instellingen....................................................................................................50 7.4.3 Sleutels overzetten..................................................................................................................51 7.4.3.1 SecretKeySpec................................................................................................................................51 7.4.3.2 SecretKeyFactory...........................................................................................................................52 7.4.3.3 SleutelFabriek.................................................................................................................................54 7.4.4 Sleuteluitwisseling..................................................................................................................54 7.4.5 Identity Sleutelbeheer.............................................................................................................56 7.4.5.1 Sleutelbezitters...............................................................................................................................57 7.4.5.2 De scope van een Identity...............................................................................................................59 7.4.5.3 De system scope beheren: Javakey.................................................................................................59 7.4.6 Keystore Sleutelbeheer...........................................................................................................60 7.4.6.1 KeyStore.........................................................................................................................................61 7.4.6.2 Keytool...........................................................................................................................................63 7.4.7 Opdracht Sleutelbeheer..........................................................................................................64 7.5 AUTHENTICATIE..............................................................................................................................64 7.5.1 Message Digest.......................................................................................................................64 7.5.1.1 Aanmaken van een message digest.................................................................................................65 7.5.1.2 Data invoer voor een message digest..............................................................................................65 7.5.1.3 Digesting........................................................................................................................................65 7.5.1.4 Digest Streams................................................................................................................................66 7.5.1.5 Beveiligde wachtwoord login.........................................................................................................66 7.5.1.6 Dubbele sterkte wachtwoord login..................................................................................................69 7.5.2 Opdracht dubbele sterkte wachtwoord login..........................................................................69 7.5.3 Message Authentication Codes: MACs..................................................................................69 7.5.3.1 MAC aanmaken..............................................................................................................................70 7.5.3.2 MAC datainvoer.............................................................................................................................70 7.5.3.3 Berekenen van de Code..................................................................................................................71 7.5.3.4 Voorbeeld van een MAC................................................................................................................71 7.5.4 Signatures...............................................................................................................................71 7.5.4.1 Aanmaken van een Signature..........................................................................................................73 7.5.4.2 Verifiëren van een Signature..........................................................................................................74 7.5.4.3 De klasse SignedObject..................................................................................................................74 7.5.5 Werken met certificaten..........................................................................................................75 7.5.5.1 Java.security.cert.Certificate...........................................................................................................75 7.5.5.2 Aanmaken van een Certificaat........................................................................................................75 7.5.5.3 Verifiëren van een Certificaat.........................................................................................................76 4
    • 7.5.5.4 X.509 certificaten...........................................................................................................................76 7.5.5.5 Certificate Revocation Lists............................................................................................................78 7.6 ENCRYPTIE......................................................................................................................................79 7.6.1 Stroom- en blokvercijfering...................................................................................................79 7.6.2 Padding...................................................................................................................................79 7.6.3 PKCS#5...................................................................................................................................79 7.6.4 Blokvercijfering modes...........................................................................................................80 7.6.5 Algoritmen..............................................................................................................................80 7.6.6 Cipher.....................................................................................................................................80 7.6.6.1 Verkrijgen van een Cipher..............................................................................................................81 7.6.6.2 Basis informatie..............................................................................................................................82 7.6.6.3 Instellen van een Cipher.................................................................................................................82 7.6.6.4 Een Cipher vullen met gegevens.....................................................................................................84 7.6.7 Familie van Cipher.................................................................................................................87 7.6.7.1 Stroom Cipher................................................................................................................................87 7.6.7.2 javax.crypto.SealedObject..............................................................................................................88 7.6.8 Wachtzin Encryptie.................................................................................................................89 7.6.8.1 Zout maakt zuur..............................................................................................................................89 7.6.9 Opdracht.................................................................................................................................90 7.7 PROVIDER.......................................................................................................................................91 7.7.1 Inleiding Provider...................................................................................................................91 7.7.2 Een simpel voorbeeld van een provider..................................................................................91 7.8 SIGNED APPLETS............................................................................................................................92 7.8.1 Applets....................................................................................................................................92 7.8.2 Werking van een signed applet...............................................................................................93 7.8.3 Ondersteuning.........................................................................................................................93 7.9 EINDOPDRACHT .............................................................................................................................93 7.10 LITERATUURLIJST ........................................................................................................................94 5
    • Voorwoord Voor je ligt de syllabus die je nodig hebt voor het volgen van het van Encryptie. Technische woorden die nog niet eerder zijn voorgekomen in de tekst worden cursief afgedrukt. Engelse termen worden zo min mogelijk gebruikt, maar de Engelse vertaling voor enkele kernbegrippen moeten worden geïntroduceerd daar deze in de literatuur veelvuldig gebruikt worden. De syllabus is gemaakt in het kader van een 6e semester project in het cursusjaar 19992000 aan de Hogeschool van Utrecht door: • Rick van Soest; • Patrick Mackaaij; • Freerk van Dijk; • Pieter de Boer. Wij hopen dat jullie veel aan het interessante materiaal zullen hebben. Wij hebben het leuk gevonden om het bij elkaar te zoeken en te rangschikken. Overig cursusmateriaal Voor deze cursus maak je gebruik van het boek 'Netwerkbeveiliging en cryptografie' van William Stallings, Academic Service 1999 (ISBN 90-395-1105-5). Indien in deze syllabus wordt gesproken over 'het boek', dan duidt dat op het genoemde boek. Let op: De appendices waar naar verwezen wordt in het boek zijn direct achter het hoofdstuk opgenomen. Niet geheel achterin. Deze appendices zijn optioneel, maar worden wel aanbevolen. Achter in het boek vind je overigens een begrippenlijst waar veel termen die te maken hebben met encryptie kort worden uitgelegd. De URL van het boek is http://williamstallings.com/Security2e.html. Op de site zijn correcties op het boek te vinden. Tevens is voor de cursus een CD samengesteld waarop benodigde programmatuur staat. Op de CD vind je ook belangrijke Internetpagina's terug voor het geval ze van Internet afgehaald worden. De URL's van deze Internetpagina's vind je terug in de literatuuropgave. Daarbij staat ook expliciet aangegeven wanneer een URL niet op de CD te vinden is. De site wordt dan te regelmatig van nieuwe informatie voorzien of de tekst is reeds compleet terug te vinden in de syllabus. 6
    • 1. Introductie In dit hoofdstuk worden de grondbeginselen van encryptie uitgelegd. Er wordt bijvoorbeeld antwoord gegeven op de vragen hoe encryptie werkt, waarom encryptie noodzakelijk is wat encryptie precies is. Verschillende soorten encryptie worden genoemd. Voorkennis is voor dit hoofdstuk niet vereist. We leggen de grondbeginselen uit aan de hand van het verhaal van Robin Hood en Marian. Robin wil Marian geheime berichten kunnen sturen, zonder dat de corrupte Sherif van Nottingham deze kan lezen. Robin Hood heeft met Marian een gemeenschappelijke vriend (vertrouwenspersoon), genaamd Little John. Mocht het verhaal je niet bekend voorkomen, dan kun je meer informatie over de legende Robin Hood vinden op Internet. De URL vind je in de literatuuropgave ([1], 'Welcome to the World Wide Robin Hood Society Sherwood'). In het dagelijkse leven ben jij zelf Robin Hood en is de sherif de vijand, de systeembeheerder, een huisgenoot of een hacker. 1.1 Wat is encryptie? Als Robin Hood zijn berichten aan Marian verstuurt via een boodschapper en deze boodschapper geeft de berichten aan de sherif of de sherif pakt de berichten af, dan zijn ze niet meer geheim. Robin en Marian moeten dus een manier verzinnen om berichten zo te versturen dat ze voor derden onleesbaar zijn. Het voor derden onleesbaar maken van het bericht heet encryptie. Bij de ontvangst van het bericht wordt het bericht weer leesbaar gemaakt. Dit heet decryptie. Andere woorden voor encryptie die je verder tegen zult komen in de tekst zijn versleutelen, vercijferen en coderen. Voor decryptie gebruiken we soms ontsleutelen, ontcijferen en decoderen. In de Engelse literatuur wordt het originele bericht plaintext genoemd. De term voor versleutelde tekst is ciphertext. 1.2 Waarom encryptie? Waarschijnlijk ben je in het dagelijkse leven niet zo gevaarlijk bezig als Robin Hood en vraag jij je misschien af waarom je iets met encryptie zou moeten doen. In het begin van dit hoofdstuk werd gewezen op het feit dat de systeembeheerder, een huisgenoot of een hacker je berichten op de computer kan lezen. Ze kunnen deze berichten ook wijzigen of onder jouw naam berichten versturen. En ze hebben geen fysieke toegang nodig tot jouw PC om dat allemaal te doen! We nemen aan dat dit je wat uitmaakt, je post je brief tenslotte ook in een enveloppe en schrijft een bericht niet op een briefkaart. E-mail versturen via Internet daarentegen, komt qua privacy wel op hetzelfde neer. Als extra nadeel valt E-mail niet onder het briefgeheim (artikel 13 van de Grondwet) en is het voor systeembeheerders anno april 2000 dus niet illegaal om andermans E-mail te lezen. Daar komt bij dat E-mail tijdens het transport van zender naar ontvanger langs een aantal computer komt (kijk hiervoor maar eens naar de header van een E-mailbericht) en dus door al deze tussenpersonen kan worden gelezen en gewijzigd. 7
    • Verder is het goed mogelijk dat je een typefout maakt bij het adresseren van een Emailbericht. Dan bestaat er een grote kans dat het bericht bij een algemene beheerder aan de kant van de ontvanger terechtkomt. Het lezen van andermans E-mail kan onder computervredebreuk vallen, als daarbij een wachtwoord geraden of gekraakt wordt. 1.2.1 Integriteit, authenticatie Buiten het feit dat berichten niet zonder meer door derden te lezen zijn, kan encryptie er voor zorg dragen dat het bericht de ontvanger onveranderd bereikt. Dit wordt integriteit (integrity) genoemd. Ook is het mogelijk om met zekerheid vast te stellen dat een bericht van een bepaalde persoon afkomstig is. Dit gegeven wordt authenticatie (authentication) genoemd. 1.3 Hoe werkt encryptie? Robin en Marian spreken samen af alle letters van het alfabet één positie naar rechts door te draaien bij de verzending van een bericht. De 'a' wordt dus een 'b' een het woord 'aap' wordt 'bbq'. Het bericht wordt nu dus onleesbaar verzonden. Aan de ontvangstzijde worden de letters allemaal weer één positie teruggedraaid. De afspraak die Robin en Marian maken wordt het algoritme of, in het Engels, de cipher genoemd. Het aantal posities opschuiven van de letters van het alfabet de sleutel of cipherkey. Cipherkey korten we soms af tot key. Berichten versleuteld met dit algoritme zijn voor een hacker niet erg moeilijk om te achterhalen, te kraken. Als het algoritme bekend is, kan de hacker zien dat er maar 25 mogelijke sleutels zijn en deze allemaal proberen. Toch werd deze methode in de praktijk door bijvoorbeeld Julius Caesar toegepast en kom je hem tegen in nieuwsgroepen op Internet onder de naam ROT-13 (rotation van 13, 13 posities doordraaien dus). In de cursus encryptie maak je kennis met geavanceerdere algoritmen. Uit de vorige alinea zou je kunnen halen dat het algoritme geheim gehouden moet worden om een goed programma voor encryptie te schrijven. Dit lijkt ook een logische gedachte, zij het niet dat programma's gedeassembleerd kunnen worden. Na het schrijven van een programma in een hogere programmeertaal wordt de programmacode gegenereerd voor een bepaalde processor. Mensen die zich verdiepen in deze machine-code kunnen het programma deassembleren. Dit proces staat bekend als reverse-enginering. Kenmerken die wel bijdragen aan een sterk algoritme zijn te vinden in paragraaf 1.7 'Wat maakt een sterk algoritme?'. 1.4 Asymmetrisch, symmetrisch Als Robin en Marian het rotation-algoritme willen gebruiken om geheime berichten te versturen moeten zij dus samen een sleutel afspreken. Anders zou de ontvanger van het bericht alle mogelijke sleutels moeten proberen! Het is natuurlijk mogelijk om deze sleutel tijdens een ontmoeting af te spreken, maar wat nu als zij elkaar nooit kunnen ontmoeten? Ook het continue werken met dezelfde sleutel is niet veilig, daar de sherif wellicht druk doende is een bericht te ontcijferen en de sleutel op een gegeven moment achterhaalt. Een oplossing hiervoor is om de boodschapper, die je beide vertrouwt, een andere sleutel over te laten brengen. Je beschikt dan over een zogenaamd secure channel. Maar als je over een secure channel beschikt, waarom moet je dan nog versleutelen? 8
    • Algoritmen waarbij men aan zowel de zend- als ontvangstkant moet beschikken over dezelfde sleutel staan bekend als symmetrische algoritmen. Voorbeelden van symmetrische algoritmen die tijdens de cursus behandeld worden zijn DES, AES en IDEA. Symmetrische algoritmen worden in de literatuur ook wel conventionele algoritmen genoemd. Er bestaan ook asymmetrische algoritmen. De zender en de ontvanger maken op een bepaalde manier tegelijkertijd m.b.v. één algoritme twee sleutels aan, een publieke (public key) en een geheime (private key). De publieke sleutel wordt door de verzender gebruikt om een bericht te versleutelen. Daarna kan alleen de ontvanger het nog ontcijferen met zijn geheime sleutel. Algoritmen die deze manier van encryptie gebruiken staan het versleutelen met meerdere publieke sleutels tegelijk toe. Een asymmetrisch algoritme wat in de cursus behandeld wordt is RSA. Door de eigen publieke sleutel iedere keer mee te coderen kan de verzender van het bericht dit later zelf nog ontcijferen. De publieke sleutel mag men zonder meer bekend maken aan vriend en vijand. Voor iemand die een versleuteld bericht aan je wil sturen is het zelfs vereist dat deze over de sleutel beschikt. Ook asymmetrische algoritmen hebben hun nadelen: Het aantal mogelijke sleutels moet veel groter zijn dan bij symmetrisch om niet eenvoudig achterhaald te kunnen worden. De sleutellengte wordt bij computers aangegeven in bits. Zie tabel 1 voor een vergelijking van veiligheid tussen symmetrisch en asymmetrisch. Symmetrische sleutellengte Asymmetrische sleutellengte 56 bits 384 bits 64 bits 512 bits 80 bits 768 bits 112 bits 1792 bits 128 bits 2304 bits Tabel 1: vergelijking vereiste sleutellengte tegen brute-force attacks Door de grotere sleutels wordt een asymmetrisch algoritme veel trager dan een symmetrische. De oplossing hiervoor wordt gezocht in het symmetrisch coderen van een bericht waarbij de sleutel bij ieder bericht weer anders is. Deze sleutel wordt vervolgens asymmetrisch gecodeerd en zo wordt het geheel verzonden. Dit wordt een hybride systeem genoemd. In de cursus wordt PGP behandeld, een programma wat gebruik maakt van onder andere IDEA en RSA en wereldwijd gebruikt wordt om E-mail over het Internet te verzenden (PGP kan overigens ook voor versleuteling van bestanden worden gebruikt, zoals je in het hoofdstuk PGP zult lezen). Het is moeilijk vast te stellen of de publieke sleutel die je via-via van iemand krijgt of van het Internet afhaalt, daadwerkelijk van de persoon is van wie je denkt dat hij is. Dit probleem lost men op door sleutels te laten 'tekenen' (digitale handtekening, digital signature) door tussenpersonen en door speciale ontmoetingen tussen allerlei personen te organiseren. Daar Robin Hood en Marian beide Little John vertrouwen, kan deze naar Marian toegaan en haar publieke sleutel persoonlijk ontvangen. Little John tekent ervoor dat deze sleutel echt van Marian is en Robin Hood vertrouwt hem. 9
    • Ook is het mogelijk om de publieke sleutel bijvoorbeeld via de telefoon te verifiëren, maar dan moet men de stem van de verzender kunnen herkennen. 1.5 Random getallen Een belangrijk technisch gegeven is nog niet ter sprake gekomen. Om een bericht te versleutelen kan een sleutel gebruikt worden. Als sleutel kan van alles worden gekozen. Je kunt zelf een sleutel kiezen, bijvoorbeeld een woord of een reeks getallen. Maar om een versleuteling echt veilig te maken is een sleutel nodig die bij niemand bekend is en die ook niet te onthouden is. Het is dus handig om bijvoorbeeld de computer een willekeurige sleutel te laten kiezen. Maar hoe kiest een computer een willekeurige sleutel? Dit zal de computer doen aan de hand van een willekeurig (random) getal. Helaas produceert de computer zulke getallen niet zo willekeurig. Een computer maakt namelijk gebruik van een zogenaamde Pseudo Random Number Generator voor het genereren van willekeurige getallen. Een PRNG leidt zijn willekeurige getallen namelijk af van bijvoorbeeld de interne klok (tijd) van de computer. Al gaat het hier om milliseconden of korter, als een hacker ongeveer op de hoogte is van de datum/tijd waarop jij je sleutel hebt gegenereerd, hoeft de hacker aanzienlijk minder sleutels te proberen tot hij de juiste heeft. Een oplossing voor dit probleem is specifieke, dure, hardware aan te schaffen om willekeurige getallen aan te maken. In de praktijk is dit voor particulier gebruik en kleine bedrijven niet betaalbaar. PGP, het programma wat in de cursus wordt behandeld, laat de gebruiker voor het genereren van het sleutelpaar (publiek en geheim) op het toetsenbord typen (de gebruiker moet niet steeds dezelfde letter intypen met regelmaat). Daar de gebruiker niet regelmatig zal typen (dit wordt in zeer kleine tijdseenheden gemeten), kan dit gebruikt worden als invoer voor de random-getallen. De volgende random-getallen die PGP nodig heeft haalt het programma onder andere uit tussentijden tussen het gebruik van de harddisk. Er staat een bestand op de harde schijf wat continu veranderd wordt. 1.6 Hoe werkt een hacker? In deze paragraaf worden enkele manieren opgesomd waarvan een hacker gebruik kan maken om een systeem illegaal binnen te dringen. Het is natuurlijk niet de bedoeling dat je ze zelf gaat toepassen, maar het geeft je inzicht in de manier waarop je 'aangevallen' kunt worden. Misschien kan je je er met deze aanwijzingen tegen verdedigen. • Leer het systeem kennen Probeer verbinding met het systeem te maken via utilities als Telnet en FTP. Meestal slaagt deze poging niet, maar je weet in ieder geval welke software er draait. • Controleer bekende veiligheidsgaten Wanneer je weet welke software er draait kun je op Internet kijken of er bekende fouten in deze software aanwezig zijn. Deze zogenaamde 'exploits' kun je vervolgens uitbuiten, tenzij de systeembeheerder updates netjes heeft uitgevoerd. • Probeer wachtwoorden te sniffen Sniffen houdt in dat je al het netwerkverkeer wat over de kabel gaat analyseert. Hier zijn programma's voor. Als loginnamen en wachtwoorden zonder encryptie het netwerk over gaan, kun je ze op deze manier achterhalen. Dit gebeurt niet (meer) met netwerkbesturingssystemen zoals Windows NT en Novell Netware, maar veel applicatieprogrammeurs gaan dezelfde fout in (bijvoorbeeld Bomas 3.0 van Roccare). 10
    • • Probeer te spoofen Veel machines zijn zo ingesteld dat ze voor bepaalde zaken enkel machines met een bepaald netwerkadres of IP-adres toelaten. Dit is namelijk eenvoudig in te stellen. Met spoofen neem je dat adres over. Je moet hiervoor wel fysiek vlak bij de machine zitten die je nadoet. • Login spoofing Bij deze methode zorgt de hacker voor een programma wat lijkt op het loginprogramma wat de gebruiker gebruikt. Na het invoeren van de loginnaam en wachtwoord krijgt de gebruiker een foutmelding. De gebruiker denkt een typefout te hebben gemaakt. Het programma slaat de loginnaam en het corresponderende wachtwoord op en schakelt over naar het échte login programma (zie [10], 'Passwords -- Strengths and Weaknesses'). • Trojan horses Stuur de gebruiker van een systeem een programma toe wat een server bevat waar jij toegang toe hebt, zoals Back Orifice. Als de gebruiker het programma start kun jij alles met de PC doen wat je wilt. • Replay-attack Vang een gecodeerd packet (deel van een bericht) op en stuur dit vervolgens opnieuw. De PC van de ontvanger van het packet kan vervolgens vastlopen of andere ongewenste reacties geven (zie [11], paragraaf 13.3 boek 'Authenticatie-header'). • Vraag de gebruiker om het wachtwoord Een van de meest eenvoudige methoden om achter het wachtwoord te komen is het gewoon te vragen aan de gebruiker. Door zich voor te doen als systeembeheerder is dit een succesvolle methode. Een variant op deze methode is het sturen van een emailbericht naar een gebruiker met het verzoek het wachtwoord te wijzigen naar een voor de hacker bekend wachtwoord. Uiteraard moeten gebruikers op de hoogte zijn van het feit dat systeembeheerders e.d. nooit om hun wachtwoord vragen en dat zij hun wachtwoord altijd voor zichzelf dienen te houden (zie [10], 'Passwords -Strengths and Weaknesses'). Verder nog enkele manieren die een hacker gebruikt om een encryptie te kraken: • Brute-force search Een hacker kan domweg alle mogelijke sleutels gaan proberen. Rond 1990 werd gedacht dat dit onmogelijk was voor bijvoorbeeld DES, daar er 1017 mogelijkheden waren. Tegenwoordig zijn computers sneller en worden ze parallel ingezet voor dergelijke pogingen. Toch blijft brute-force de traagste methode om sleutels te achterhalen. • Dictionary search Vaak gebruikt een gebruiker als wachtwoord een naam van een familielid, bekend persoon of huisdier. Als wachtzin wordt gekozen voor bekende zinnen zoals bijvoorbeeld spreekwoorden of Murphy's Law. Door deze allemaal in een groot bestand te zetten samen met een woordenboek kan de tijd om een sleutel te vinden drastisch worden verminderd. • Ciphertext-only attack Als de hacker beschikt over ciphertext en hij weet wat de originele tekst was, dan kan hij de tekst net zo lang coderen tot hij de ciphertext weer heeft. De sleutel is dan gevonden. • Known-plaintext attack Zie 'Ciphertext-only attack', maar dan andersom. 11
    • 1.7 Wat maakt een sterk algoritme? Een sterk, modern algoritme moet: • niet geheim gehouden worden, maar moet openbaar zijn en te controleren zijn door experts Makers van encryptiesoftware geven soms aan dat het algoritme geheim moet blijven omdat deze anders eenvoudig gekraakt zou kunnen worden. Maar hackers kunnen een programma eenvoudig de-assembleren en het algoritme ontdekken. • een grote sleutellengte (in bits) gebruiken Een grotere sleutellengte geeft meer mogelijke sleutels en dus duurt het langer om de juiste te vinden. • ciphertext produceren die willekeurig aandoet voor alle statistische testmethoden Dit heeft te maken met aanvallen op een bepaalde taal. Bepaalde letters komen statistisch gezien binnen een bepaalde taal meer voor dan andere letters. Door dit te vergelijken met statistische uitkomsten van ciphertext kan op deze manier eenvoudiger gekraakt worden. Dit moet dus voorkomen worden. • resistent zijn tegen alle bekende aanvallen Als van een algoritme op een bepaalde manier sneller alle sleutels kunnen worden getest, moet het algoritme daarop worden aangepast. 1.8 Hoe veilig is encryptie? Mocht je na dit inleidende hoofdstuk een veilig gevoel gekregen hebben en denken dat je met een goede encryptie veilig bent, dan moeten we je teleurstellen. Er zijn nog zaken waar je rekening mee moet houden, zoals: • slordigheid van jezelf Een sleutel uit je hoofd leren is niet aan te raden, derhalve worden sleutels bij een programma als PGP zelf ook gecodeerd en dan opgeslagen op de harde schijf. Het wachtwoord (bij PGP zelfs een wachtzin) waarmee je de sleutel codeert moet je dan niet op je monitor plakken of kenbaar maken aan anderen! • een sterk wachtwoord of sterke wachtzin Om je tegen dictionary-search attacks te beschermen zorg je voor een veilige wachtzin bij PGP. Meer informatie hierover in 'The passphrase FAQ' van Randall T. Williams of bij 'Reinholds Diceware website'. 'The passphrase FAQ' wordt ook nog behandeld in het hoofdstuk PGP. • slordigheid van de ontvanger De ontvanger moet er zorg voor dragen dat het door jou gecodeerde bericht niet gedecodeerd beschikbaar is op zijn computer of uitgeprint op papier. • diefstal van je geheime sleutel Als je geheime sleutel van bijvoorbeeld PGP gestolen wordt (kan door een hacker die op je harddisk bestanden kan lezen), heb je ook een probleem. Het hoeft geen probleem te zijn als je een sterk wachtwoord had, maar meestal hebben mensen dit niet en kan een hacker een dictionary-attack uitvoeren. De geheime sleutel van PGP kan bijvoorbeeld op een harddisk opgeslagen worden, waarna de PC gestolen wordt… Aan justitie hoef je overigens je geheime sleutel niet te overhandigen, dit wordt afgeschermd door de regel dat je niet tegen jezelf hoeft te getuigen. 12
    • • het Amerikaanse exportverbod De Amerikaanse regering beschouwt encryptie-algoritmen en programmatuur als munitie en stelt uit dat oogpunt zware eisen aan de export daarvan. Als de Amerikaans regering export van een bepaald algoritme met een bepaalde sleutellengte toestaat, wordt dit door cryptoanalysten opgevat als teken dat dit door hen snel te ontcijferen is. Overigens is de auteur van PGP, Philip Zimmermann bij het Amerikaanse congres bezig om te proberen het exportverbod te versoepelen (zie 'The comp.security.pgp FAQ, Appendix III - Testimony of Philip Zimmermann to Congress'). • swappen van Operating Systems Na het intypen van je wachtwoord kan een Operating System als Windows '95 of Unix besluiten het geheugen te swappen. Het wachtwoord komt dan niet-gecodeerd in de swapfile te staan. Als je je hier zorgen over maakt moet je op zoek naar programmatuur die je wachtwoord uit de swapfile van het OS haalt (zie 'The comp.security.pgp FAQ, question 3.19'). • vooruitgang in de wiskunde, cryptoanalyse en rekenkracht van computers Een algoritme als RSA leunt sterk op de moeilijkheid van het ontbinden in factoren (zie het hoofdstuk over RSA). Mocht dit wiskundig eenvoudiger worden, dan is het algoritme van RSA niet meer veilig. Ook cryptoanalysten en hackers worden steeds slimmer in het zoeken van oplossingen voor dit soort problemen. Men bundelt bijvoorbeeld computers samen om 'het probleem' parallel op te lossen. Tot slot is de toenemende rekenkracht van computers interessant daar snellere computers sneller alle opties kunnen proberen. • Tempest monitoring Het is mogelijk om met geavanceerde apparatuur op ruime afstand (zeker tot 100 meter) buiten de ruimte waar elektronische apparatuur staat opgesteld de elektromagnetische straling van deze apparatuur op te vangen. Deze straling kan vervolgens worden opgeslagen en later worden omgezet naar het originele beeld. De meting kan niet worden waargenomen. TEMPEST staat overigens voor Transient ElectroMagnetic PulsE STandard en is al in 1985 ontdekt door de Nederlander Wim van Eck (zie 'TEMPEST monitoring in the real world'). • Echelon Echelon is een netwerk wat is opgezet door de NSA (National Security Agency in Amerika). Er wordt samengewerkt met geheime diensten in andere landen, zoals de GCSB (Government Communications Security Bureau in Nieuw Zeeland). Wereldwijd wordt e-mail, telefoon-, telex- en faxverkeer met computers 'afgeluisterd'. Er wordt gezocht naar trefwoorden die de aangesloten geheime diensten aanleveren. Als een trefwoord gevonden wordt, krijgt de geheime dienst die dat trefwoord ingaf een kopie van het bericht inclusief data als tijdstip, zender en ontvanger. Echelon is geen fictie, bewijst het rapport wat is opgesteld in opdracht van het Europese Parlement (zie 'Codenaam Echelon: An Appraisal of Technologies of Political Control'). 1.9 Encryptie en netwerken Vertrouwelijkheid, integriteit en authenticatie zijn ook van belang op een netwerk: Vertrouwelijkheid Hackers zouden de verbinding af kunnen luisteren (door te sniffen). Gecodeerde gegevens moeten eerst nog gedecodeerd worden en vormen dus een belangrijke drempel. 13
    • Integriteit Het is altijd belangrijk dat gegevens die tussen computers onderling worden uitgewisseld niet gewijzigd worden. Authenticatie Tussen server en werkstation kan met authenticatie voorkomen worden dat een hacker een werkstation spooft. 1.20 Literatuur 1. Welcome to the World Wide Robin Hood Society Sherwood http://www.robinhood.ltd.uk/ Engelstalige site over de legende Robin Hood. In de syllabus wordt de legende gebruikt als verhaal bij de voorbeelden. Deze URL staat niet op de CD. 2. Snake Oil Warning Signs: Encryption Software to Avoid http://www.interhack.net/people/cmcurtin/snake-oil-faq.html Engelstalig document wat enkele zaken beschrijft waar men op moet letten om geen slechte encryptie-software aan te schaffen. Een goede vertaling voor Snake Oil is kwakzalverij. 3. The comp.security.pgp FAQ http://www.cam.ac.uk.pgp.net/pgpnet/pgp-faq/ Engelstalige FAQ waarin veel met betrekking tot het programma PGP uit de doeken wordt gedaan. 4. TEMPEST monitoring in the real world http://www.thecodex.com/c_tempest.html Engelstalig document waarin wordt uitgelegd wat TEMPEST is, hoe het werkt en wie het gebruikt of gebruiken kan. 5. Computer Security Basics http://www.auburn.edu/~youngd2/topics/security1.html Engelstalig document waarin beschreven wordt hoe een hacker een systeem kan binnendringen en wat een systeembeheerder kan doen om dat te voorkomen. Dit document is tijdens het project van Internet verwijderd, maar staat wel op CD. 6. Cryptography FAQ http://www.faqs.org/faqs/cryptography-faq/part01/ Engelstalige FAQ over cryptografie in het algemeen. 7. The passphrase FAQ, version 1.04 http://www.stack.nl/~galactus/remailers/passphrase-faq.html Engelstalige FAQ over het maken van een goede wachtzin voor PGP. 8. The Diceware Passphrase Home Page http://www.diceware.com/ Engelstalige site met verwijzingen naar een aantal sites die te maken hebben met het maken van goede wachtzinnen voor PGP, waaronder ' The passphrase FAQ'. Tevens een voorstel voor het maken van een wachtzin door dobbelstenen te gooien. 9. Codenaam Echelon: An Appraisal of Technologies of Political Control http://www.nrc.nl/W2/Lab/Echelon/stoa1jan1998.html Site van NRC Handelsblad waar een dossier van artikelen wordt opgebouwd die betrekking hebben op Echelon. De link zelf bevat een rapport van zo'n 140 bladzijden wat in opdracht van het Europees Parlement is opgesteld waarin onder andere het bestaan van Echelon bevestigd wordt. 14
    • 10. Passwords -- Strengths and Weaknesses http://www.vtac.org/Tutorials/password.html Engelstalig document waarin het belang van de goede keuze van een wachtwoord wordt benadrukt. Tevens worden enkele suggesties gedaan om een beter wachtwoord te kiezen en wordt verteld hoe hackers achter wachtwoorden kunnen komen. 11. Boek 'Netwerkbeveiliging en cryptografie' van William Stallings, Academic Service 1999 (ISBN 90-395-1105-5) Paragraaf 13.3, 'Authenticatie-header' In deze paragraaf wordt de opbouw van een IP-packet beschreven. De replay-attack en de bescherming daartegen is te vinden onder het kopje 'Anti-replay service'. 15
    • 2. DES 2.1 Globale beschrijving van de lesstof DES wordt in het boek behandeld in hoofdstuk 3 (Conventionele encryptie: moderne technieken). In eerste instantie wordt het principe uitgelegd aan de hand van Simplified DES (S-DES). Vervolgens gaan we in op de vercijfering van data. Hierbij worden onderwerpen als blok-, stroom- en Feistel-vercijfering besproken. Na deze grondbeginselen gaan we verder in op DES en de kracht van DES. Een sterkere variant van DES, Triple DES, komt aan bod in paragraaf 4.1. 2.2 Gedetailleerde beschrijving van de lesstof Hieronder wordt in hoofdlijnen verteld wat aan bod komt in de bovengenoemde hoofdstukken. Paragraaf 3.1 (Simplified DES (S-DES)) Deze paragraaf beschrijft het vereenvoudigde DES-encryptie algoritme. Dit algoritme is niet zozeer veilig maar wel uitermate geschikt voor educatieve doeleinden. Het is DES met veel minder parameters. In deze paragraaf wordt ook S-DES sleutelgeneratie en SDES encryptie behandeld. Hierna wordt de relatie met DES bekeken. Paragraaf 3.2 (De principes van blokvercijfering) Deze paragraaf behandelt drie vormen van vercijfering. Deze drie vormen zijn stroomvercijfering, blokvercijfering en feistel-vercijfering. Van de eerste twee wordt enkel het principe weergegeven. Van de laatste, feistel-vercijfering wordt ook de vercijferingsstructuur en het decryptie-algoritme behandelt. Paragraaf 3.3 (De Data Encryption Standaard (DES)) Deze paragraaf behandelt DES tot in het kleinste details. Ten behoeve van de cursus is het niet nodig alle detail van DES uit het hoofd te weten. Het is echter wel vereist dat het in deze paragraaf behandelde principe duidelijk is. Paragraaf 3.4 (De kracht van DES) Deze paragraaf geeft kort aan hoe DES groot is geworden en hoe de toekomst van DES eruit ziet. Over de toekomst van DES wordt geschreven dat het tijd is om naar alternatieven voor conventionele encryptie te zoeken. Hiermee is men reeds bezig. De vervanger zal Advanced Encryption Standard (AES) gaan heten. Het algoritme achter AES is echter nog niet bepaald en wordt in het boek ook niet behandeld. In het volgende hoofdstuk, AES, gaan we hier verder op in. Paragraaf 3.6 (De principes van het ontwerpen van blokvercijferingen) Deze paragraaf verschaft informatie over het ontwerpen van blokvercijferingen. Verder wordt hier de term S-box geïntroduceerd en toegelicht. Paragraaf 3.7 (Werkmodes voor blokvercijfering) Deze paragraaf beschrijft vier manieren (modes) van blokvercijfering en hun karakteristieke toepassigen. Onder deze vier modes bevinden zich de Electronic Codebook-mode (ECB), de Cipher Block Chaining-mode (CBC), de Cipher Feedbackmode en de Output Feedback-mode. Paragraaf 4.1 (Triple DES) In deze paragraaf worden varianten van DES besproken. Hieronder verstaan we Double DES en Triple DES. Dus dubbele en driedubbele DES-encryptie. Deze varianten komen voor met een variabel aantal sleutels ook dit wordt behandeld. 16
    • 3. AES AES staat voor Advanced Encryption Standard. Het is de opvolger van DES. DES is al meer dan 20 jaar in gebruik (zie [1], 'Request for Candidate Algorithm Nominations for the AES') en wordt gezien de huidige stand van de techniek niet meer als veilig beschouwd. Daarbij speelt met name het beperkte aantal mogelijke sleutels een rol. AES staat helaas óók voor Automated Export System, een systeem om douaneafhandelingen te automatiseren. Let hierop als je meer informatie over AES probeert te vinden op Internet. In dit hoofdstuk vertellen we kort wat AES is en hoe het algoritme tot stand is gekomen. Een aantal algoritmen die tot AES verheven kunnen worden, worden kort besproken. 3.1 Wat is AES? De National Institute of Standards and Technology (NIST) heeft in 1997 een wereldwijde oproep gedaan naar een algoritme wat DES kan opvolgen (zie [1], 'Request for Candidate Algorithm Nominations for the AES'). Iedere particulier en ieder bedrijf over de hele wereld mocht reageren op de oproep om een nieuwe standaard te introduceren om gevoelige 'unclassified' informatie van de regering te beschermen. De kandidaat-algoritmen worden, indien mogelijk met de Amerikaanse export-restricties, gepubliceerd. Voor de meest recente informatie m.b.t. het Amerikaanse export-verbod voor encryptie-algoritmen, zie [10], 'The Homepage for the Bureau of Export Administration'. 3.2 Aan welke eisen moet AES voldoen? Mogelijke algoritmen moesten aan een aantal specifieke eisen voldoen, te weten: • het algoritme moet symmetrisch zijn; • het algoritme moet als block cipher te implementeren zijn; • het algoritme moet key-block combinaties aan kunnen van 128-128, 192-128 en 256128 bits. Ook houdt NIST rekening met aspecten als: • Veiligheid (security) Het algoritme moet wiskundig onderbouwd kunnen worden en uiteraard moeilijk te kraken zijn. • Kosten (costs) Het algoritme moet vrij beschikbaar worden gesteld, zodat het ook door de publieke sector kan worden gebruikt èn het moet efficiënt met bronnen van de computer omgaan. • Implementatie (algorithm and implementation characteristics) Het algoritme moet eenvoudig te implementeren en bij voorkeur flexibel zijn (met parameters in te stellen), zodat het voor een breed scala aan toepassingen te gebruiken is. De exacte eisen zijn te vinden in [1], 'Request for Candidate Algorithm Nominations for the AES'. 17
    • 3.3 Welke algoritmen behoren tot de mogelijkheden? In 1998 maakte NIST bekend dat 15 algoritmen geaccepteerd waren voor de eerste selectieronde. Cryptografen over de hele wereld werden uitgedaagd om het algoritme te beoordelen op kenmerken als veiligheid en efficiëntie. NIST heeft op basis van deze beoordelingen een keuze gemaakt voor de volgende vijf algoritmen: 1. MARS - IBM (zie [2], 'The MARS cipher'); 2. RC6 - RSA Laboratories (zie [3], 'RSA Laboratories | Advanced Encryption Standard'; 3. Rijndael - Joan Daemen en Vincent Rijmen uit België (zie [4], 'The Rijndael Page'; 4. Serpent - Ross Anderson, Eli Biham en Lars Knudsen uit Noorwegen (zie [5], 'Serpent home page'; 5. Twofish - Counterpane Internet Security Inc (zie [6], 'Twofish: A New Block Cipher'. De naam van het algoritme wordt in bovenstaande opsomming gevolgd door de inzender(s). De site waarnaar verwezen wordt bevat tevens de door NIST vereiste informatie en documentatie, zoals gevraagd in [1], 'Request for Candidate Algorithm Nominations for the AES'. Na een tweede selectieronde worden (we spreken anno 2000) in de zomer van 2001 één of meerdere van deze algoritmen tot AES verheven (de einddatum voor AES ligt niet vast, zie [1], 'Request for Candidate Algorithm Nominations for the AES'). Over het aantal AES-algoritmen wordt nog gediscussieerd, zoals te lezen in [7], 'Round 2 Discussion Issues for the AES Development Effort'. De inzenders van de vijf overgebleven algoritmen geven allen aan de voorkeur te hebben voor één standaard, zoals zij aangeven in hun statements (zie PDF-bestanden [11, 12, 13, 14 en 15], resp. 'IBM Comments', 'RC6 as the AES', 'Rijndael for AES', 'The Case for Serpent' en 'Comments on Twofish as an AES Candidate'). Het AES-algoritme is tijdens het schrijven van deze syllabus nog niet bekend. De huidige status is dat de auteurs van de vijf algoritmen, samen met het publiek, de algoritmen beoordelen (zie wederom [11, 12, 13, 14 en 15]). Vervolgens heeft NIST het laatste woord. Voor de meest recente informatie m.b.t. de status van AES kun je terecht bij [8], 'Advanced Encryption Standard (AES) Development Effort'. NIST geeft overigens duidelijk aan dat algoritmen die wel meegedaan hebben aan de AES-competitie, maar niet tot AES verheven werden, niet per definitie slecht zijn. Ze voldoen niet aan enkele door NIST gestelde eisen of één van de andere algoritmen voorziet beter in een bepaalde eis. Zie [9], 'NIST's AES Round 1 Report' voor de beredenering achter het niet promoveren van een bepaald algoritme naar de tweede ronde. Hieronder bespreken we kort de voor- en nadelen van de verschillende algoritmen [9], 'NIST's AES Round 1 Report'. De voor- en nadelen m.b.t. smart cards worden buiten beschouwing gelaten. 18
    • 3.3.1 MARS Voordelen: • grote veiligheidsmarge; • werkt snel op 32-bits platformen die 32-bits rotatie- en vermenigvuldiging ondersteunen; • ondersteunt grote sleutels, tot zo'n 1248 bits. Nadelen: • de snelheid wordt beduidend minder op platformen die de 32-bits ondersteuning niet verlenen; • het algoritme zit ingewikkeld in elkaar. 3.3.2 RC6 Voordelen: • werkt snel op 32-bits platformen die 32-bits rotatie- en vermenigvuldiging ondersteunen; • eenvoudig algoritme; • opvolger van een bekend algoritme, RC5 [16], paragraaf 4.4 boek 'RC5'; • ondersteunt grote sleutels, tot zo'n 1248 bits; • compleet in te stellen (parameters). Nadelen: • kleine veiligheidsmarge; • de snelheid wordt beduidend minder op platformen die de 32-bits ondersteuning niet verlenen. 3.3.3 Rijndael Voordelen: • presteert goed (snel) op verschillende platformen; • goede veiligheidsmarge; • kan met parallel-werkende hardware gebruikt worden; • werkt met andere blok-formaten in stappen van 32-bits. Nadelen van dit algoritme zijn op het moment van schrijven nog niet gevonden. Uit de diverse stukken m.b.t. de selectie van AES maken wij op dat Rijndael een zeer goede kans maakt tot AES verheven te worden. 19
    • 3.3.4 SERPENT Voordelen: • grote veiligheidsmarge; • kan met parallel-werkende hardware gebruikt worden; • goed beschermd tegen bekende aanvallen. Nadelen: • traag op andere platformen. 3.3.5 Twofish Voordelen: • grote veiligheidsmarge; • presteert goed (snel) op verschillende platformen; • kan met parallel-werkende hardware gebruikt worden; • gedeeltelijk in te stellen (parametiseerbaar); • sleutelformaten tot 256-bits worden ondersteund. Nadelen: • ingewikkeld te analyseren; • het ingewikkelde ontwerp heeft vraagtekens opgeworpen. 3.4 Van DES naar AES DES is een afgeslankte versie van het door IBM ontworpen algoritme 'LUCIFER'. Het werd in 1977 tot standaard verheven. Reeds in die tijd werden er opmerkingen gemaakt over de beperkte sleutellengte (56 bits). DES zou aan te vallen zijn m.b.v. brute-force attacks. Delen van de interne structuur van DES werden als militair geheim bestempeld, wat door het publiek werd opgevat als een teken dat DES door de NSA snel te kraken zou zijn [17], paragraaf 3.3 boek 'De Data Encryption Standard (DES)'. De tijd is nu daar dat DES met relatief weinig moeite gekraakt kan worden. NIST is op zoek naar een vervanger voor DES die qua beveiliging minimaal overeen moet komen met Triple DES [1], 'Request for Candidate Algorithm Nominations for the AES'. Het nieuwe algoritme moet efficiënter werken dan het Triple DES algoritme (zie [18], paragraaf 4.1 boek 'Triple DES'). Tevens wordt er rekening gehouden met de mogelijkheid om het algoritme op 8-bits machines te gebruiken. Welk algoritme tot AES zal worden gekozen is op het moment van schrijven nog niet bekend. NIST verwacht medio 2001 de selectie rond te hebben, maar de einddatum staat niet vast. 20
    • 3.5 Literatuur 1. Request for Candidate Algorithm Nominations for the AES http://csrc.nist.gov/encryption/aes/pre-round1/aes_9709.htm De originele, Engelstalige, uitnodiging van NIST voor kandidaten voor AES. 2. The MARS cipher http://www.research.ibm.com/security/mars.html Officiële IBM-homepage (Engelstalig) m.b.t. het MARS-algoritme en AES. Deze URL staat niet op de CD. 3. RSA Laboratories | Advanced Encryption Standard http://www.rsasecurity.com/rsalabs/aes/ Officiële RSA-homepage (Engelstalig) m.b.t. het RC6-algoritme en AES. Deze URL staat niet op de CD. 4. The Rijndael Page http://www.esat.kuleuven.ac.be/~rijmen/rijndael Officiële homepage van Vincent Rijmen (Engelstalig) m.b.t. het Rijndael-algoritme en AES. Deze URL staat niet op de CD. 5. Serpent home page http://www.cl.cam.ac.uk/~rja14/serpent.html Officiële homepage van Ross Anderson (Engelstalig) m.b.t. het SERPENT-algoritme en AES. Deze URL staat niet op de CD. 6. Twofish: A New Block Cipher http://www.counterpane.com/twofish.html Officiële Counterpane-homepage (Engelstalig) m.b.t. het Twofish-algoritme en AES. Deze URL staat niet op de CD. 7. Round 2 Discussion Issues for the AES Development Effort http://csrc.nist.gov/encryption/aes/round2/Round2WhitePaper.htm Engelstalig document waarin verschillende aspecten m.b.t. de keuze van het AESalgoritme aan de orde worden gesteld (o.a. het aantal algoritmen en de afweging tussen snelheid en veiligheid). 8. Advanced Encryption Standard (AES) Development Effort http://csrc.nist.gov/encryption/aes/ Officiële, Engelstalige, site van NIST met up-to-date informatie m.b.t. de voorgang van AES. 9. NIST's AES Round 1 Report http://csrc.nist.gov/encryption/aes/round1/r1report.htm Engelstalig verslag van de eerste selectieronde voor AES. In het verslag wordt o.a. uitgelegd welke algoritmen om welke reden gepromoveerd werden naar de tweede ronde. 10. The Homepage for the Bureau of Export Administration http://www.bxa.doc.gov/ Engelstalige homepage van de Amerikaanse BXA, verantwoordelijk voor het exportverbod op encryptie. 11. IBM Comments http://csrc.nist.gov/encryption/aes/round2/conf3/papers/mars-statement.pdf Engelstalig statement waarin IBM beredeneert waarom MARS tot AES verheven moet worden. 21
    • 12. RC6 as the AES http://csrc.nist.gov/encryption/aes/round2/conf3/papers/rc6-statement.pdf Engelstalig statement waarin RSA Laboratories beredeneert waarom RC6 tot AES verheven moet worden. 13. Rijndael for AES http://csrc.nist.gov/encryption/aes/round2/conf3/papers/rijndael-statement.pdf Engelstalig statement waarin Joan Daemen en Vincent Rijmen beredeneren waarom Rijndael tot AES verheven moet worden. 14. The Case for Serpent http://csrc.nist.gov/encryption/aes/round2/conf3/papers/serpent-statement.pdf Engelstalig statement waarin Ross Anderson, Eli Biham en Lars Knudsen beredeneren waarom SERPENT tot AES verheven moet worden. 15. Comments on Twofish as an AES Candidate http://csrc.nist.gov/encryption/aes/round2/conf3/papers/twofish-statement.pdf Engelstalig statement waarin Counterpane beredeneert waarom Twofish tot AES verheven moet worden. 16. Boek 'Netwerkbeveiliging en cryptografie' van William Stallings, Academic Service 1999 (ISBN 90-395-1105-5) Paragraaf 4.4, 'RC5' Technische beschrijving van de werking van het RC5 algoritme, de voorloper van de RC6-kandidaat voor AES. 17. Boek 'Netwerkbeveiliging en cryptografie' van William Stallings, Academic Service 1999 (ISBN 90-395-1105-5) Paragraaf 3.3, 'De Data Encryption Standard (DES)', tot DES-encryptie Historische informatie m.b.t. het DES-algoritme, de voorloper van AES. 18. Boek 'Netwerkbeveiliging en cryptografie' van William Stallings, Academic Service 1999 (ISBN 90-395-1105-5) Paragraaf 4.1, 'Triple DES' In deze paragraaf worden varianten van DES besproken (Double- en Triple DES). Deze varianten komen voor met een variabel aantal sleutels. 22
    • 4. IDEA 4.1 Beschrijving van de lesstof IDEA wordt in het boek behandeld in paragraaf 4.2 (International Data Encryption Algorithm). Deze paragraaf beschrijft het principe van IDEA in detail. Dit gebeurt, door achtereenvolgens de ontwerpideeën en de sterke punten aan te stippen. Vervolgens gaat men dieper in op de gebruikte wiskundige operaties. Na deze inleiding volgt het encryptie-algoritme met subkey generatie en het decryptiealgoritme met de bijbehorende subkey generatie. Voor dit hoofdstuk is wiskundige voorkennis van belang. Je moet bekend zijn met: • het berekenen van de vermenigvuldigde inverse modulo. Mocht deze kennis zijn weggezakt, dan kun je je geheugen opfrissen door hoofdstuk 7 (Introductie in de getal theorie) te lezen. Het bepalen van de grootste gemene deler van twee getallen vind je in paragraaf 7.5 (De algoritme van Euclides). Daarnaast geeft deze paragraaf ook uitleg hoe men de vermenigvuldigde inverse kan berekenen. Om de vermenigvuldigde inverse modulo (M) van een getal (G) te berekenen gaat men als volgt te werk: G ^ (M-1) modulo M Let op: bij grote getallen (zoals bij IDEA het geval is) gaat dit erg lang duren! 4.2 Afkortingen en termen uit het boek Er wordt in het boek bij paragraaf 4.2 gesproken over PGP. PGP is een programma wat het mogelijk maakt om gecodeerde berichten te versturen. PGP maakt daarvoor gebruikt van o.a. het IDEA algoritme. PGP komt later in de syllabus aan bod in hoofdstuk 6 en is op dit moment nog niet relevant. DES paragraaf 4.1 (Triple DES) In deze paragraaf worden een aantal varianten van DES besproken, waaronder Double DES en Tripple DES. Dus dubbele en driedubbele encryptie. Verder worden er ook varianten besproken met twee en drie sleutels. 23
    • 5. RSA 5.1 Beschrijving van de lesstof RSA wordt in het boek behandeld in hoofdstuk 6 (Public-key cryptografie). RSA is in tegenstelling tot DES, AES en IDEA een asymmetrisch algoritme. Dit verschil wordt in de inleiding van hoofdstuk 6 uitgelegd. Vervolgens lees je paragraaf 6.1 (Principes van public-key cryptosystemen). Deze paragraaf bespreekt de argumenten waarom symmetrische encryptie algoritmen niet afdoende zijn. In het kort worden de algemene eigenschappen van asymmetrische algoritmen toegelicht en de gebruiksmogelijkheden van public-key cryptografie systemen. Paragraaf 6.2 (De RSA-algoritme) legt de werking van het RSA algoritme uit. Er wordt beschreven hoe met RSA encryptie en decryptie te implementeren is. Tevens wordt besproken op welke manier sleutels voor RSA worden gegenereerd. Ook gaat men dieper in op de zwakke kanten van RSA. Voor deze paragraaf is enige wiskundige voorkennis van belang. Je moet bekend zijn met: • het bepalen van de grootste gemene deler; • het berekenen van de vermenigvuldigde inverse modulo. Mocht deze kennis zijn weggezakt, dan kun je je geheugen opfrissen door hoofdstuk 7 (Introductie in de getal theorie) te lezen. Het bepalen van de grootste gemene deler van twee getallen vind je in paragraaf 7.5 (De algoritme van Euclides). Daarnaast geeft deze paragraaf ook uitleg over hoe men de vermenigvuldigde inverse kan berekenen. Kort: Om de vermenigvuldigde inverse modulo (M) van een getal (G) te berekenen gaat men als volgt te werk: G ^ (M-1) modulo M Let op: bij grote getallen (zoals bij b.v. IDEA het geval is) gaat dit erg lang duren! Sleutelbeheer is een aan asymmetrische algoritmen (zoals RSA) gerelateerd probleem. Het werken met publieke sleutels is namelijk niet zo makkelijk als het lijkt. Meer hierover in paragraaf 6.3 (Sleutelbeheer) van boek. Deze paragraaf gaat in op het beheer en de uitwisseling van de sleutels bij asymmetrische algoritmen. Welke methoden hiervoor bruikbaar zijn en hoe deze werken. 5.2 Afkortingen en termen uit het boek Er worden in het boek bij paragraaf 6.1 afkortingen en termen gebruikt die je nog niet eerder tegen bent gekomen of die je graag nog even wilt nalezen. Deze afkortingen en termen zijn: DES paragraaf 4.1 (Triple DES) In deze paragraaf worden een aantal varianten van DES besproken, waaronder Double DES en Tripple DES. Dus dubbele en driedubbele encryptie. Verder worden er ook varianten besproken met twee en drie sleutels. Diffie Hellman paragraaf 6.3 (Diffie Hellman Sleuteluitwisseling) Deze paragraaf beschrijft het eerste gepubliceerde public-key algoritme. Hoe dit algoritme in detail werkt, wordt in deze paragraaf beschreven. Dit algoritme stelt gebruikers in staat op een veilige manier sleutels uit te wisselen. 24
    • Digitale handtekening paragraaf 10.1 (Digitale handtekening) In deze paragraaf wordt een korte inleiding gegeven op digitale handtekeningen , gevolgd door 2 mogelijke manieren waarop men een digitale handtekening uitwisseling kan organiseren. DSS paragraaf 10.3 (Digital Signature Standard) In deze paragraaf wordt het begrip Digital Signature Standard (DSS) uitgelegd. Verder wordt het achterliggende algoritme Digital Signature Algoritme (DSA) toegelicht. Blokvercijfering paragraaf 3.2 (De principes van blokvercijfering) In deze paragraaf wordt in het begin kort uitgelegd wat onder andere een blokvercijfering is, daarnaast behandelt het kort een stroomvercijfering en de Feistel vercijfering structuur. PGP paragraaf 12.1 (Pretty Good Privacy) Deze paragraaf geeft kort een uitleg wat PGP is, hoe het werkt en nog veel meer. Later in deze cursus (hoofstuk 6) komen we hier uitgebreid op terug. 25
    • 6. PGP 6.1 Beschrijving van de lesstof PGP wordt in het boek behandeld in [10] paragraaf 12.1 boek 'Pretty Good Privacy (PGP)'. Deze paragraaf beschrijft het principe van het computerprogramma PGP tot in detail. Onderwerpen die hierbij aan de orde komen zijn onder andere: • de werking van PGP; • cryptografische sleutels en sleutelringen; • het beheer van public-keys met PGP. Aansluitend hierop lees je uit het boek [11] paragraaf 12.2 boek 'S/MIME'. Deze paragraaf behandelt een andere techniek die naar alle waarschijnlijkheid veel in het bedrijfsleven gebruikt gaat worden. Dit omdat er een aantal essentiële verschillen zijn ten opzicht van PGP. Deze verschillen worden in paragraaf 12.2 naar voren gebracht. Vervolgens lees je in de syllabus verder over het gebruik van: • een virtual harddisk versleuteld m.b.v. PGP; • PGP als plug-in bij Microsoft Outlook en Pegasus (de opdracht van paragraaf 6.3 van deze syllabus); • een wachtzin (passphrase). Tot slot is er in de syllabus een aanvulling op de stof uit het boek opgenomen uit o.a. de FAQ van PGP. 26
    • 6.2 Afkortingen en termen uit het boek Er worden in het boek bij paragraaf 12.1 afkortingen en termen gebruikt die je nog niet eerder bent tegengekomen of die je misschien graag nog even wilt nalezen. In het volgende overzicht kun je zien waar ze in het boek behandeld worden. Deze afkortingen en termen zijn: RSA paragraaf 6.2 (De RSA-algoritme) In deze paragraaf worden de grondbeginselen van RSA uitgelegd. DSS paragraaf 10.3 (Digital Signature Standard) In deze paragraaf wordt het begrip Digital Signature Standard (DSS) uitgelegd. Verder wordt het achterliggende algoritme Digital Signature Algoritme (DSA) toegelicht. Diffie Hellman paragraaf 6.3 (Diffie Hellman Sleuteluitwisseling) Deze paragraaf beschrijft het eerste gepubliceerde public-key algoritme. Hoe dit algoritme in detail werkt, wordt in deze paragraaf beschreven. Dit algoritme stelt gebruikers in staat op een veilige manier sleutels uit te wisselen. CAST-128 paragraaf 4.5 (CAST-128) Deze paragraaf beschrijft een ontwerpprocedure voor symmetrische encryptie algoritme en richt zich verder op de werking van het CAST-128 algoritme. Dit inclusief gebruikte functionaliteiten als substitutieboxen (S-boxen) en deelsleutelgeneratie. IDEA paragraaf 4.2 (International Data Encryption Algorithm) In deze paragraaf worden de grondbeginselen van IDEA uitgelegd. 3DES paragraaf 4.1 (Triple DES) In deze paragraaf worden een aantal varianten van DES besproken, waaronder Double DES en Triple DES. Dus dubbele en driedubbele encryptie. Verder worden er ook varianten besproken met twee en drie sleutels. SHA-1 paragraaf 9.2 (Secure Hash Algoritm) In deze paragraaf wordt de werking van SHA bescheven. Dit houdt in dat de logica achter SHA-1 word behandeld en de compressiefunctie van SHA-1. Verder wordt er in deze paragraaf een vergelijking gemaakt tussen SHA-1 en MD5. Dit omdat beide van MD4 zijn afgeleid. CFB-mode paragraaf 3.7 (De cipher feedback-mode) Deze paragraaf beschrijft een techniek die het mogelijk maakt om blokvercijfering om te zetten in stroomvercijfering. Een vergelijkbare techniek is Output Feedback-mode (OFB). 27
    • 6.3 Opdracht PGP Personal installatie De doelstelling van deze opdracht is je bekend te maken met het programma PGP Personal. We laten je experimenteren met de e-mail plug-in van PGP Personal. Na de installatie van PGP stuur je een gecodeerd bericht naar de docent. 1. Zorg dat je het programma PGP Personal ter beschikking hebt. Dit kan via Internet maar het is sneller om het programma van de studenten-CD te halen. Ter informatie: Hoewel overal vermeld wordt dat PGP gratis is (freeware), gaat deze vlieger niet op voor bedrijven. PGP is enkel gratis als het niet voor commerciële doeleinden wordt gebruikt (zie [5], 'The comp.security.pgp FAQ - Part 1/11'). Meer informatie over de kosten die PGP voor een bedrijf met zich meebrengt is te vinden op de homepage van PGP, http://www.pgp.com/. Houdt er bij het maken van een keuze rekening mee dat er vanaf versie 2.3 een andere manier van versleutelen wordt gebruikt. Dit houdt in dat versies lager dan 2.3 de door de hogere versies gecodeerde berichten niet kunnen decoderen. Oudere versies van PGP zijn compatible met de nieuwe versies. Het verschil met versie 2.3 heeft te maken met het feit dat de versies voor 2.3 gebruik maken van RSA encryptie zonder daarvoor een licentie aangevraagd te hebben. Door berichten op deze manier onleesbaar te maken probeerde men de massa verplicht over te laten schakelen naar de nieuwe versie (zie [5], 'The comp.security.pgp FAQ - Part 2/11'). Ten behoeve van de uitwisseling van berichten tussen verschillende versies van PGP is het raadzaam enkel de algoritmen MD5, RSA en IDEA te gebruiken. 2. Installeer het programma PGP Personal. Indien je hierbij problemen ondervindt bij de installatie of het genereren van een sleutel raden we je aan eerst de website ([6] 'Cog / PGP & Outlook') te bekijken. Deze site kan je door de installatie heen helpen. Bruikbare tips die van de site komen zijn: • zorg voor een sterke wachtzin; • het bestand secring.skr bevat de geheime sleutel en mag derhalve niet in verkeerde handen vallen; • laat berichten die je gedecodeerd hebt niet zomaar ergens liggen; dit was niet de intentie van de afzender van het bericht! Tips voor het gebruik van PGP Personal in combinatie met Microsoft Outlook ([7] 'Outlook 98 and PGP'): • gebruik geen HTML-mail in combinatie met PGP (het HTML-deel wordt niet gecodeerd!); • teken geen mailtjes met attachment als de ontvanger geen PGP gebruikt (attachments worden dan onleesbaar!); • zet geen vinkje bij 'Use PGP/MIME' bij de voorkeuren, dit wordt niet ondersteund in combinatie met Outlook '98; • let erop dat de optie 'Word wrap clear-signed messages at column' een waarde bevat die kleiner dan of gelijk aan de 'word wrap' optie in Outlook '98 is (anders klopt de signature niet). PGP Personal werkt overigens ook met andere programma’s, zoals Microsoft Oulook Express, Eudrora en Pegasus (bij [8] 'QDPGP' kun je een plugin voor de 32-bits versie van Pegasus Mail voor Windows downloaden). 28
    • Ter informatie: Het is tevens mogelijk om een versie voor Linux te downloaden. Houdt er dan wel rekening mee dat in versie 5.0 bij het programmeren een fout is gemaakt. Deze fout zorgt ervoor dat de keyspace aanzienlijk kleiner is. Dit heeft tot gevolg dat jouw sleutel een makkelijkere prooi is voor hackers. 3. Zorg nu dat je over de publieke sleutel van een medestudent en van de docent beschikt (vraag de sleutel van de docent aan de docent). Stuur een gecodeerd bericht naar je medestudent en controleer of hij/zij het bericht heeft ontvangen. Vraag in dit e-mailtje of hij/zij een gecodeerd bericht terugstuurt. 4. Stuur nu een gecodeerd e-mailbericht naar de docent met hierin jouw publieke sleutel (vraag de docent om het e-mail adres waarop de opdacht ingeleverd moet worden). 5. Stuur nu een bericht naar de docent met het antwoord op de volgende vraag: Hoe weet je of een publieke sleutel is van de persoon van wie hij lijkt te zijn? Geef in je antwoord op zijn minst twee methoden om de identiteit van de zender van een bericht vast te stellen. 29
    • 6.4 PGP Virtuele harddisk PGP is al jaren een autoriteit op het gebied van encryptie. We kennen het vooral als email encryptie programma. Van de algoritmen waarvan PGP gebruik maakt zijn nog geen zwakke plekken gevonden. Het programma PGP bestaat echter uit meerdere onderdelen (kijk maar naar de PGP tray). Op één van deze onderdelen gaan we nu verder in. We hebben in de inleiding reeds gesproken over gevaren die onze data bedreigen. Eén van deze gevaren bestond uit het feit dat collegae, huisgenoten en hackers achter je computer gaan zitten en informatie van je systeem halen. De virtuele harddisk van PGP biedt hier een oplossing voor. 6.4.1 Virtuele harddisk (PGPdisk) De PGPdisk. Hiermee kun je virtuele partities creëren die zijn versleuteld. Je kunt deze partitie alleen aanspreken met behulp van de bijbehorende wachtzin (de term wachtzin is verzonnen om gebruikers aan te moedigen om meer dan één woord te gebruiken voor het beschermen van de geheime sleutel. Hier komen we in paragraaf 6.5 “Wat maakt een goede wachtzin?” uitgebreid op terug). Zo’n virtuele partitie is niets anders dan een bestand op de harde schijf die de schijn wekt een echte partitie te zijn. Je kunt met PGPdisk een partitie aanmaken van bijvoorbeeld 100 MB die dan bijvoorbeeld als schijf H: benaderd kan worden. In feite is het een bestand van 100 MB die op schijf C: staat. En dat is dan ook direct de zwakke schakel. Hoe goed PGP zijn werk ook doet, aan de zwakheden van Windows ontkomt het niet. Het versleutelde bestand kan nog steeds worden verwijderd. Het is dan ook aan te raden om het bestand na gebruik op “alleen lezen” te zetten, zo verklein je de kans dat de virtuele partitie per ongeluk in de prullenbak verdwijnt. Windows vraagt dan namelijk om een extra bevestiging. Tijdens gebruik kan het bestand niet op deze manier beschermd worden, daar er dan geen wijzigingen in kunnen plaatsvinden. Het is in ieder geval zeker dat niemand anders bij de data kan die op die virtuele partitie staat. En dat is veilig en bovendien reuze handig. Je kunt namelijk ook gewoon programma’s installeren op de PGP partitie, bijvoorbeeld een e-mailclient of een telebankierprogramma. Of je kunt er vertrouwelijke zakelijke documenten op zetten. In het ergste geval ben je alles kwijt (al erg genoeg), maar je hebt de zekerheid dat niemand anders de vertrouwelijke informatie kan bekijken. Een virtuele partitie aanmaken is gemakkelijk. Na installatie van PGP Personal nestelt PGP tray zich in de systeembalk van Windows. Na het kiezen van de optie PGPdisk krijg je vier opties new, mount, unmount en prefs, voor meer informatie hierover, zie paragraaf 6.4.2 Installatie / Gebruik PGPdisk. Tip: plaats de partitie-file op een andere partitie dan je boot-partitie. De achterliggende gedachte hierbij is dat virussen en hackers altijd de standaard onderdelen aanvallen. Hieronder valt ook het formatteren van de boot-partitie. 6.4.2 Installatie / gebruik van PGP disk Wanneer we vanuit de PGP-tray op de syteembalk de optie “PGPdisk” selecteren krijgen we het volgende scherm te zien, zie figuur 6.1. figuur 6.1 30
    • De vier opties, die we in figuur 1 terug zien, zijn de hoofdfuncties van PGPdisk. Allereerst de optie “New”. Met behulp van deze optie zijn we in staat een virtuele partitie aan te maken. Dit gebeurt door middel van de “New PGPdisk Wizard”. Allereerst moet je opgeven waar je de partitie-file wilt opslaan. Vervolgens gaan we verder met de wizard, zie figuur 6.2. Standaard is de virtuele partitie 100 MB. Pas het formaat aan naar gelang de informatie die je wilt opslaan. Houdt hierbij rekening met het feit dat het formaat van de virtuele partitie achteraf niet te veranderen is. Ook moet je de partitie een driveletter toekennen. In dit geval is dat H:. De volgende stap is de sleutel. Je moet tenminste een wachtzin van acht karakters invoeren, maar hoe langer de wachtzin is, hoe beter. Meer informatie over wachtzinnen kun je vinden in de syllabus paragraaf 6.5 “Wat maakt een goede wachtzin?”. Vervolgens moet je de muis bewegen. PGP gebruikt deze muisbewegingen voor de versleuteling. Hier over hebben we het aan het begin van de syllabus reeds gehad, zie paragraaf 1.5 “random getallen”. figuur 6.2 Nu we de wizard hebben afgerond is er een virtuele partitie gecreëerd. Deze partitie heeft alle eigenschappen van een extra harddisk. Dit houdt in dat de partitie nog wel geformatteerd moet worden. Wanneer dit gebeurd is, is de virtuele partitie klaar voor gebruik. Indien je de machine herstart is de partitie niet meer met behulp van de verkenner te vinden, je hebt immers geen wachtzin ingevoerd. Nu komen de overige opties aan bod. De opties “mount” en “unmount” zijn Unix termen en kunnen worden vertaald als “koppel de partitie” en “ontkoppel de partitie”. Bij het koppelen selecteert je de betreffende partitie-file. Hierna word je om de reeds eerder opgegeven wachtzin gevraagd, zie figuur 6.3. Het ontkoppelen gebeurt met behulp van de toegewezen driveletter in “unmount”. figuur 6.3 31
    • Tot slot hebben we de optie “Prefs”. Met behulp van deze optie kun je je voorkeuren aangeven met betrekking tot unmounten. Zo kun je bijvoorbeeld een disk na 15 minuten automatisch laten unmounten. Zie figuur 6.4. figuur 6.4 32
    • 6.5 Wat maakt een goede wachtzin? Deze paragraaf is samengesteld uit 'The passphrase FAQ, version 1.04' [1]. PGP codeert een wachtzin met behulp van het MD5-algoritme naar een IDEA-sleutel (MD5 wordt behandeld in het boek, zie [12], 'De MD5 Message Digest-algoritme', maar is voor het begrijpen van deze paragraaf niet relevant). De sleutellengte van IDEA is 128 bits. Dit levert 2128 mogelijke combinaties op. Met speciale hardware waarmee één miljard sleutels per seconde geprobeerd kunnen worden, brandt de zon nog eerder op dan dat de sleutel gevonden wordt. Het mag duidelijk zijn dat IDEA niet de zwakke schakel in dit principe is, maar de mens die een wachtzin moet bedenken. Een goede wachtzin bedenken is dus relevant. Volgens de CERT (Computer Emergency Response Team) is zo'n 80% van de incidenten m.b.t. beveiliging terug te leiden naar de keuze van zwakke wachtwoorden (zie [3], 'Passwords -- Strengths and Weaknesses'). De FAQ noemt een wachtzin goed als het voor een hacker niet loont om een andere methode dan brute-force toe te passen om de wachtzin te kraken. Enkele vragen waar de FAQ antwoord op geeft zijn: • Hoe lang moet een wachtzin zijn? Per bit zou je één karakter moeten gebruiken. Dit zou dus betekenen dat je wachtzin zou moeten bestaan uit 128 karakters. Deze moet je wel iedere keer intypen als je PGP gebruikt, waardoor velen hier niet voor kiezen. • Wat als ik een andere taal gebruik? Een hacker kan gebruik maken van een dictonary-attack. Deze is uiteraard ook beschikbaar in een andere taal. Een andere taal gebruiken helpt dus niet. • Wat als ik citeer? Er zijn speciale boeken beschikbaar waarin citaten verzameld zijn. Star Trek fans zouden de zin 'Beam me up Scottie' dus niet moeten gebruiken. Met behulp van de standaard DOS-versie van PGP kunnen 40.000 citaten in 2½ dag geprobeerd worden. • Wat als ik citaten en onzin-zinnen door elkaar heen gebruik? Dit is beter dan de normale citaten, maar de woorden kunnen nog met een dictonaryattack gevonden worden. • Helpt het om hoofd- en kleine letters door elkaar heen te gebruiken? Door gebruik te maken van hoofd- en kleine letters en door cijfers te gebruiken in plaats van letters (b.v. '3' i.p.v. 'E') wordt de zoektijd van een brute-force attack zeker langer. • Wat als ik willekeurige woorden gebruik? Door 8 willekeurige woorden te gebruiken uit een woordenboek met 74.000 woorden heb je een goede wachtzin. Hij is meestal wel moeilijk te onthouden. • Wat als ik allemaal willekeurige letters gebruik? Hoewel dit moeilijk te onthouden is, is het wel mogelijk. Met 28 willekeurige letters heb je een sterke wachtzin. • Wat als ik allemaal willekeurige tekens gebruik? Er zijn 95 afdrukbare tekens. Meer dan de 26 letters uit het alfabet dus. Met 20 willekeurige tekens onthouden heb je een sterke wachtzin. 33
    • De berekeningen kun je terug vinden in de FAQ. De FAQ geeft ook aan dat je de wachtzin nergens moet opschrijven, maar mocht je het nodig hebben, dan raadt de FAQ je aan om de wachtzin in drie delen op te splitsen die aan zes vrienden te geven (je hebt dus ook een backup). Een methode om willekeurig samengestelde wachtzinnen te maken waar de FAQ vaak naar verwijst is ' The Diceware Passphrase Home Page' [2]. Richtlijnen voor het opzetten van een afdoende beveiliging met wachtwoorden kun je vinden in RFC 1244 (Requestfor-comment 1244, zie [4], 'Site Security Handbook'). Er is een document waarin wordt bekeken op welke manier PGP te kraken is. De diverse algoritmen die PGP gebruikt komen daar aan bod ([9] 'PGP Attacks'). 6.5.1 Formule Passphrase Security Tot slot nog een formule om te berekenen of je wachtzin sterk is. Als de uitkomst van de formule groter dan één is, dan is brute-force aanval op de sleutel eenvoudiger dan een andere methode en heb je dus een goede wachtzin. Als de uitkomst kleiner dan één is, is je wachtzin niet per definitie slecht. Een uitkomst lager dan 0,35 kan echter naar verwachting binnen een jaar gekraakt worden. De formule wordt toegelicht in de FAQ [1], 'The passphrase FAQ, version 1.04' in paragraaf 4.0 ('How strong is my passphrase?'). De afkortingen van de onderstaande variabelen worden daar verklaard. De formule om de Passphrase Security te berekenen luidt: PS = RW/8 + RC/20 + RL/28 + LC/107*FF. De variabele FF is zelf weer een formule: FF = 1 + F1 + F2 + F3. De betekenis van de verschillende variabelen zijn terug te vinden in de FAQ. Ook de fudge factor komt in de FAQ aan bod. Spaties tellen in het hele verhaal niet mee, tenzij alle karakters random zijn. Verder is het van belang om in te zien dat niet alle variabelen voor iedere wachtzin ingevuld moeten worden. De voorbeelden hieronder lichten het gebruik van de formule toe en verschaffen je inzicht in de manier waarop een sterke wachtzin opgebouwd kan worden. Voorbeeld 1 "There is a sucker born every minute." met PS=0,280. Dit is een gemiddelde zin. Derhalve telt enkel de lengte (LC = 30) van de zin mee, welke wordt gedeeld door 107. Voorbeeld 2 "paper factors difference votes behind chain treaties never group" met PS = 1,125. Een duidelijk voorbeeld van negen willekeurige woorden (RW = 9), dit wordt gedeeld door 8. Voorbeeld 3 "A6:o@6 Ls+` uGX%3y[k" met PS = 1,05. Deze wachtzin bestaat enkel uit willekeurige karakters (RC = 21). Dit wordt gedeeld door 20. Let op: de spaties tellen hier wel mee daar de complete wachtzin uit willekeurige karakters is opgebouwd. Voorbeeld 4 "betty was smoking tires in her peace of pipe organs and playing tuna fish." met PS = 0,855. De zin telt 61 karakters (LC = 61). Verder wordt de FF met 0,5 opgehoogd daar de zin nergens op slaat (zie F1 in de FAQ). Derhalve wordt de PS = (61/107)*1,5. 34
    • Voorbeeld 5 "Web oF thE Trust is BrokEn cAn You Glue it Back ToGether? and give it xRays." met PS = 1,34. De fudge factor van deze wachtzin die bestaat uit 61 karakters komt door de onzin al 0,5 hoger uit (F1). Vervolgens zorgen de afwijkende karakters (de 13 hoofdletters) ervoor dat F2 van toepassing is. F2 komt op (4*13)/61. De uiteindelijke PS = (61/107)*FF. 35
    • 6.6 Tips uit de PGP FAQ In deze paragraaf behandelen we enkele punten van `The comp.security.pgp FAQ`. We hebben hier een aantal belangrijke/opmerkelijke punten uitgehaald en vertaald. Per alinea behandelen we één onderwerp. Dit met het doel je te informeren over het onderwerp en het type informatie wat je op de site kunt vinden. Mocht je je meer in PGP willen verdiepen, dan adviseren we je de FAQ zelf ook te lezen. 6.6.1 Gebruik de omgevingsvariabele niet PGP biedt de mogelijkheid om je wachtzin op te slaan als omgevingsvariable (met SET) (zie [5], 'The comp.security.pgp FAQ - Part 2/11'). Wij raden aan deze optie niet te gebruiken, daar je wachtzin dan voor mensen die fysieke toegang tot jouw PC hebben te zien is. Bij gebruik van Unix-achtige omgevingen en het opslaan van de wachtzin in het autoexec.bat bestand is fysieke toegang niet eens vereist. Andere gebruikers kunnen opvragen welke processen je hebt draaien en welke parameters daaraan meegegeven zijn. 6.6.2 Randseed.bin is niet geïnfecteerd door een virus PGP maakt gebruik van een bestand 'randseed.rnd'/'randseed.bin' om voor iedere bewerking een willekeurige sleutel te kiezen (zie [5], 'The comp.security.pgp FAQ - Part 2/11'). Dit bestand wordt constant bijgewerkt door PGP, ook als PGP niet in gebruik is. Het bestand wordt gevuld met random-data die afkomstig is van o.a. schijftoegang, toetsaanslagen en muisbewegingen. De extensie (indien .bin) kan heuristische virusscanners in de war brengen. Dit is op te lossen door PGP zo te configureren dat het voor de random-data een andere bestandsnaam gebruikt. 6.6.3 Verlies je sleutel en vergeet je wachtzin niet Vervelende zaken die je moet voorkomen bij het gebruik van PGP zijn het verliezen van je geheime sleutel (denk ook aan diefstal) en het vergeten van je wachtzin. Als je bang bent dat je je wachtzin vergeet, stelt de FAQ voor dat je een kopie maakt van je geheime sleutel met een eenvoudige wachtzin (zie [5], 'The comp.security.pgp FAQ - Part 3/11'). Deze kopie berg je vervolgens goed op. Als je je geheime sleutel verliest, kun je de sleutel intrekken met een zogenaamd revocation certificate (zie [5], 'The comp.security.pgp FAQ - Part 7/11'). Om dit certificaat te maken heb je wel een kopie van je geheime sleutel nodig. Derhalve wordt geadviseerd altijd preventief een kopie van je geheime sleutel op een veilige lokatie te hebben. Als je je wachtzin vergeten bent en je wilt je sleutel intrekken is dit niet mogelijk (je kunt immers niet bij je geheime sleutel). Om dit probleem te omzeilen stelt de FAQ voor om na het aanmaken van het sleutelpaar direct een revocation certificate aan te maken. Dit certificaat stel je samen met je geheime sleutel veilig. 6.6.4 De PGP Developer Kit Mocht je zelf met PGP aan de slag willen, dan is er een developer kit voor PGP te vinden op http://www.pgp.com/sdk/. Met de developer kit kun je PGP integreren in je eigen applicatie. 36
    • 6.7 Literatuur 1. The passphrase FAQ, version 1.04 http://www.stack.nl/~galactus/remailers/passphrase-faq.html Engelstalige FAQ over het maken van een goede wachtzin voor PGP. 2. The Diceware Passphrase Home Page http://www.diceware.com/ Engelstalige site met verwijzingen naar een aantal sites die te maken hebben met het maken van goede wachtzinnen voor PGP, waaronder ' The passphrase FAQ'. Tevens een voorstel voor het maken van een wachtzin door dobbelstenen te gooien. 3. Passwords -- Strengths and Weaknesses http://www.vtac.org/Tutorials/password.html Engelstalig document waarin het belang van de goede keuze van een wachtwoord wordt benadrukt. Tevens worden enkele suggesties gedaan om een beter wachtwoord te kiezen en wordt verteld hoe hackers achter wachtwoorden kunnen komen. 4. Site Security Handbook http://www.ietf.org/rfc/rfc1244.txt?number=1244 Engelstalige RFC waarin richtlijnen worden voorgesteld m.b.t. beveiliging die door systeembeheerders zouden moeten worden overgenomen. 5. The comp.security.pgp FAQ http://www.cam.ac.uk.pgp.net/pgpnet/pgp-faq/ Engelstalige FAQ waarin veel met betrekking tot het programma PGP uit de doeken wordt gedaan. 6. Cog / PGP & Outlook http://www.cog.clara.net/pgpinstall/ Op deze Engelstalige site kun je informatie vinden betreffende de installatie van PGP Personal in combinatie met Microsoft Outlook. Jouw versie van PGP en de versie op de website kunnen enigszins verschillen maar deze verschillen zijn te verwaarlozen. 7. Outlook 98 and PGP http://www.tombeck.com/privacy/outlook98pgp.html Deze Engelstalige site geeft enkele bruikbare tips voor het gebruik van PGP in combinatie met Outlook '98. Deze URL staat niet op CD. 8. QDPGP http://www.download32.com/proghtml/59/5938.htm Deze Engelstalige site bevat een PGP plugin voor de 32-bits versie van Pegasus Mail voor Windows. 9. PGP Attacks http://axion.physics.ubc.ca/pgp-attack.html Engelstalig document waarin de door PGP gebruikte algoritmen worden bekeken op veiligheid. In het document worden ook enkele praktisch haalbare aanvallen op PGP beschreven. 10. Boek 'Netwerkbeveiliging en cryptografie' van William Stallings, Academic Service 1999 (ISBN 90-395-1105-5) Paragraaf 12.1, 'Pretty Good Privacy (PGP)' Beschrijving van de werking van het programma PGP. 37
    • 11. Boek 'Netwerkbeveiliging en cryptografie' van William Stallings, Academic Service 1999 (ISBN 90-395-1105-5) Paragraaf 12.2, 'S/MIME' S/MIME is een veiligheidsverbetering van de Internet e-mailformaatstandaard die waarschijnlijk in het bedrijfsleven gebruikt gaat worden. S/MIME staat voor Secure/Multipurpose Internet Mail Extension. 12. Boek 'Netwerkbeveiliging en cryptografie' van William Stallings, Academic Service 1999 (ISBN 90-395-1105-5) Paragraaf 9.1, 'De MD5 Message Digest-algoritme' MD5 is het hash-algoritme wat door PGP gebruikt wordt om van een passphrase een IDEA-sleutel te maken. In deze paragraaf worden MD4 en MD5 gedetailleerd besproken. 38
    • 7. Encryptie in Java met JCA en JCE 7.1 Beschrijving van de lesstof Java cryptografie, JCA en JCE worden behandeld in dit hoofdstuk van de syllabus. Het hoofdstuk is opgedeeld in de paragrafen: 7.2 Inleiding op Java In deze paragraaf van de syllabus wordt een korte inleiding gegeven op de JCA en JCE klassen. 7.3 Random getallen In deze paragraaf wordt kort het gebruik van random getallen in Java besproken. Zo komen onder werpen als secure random en random getallengeneratoren aan bod. Aan het einde van deze paragraaf moet je een opdracht doen. Het is de bedoeling om een eigen seeder te schrijven voor het voeden van een random getallengenerator. 7.4 Sleutelbeheer Deze paragraaf gaat over sleutels, het aanmaken van sleutels en het beheren van sleutels, met gebruik van Java. Verder komen nog het converteren en uitwisselen van sleutels, zoals bij Diffie Hellman, aan bod. Aan het einde van deze paragraaf moet je zelf een klein sleutelbeheer programmaatje in Java schrijven. 7.5 Authenticatie Deze paragraaf gaat voornamelijk over de vier begrippen message digests, MACs, signatures en certificaten. Er wordt beschreven hoe je met deze begrippen moet werken in Java. Bij de paragraaf over message digests zit een opdracht: het veranderen van een beveiligde wachtwoord login in een dubbele sterkte login. 7.6 Encryptie Bij deze paragraaf kijken we naar blok- en stroomvercijfering in Java. Hierbij wordt ook gekeken naar hoe padding in Java werkt en hoe je een cipher in Java moet aanmaken. Verder wordt wachtzin encryptie behandeld. De opdracht hierbij is het maken van een programma wat gebruik maakt van wachtzin encryptie. 7.7 Providers Deze paragraaf geeft uitleg over de implementatie van providers in Java. 7.8 Signed Applets In deze paragraaf worden signed applets besproken. 7.9 Eindopdracht Als eindopdracht voor het Java gedeelte moet er een programma geschreven worden wat beveiliging nodig heeft. Je bent vrij in de keuze van de toepassing. 39
    • 7.2 Inleiding op Java Dit hoofdstuk van de syllabus heeft betrekking op encryptie en Java. Bij dit hoofdstuk zitten een aantal practica die door de student uitgevoerd moeten worden. De tekst in deze syllabus dient ter ondersteuning voor het maken van deze opdrachten. In deze paragrafen worden verschillende methoden besproken die aansluiten bij de eerder behandelde stof in deze syllabus. Veel onderwerpen komen terug en er wordt nu gekeken hoe deze met de JCA (Java Cryptography Architecture) en JCE (Java Crypto Extensions) klassen geimplementeerd kunnen worden. Deze syllabus is gericht op JDK 1.3 en JCE 1.2 van Sun. In JDK 1.3 zit de JCA package inbegrepen. JCE is een uitbreiding op JCA. JDK 1.3 is te vinden op de website van Sun [1]. Voor een uitleg over de API’s en klassen verwijs ik naar de volgende pagina van Sun [2]. Hier kun je een complete API handleiding voor JDK 1.3 downloaden. Als je wilt kun je ook nog JDK 1.2 [3] gebruiken. JCE mag helaas, nog steeds niet anno juni 2000, geëxporteerd worden vanuit de Verenigde Staten. Gelukkig zijn er ook organisaties buiten de Verenigde Staten die JCE hebben geïmplementeerd. Bijvoorbeeld Cryptix en IAIK-JCE. Bij Cryptix is gratis een versie te downloaden [4]. JCE 1.2 is wel aanwezig op de website van Sun [5] het is alleen niet mogelijk om de package te downloaden. Er is ook een API en klassen uitleg voor JCE 1.2 op de site van Sun aanwezig. [6]. Andere JCE providers vind je in het volgende overzicht: Naam Volledige naam Website SunJCE Sun JCE Security [5] Cryptix Cryptix for Java [4] IAIK IAIK Security [8] JSAFE RSA’s Java Crypto Toolkit [9] 7.2.1 De gebruikte Java security API’s Bij security gaat het voornamelijk om de klassen java.security en javax.crypto. Je hoeft dus niet de gehele API uitleg te bekijken om er mee te kunnen werken. Voor beveiliging zijn vooral de volgende packages van toepassing: java.security JCA java.security.cert JCA java.security.interfaces JCA java.security.specs JCA javax.crypto JCA javax.crypto.interfaces JCE javax.crypto.spec JCE Omdat de JCA en JCE packages elk zo’n 20 megabyte groot zijn, is er ook een CD voor dit vak met daarop de benodigde versies van JDK en JCE van cryptix. 40
    • 7.2.2 JDK 1.3 ten opzicht van JDK 1.2.x Aan het begin van ons project was de nieuweste versie van JDK 1.2.2. De documentatie die gebruikt is ging bij veel documenten nog uit van JDK 1.2. Omdat we niet achter konden blijven bij de nieuwste versie van JDK hebben we verschillende onderdelen in dit hoofdstuk aangepast zodat deze kloppen met versie 1.3. JDK 1.3 is eigenlijk niet een complete nieuwe versie van JDK, maar meer een opvolger c.q. verbetering van JDK 1.2.x. Dit houdt in het kort in dat de veranderingen bestaan uit verbetering van de performance, uitbreiding van het aantal functies en in sommige gevallen de terugkeer van functies uit JDK 1.1 welke in de JDK 1.2.x reeks overbodig werden geacht. Omdat we hier niet meer dan een korte samenvatting van de relevante veranderingen willen geven, verwijzen we voor een precieze lijst naar de chancelog van de JDK Omdat we hier niet meer dan een korte samenvatting van de relevante veranderingen willen geven, verwijzen we voor een exacte lijst naar de changelog van de JDK [7]. 7.2.3 Practicumopdrachten Aan verschillende paragrafen over Java encryptie zijn practicumopdrachten verbonden. Deze opdrachten kunnen bij de eindopdracht gebruikt worden om een beveiligd programma in Java te schrijven. Voor informatie over het maken van gedistribueerde systemen kun je gebruik maken van de lesstof en de dictaten die zijn behandeld bij de vakken Netwerk programmeren en Gedistribueerde systemen uit het 5e semester. Voor elke opdracht geldt dat deze op tijd bij de docent ingeleverd dienen te worden. Bij elk programma moet een kort verslag worden ingeleverd met daarin de motivatie (vooren nadelen) van jouw specifieke implementatie. 7.2.4 Maak gebruik van een package Om gemakkelijk gebruik te kunnen maken van alle klassen in het laatste programma is het aan te raden om gebruik te maken van zogenaamde packages. Hierbij staan alle bestanden die tot een package horen in een zelfde package directory. Elke klasse uit de package begint dan bijvoorbeeld met package kjenc.syllabus.utils. 7.2.5 Standaard methoden Standaard methoden, factory methods, zijn speciale static methoden, die een instance van een klasse terug geven. Over het algemeen worden standaard methoden getInstance() genoemd. Een standaard methode is een voorbeeld van een ontwerp manier, een manier die standaard telkens terug komt bij object georienteerd programmeren. 7.2.6 Javacode in het Engels Alle voorbeelden zijn in het engels. Dit omdat Java een programmeertaal is die op het Engels is gericht en om de voorbeelden zo duidelijk mogelijk over te laten komen. De code kan gekopieerd worden uit de versie van deze syllabus die op de CD voor dit vak staat. 41
    • 7.3 Random Getallen Zoals al besproken is in de inleiding van deze syllabus zijn random getallen belangrijk voor cryptography. Helaas zijn computers niet goed in het produceren van echte random getallen. Hierdoor wordt er vaak gebruik gemaakt van zogenaamde pseudo-random getallen. Deze worden geproduceerd door een pseudo-random nummer generator (PRNG). Een PRNG werkt pas goed als deze echt onvoorspelbare random data genereert. Er moet echter wel opgelet worden wanneer de PRNG niet sterk is met cryptography, of als de data waarmee de PRNG wordt gevoed niet echt random is. In het PDF bestand, The Intel Random Number Generator [10], worden random number generatoren verder bekeken. 7.3.1 Random getallen met JDK JDK bevat een klasse, java.util.Random. Met deze klasse kan een simpele PRNG gemaakt worden. Nadelen van dit algoritme zijn dat het een voorspelbare reeks van getallen produceert en het algoritme standaard gevoed wordt met ‘random’ data van de klok van de computer. Hierdoor is te bepalen welke random getallen het algoritme zal produceren. Een betere PRNG, java.security.SecureRandom, is te vinden in JDK vanaf versie 1.1. 7.3.2 SecureRandom SecureRandom gebruikt SHA-1 (Secure Hash Algoritme). Meer informatie over dit algorithme kan je vinden in het boek [11], hoofdstuk 9.2 Secure Hash Algoritm. SecureRandom sr = new SecureRandom(); byte[] pseudoRandom = new byte[100]; sr.nextBytes(pseudoRandom); SecureRandom heeft drie constructoren, we kunnen van twee gebruik maken: public SecureRandom() Deze constructor zorgt zelf voor random data waarmee het algoritme wordt gevoed. Dit heet Self-Seeding, kijk hiervoor in paragraaf 7.3.3 over Self-Seeding in deze syllabus. public SecureRandom(byte[] seed) Deze constructor gebruikt de meegegeven data om het algoritme mee te voeden. public synchronized void setSeed(byte[] seed) Deze methode kan gebruikt worden om SecureRandom nieuwe data te geven om het algoritme mee te voeden. Deze data zal niet de originele data vervangen, maar zal de oude data aanvullen. public synchronized void nextByte(byte[] bytes) Deze methode vult een gegeven byte array met pseudo-random gegevens. 7.3.3 Self-seeding Bij het aanroepen van de constructor van SecureRandom, kun je ervoor kiezen om data mee te geven voor het voeden van het algoritme. Doe je dit niet, dan zal SecureRandom zelf voor deze data zorgen. 42
    • Dit gebeurt door middel van een static member variabele, die ook een SecureRandom (genaamd de seed generator) is. Deze wordt gebruikt voor het aanmaken van nieuwe seed waarden voor nieuwe instanties van SecureRandom. De seedgenerator wordt dus elke keer aangeroepen bij het maken van een nieuwe SecureRandom, door middel van new SecureRandom(). Maar hoe wordt nu de seedgenerator gevoed? SecureRandom gebruikt hiervoor een algoritme gebaseerd op de timing van threads in het systeem. Hiermee wordt schijnbare random data gegenereerd. Met deze data wordt dan de seedgenerator gevoed. Dus bij SecureRandom wordt alleen bij het aanroepen van de contructor een nieuwe seed gemaakt. Dit heeft twee nadelen, ook volgens Sun: • De processor van de computer heeft een paar seconden nodig, bij de eerste keer van het aanroepen van SecureRandom, om een seed aan te maken. • Het thread timing algoritme is niet volledig getest. Hierdoor kan het zwakke plekken hebben die gebruikt kunnen worden om het te kraken. 7.3.4 Random data uit keyboard timing Zoals al kort is uitgelegd in de inleiding van deze syllabus is het mogelijk om echte random data te maken door middel van het toetsenbord. Elke keer als een toets wordt ingedrukt wordt de tijd tussen twee toetsaanslagen gemeten. Dit gebeurt alleen als er geen gelijke toetsen na elkaar worden ingedrukt. Dit omdat er dan misschien toch een voorspelde waarde uit kan komen. Met deze echte random data kun je vervolgens je PRNG voeden. Het nadeel is dat de gebruiker wel een paar seconden toetsen in moet drukken, net zolang tot er genoeg random data is gegenereerd. Helaas is dit niet echt gebruikersvriendelijk. De random data kan overigens ook verkregen worden uit muisbewegingen, zoals je bij het programma PGP hebt gezien. 7.3.4.1 Implementatie keyboard timer Het maken van een klasse die luistert naar input van het toetsenbord kan door middel van KeyEvents. We geven een klein voorbeeld, Seeder. Seeder laat zien hoe je een seed kan maken door het laten intoetsen van toetsen op een toetsenbord. Seeder implementeert KeyListener en maakt ook gebruik van Counter om de tijd tussen twee toets aanslagen te bepalen. Verderop in de tekst wordt Counter behandeld. Import java.awt.AWTEventMulticaster; Import java.awt.event.*; public class { protected protected protected protected protected protected Seeder implements KeyListener byte[] mSeed; int mNitIndex; boolean mDone; char mLastKeyChar; ActionListener mListenerChain; Counter mCounter; public Seeder(int seedBytes) { reset(seedBytes); } public void reset(int seeBytes) { mSeed = new byte[seedBytes]; mBitIndex = seedbyte * 8 –1; 43
    • mDone = false; mLastKeyChar = ‘0’; mListeneChain = null; mCounter = new Counter(); } public byte[] getSeed() { return mSeed; } public int getBitLength() { return mSeed.Length * 8; } public int getCurrentBitIndex() { return mSeed.length * 8 –1 – mBitIndex; } public void addActionListener(ActionListener al) { mListenerChain = AWTEventMulticaster.add(mListenerChain, al); } public void removeActionListener(ActionListener al) { mListenerChain = AWTEventMulticaster.remove(mListenerChain, al); } public void keyPressed(KeyEvent ke) {} public void keyRealeased(KeyEvent ke) {} public void keyTyped(KeyEvent ke) { char keyChar = ke.getKeyChar(); if (keyChar !=mLastKeyChar) grabTimeBit(); mLastKeyChar = keyChar; } protected void grabTimeBit() { if (mDone) return; int t = mCounter.getCount(); int bit = t &0x0001; if( bit!= 0) { int seedIndex = mBitIndex / 8; int shiftIndex = mBitIndex % 8; mSeed[seedIndex] |= (bit << shiftIndex); } mBitIndex--; if (mBitIndex <0) { mCounter.stop(); mBitIndex = 0; //reset this so //getCurrentBitIndex() works. Mdone = true; } if (mListenerChain != null) { mListenerChain.actionPerformed( new ActionEvent(this, 0, “Your Seed is ready.”)); } } 44
    • } Om nu gebruik te kunnen maken van de klasse Seeder, moet deze eerst aangemaakt worden. Daarna moet deze gekoppeld worden met een bron van KeyEvents. Tevens moet er een koppeling komen met een object om te luisteren naar ActionEvents, om zo door te krijgen of het maken van een seed voltooid is: Seeder s = new Seeder(20) TheComponent.addKeyListener(s); s.addActionListener(this); Seeder houdt geen rekening met waar de eigenlijke keyboardevents vandaan komen, Seeder implementeert de KeyListener interface alleen maar. Verder maakt Seeder gebruik van de systeemklok, System.currentTimeMillis(), om de tussentijden van de toetsaanslagen bij te houden. 7.3.4.2 Risico’s van de klasse seeder Als je bezig bent met het maken van echte random data moet je eigenlijk kunnen garanderen dat de data ‘echt’ random is. Er moet dus extra aandacht besteed worden aan de risico’s die een implementatie van seeder met zich mee brengt: Tijdsmetingen met de systeemklok Voor het meten van de tijd die tussen twee toets aanslagen zit kun je de systeemklok gebruiken. Maar bij Microsoft Windows 95 verspringt deze maar iedere 10 ms. De vraag is of dit wel nauwkeurig genoeg is. Elke tussentijd kan door afronding ongeveer hetzelfde worden. Dan is de data nog steeds niet random. Een andere mogelijkheid is het maken van een eigen teller, zoals bijvoorbeeld Counter. Het blijft altijd moeilijk om te vertellen of een klasse misschien een bepaalde regelmaat heeft in het teruggeven van waarden. Het voorbeeld, Counter, werkt in een eigen thread. Van tevoren is niet te bepalen hoe een bepaald besturingssysteem omgaat met een thread. Counter zal afhankelijk van de systeemload andere waarden teruggeven. Bij een druk systeem zullen deze waarden anders zijn dan bij een systeem die het niet druk heeft. Er moet dus extra worden gelet op de waarden die Counter terug geeft. Counter geeft wel nauwkeuriger een tijd terug dan de systeemklok waardoor de tijden eerder zullen verschillen en dus meer random zullen zijn. Het gaat toch niet om de exacte tijd, maar om het verschil in de tijden en die is groter: public class Counter implements Runnable { protected boolean mTrucking; protected int mCounter; { } public Counter() mTrucking = true; mCounter = 0; Thread t = new Tread(this); t.start(); public void run() { while (mTrucking) mCounter++; } public void stop() { mTrucking = false; } 45
    • public int getCount() { return mCounter; } Herhaalde toetsaanslagen van de gebruiker Verder moet erop gelet worden dat een gebruiker niet herhaaldelijk dezelfde toets indrukt. Hierdoor kan de gebruiker er namelijk (per ongeluk door bijvoorbeeld onwetendheid) voor zorgen dat zijn data niet echt random is. Omdat hij de toetsen wel met een zekere regelmaat zou kunnen indrukken. Dit kan ook gebeuren bij het om en om intoetsen van twee verschillende toetsen. Het kan ook nog zo zijn dat het toetsenbord een bepaald interval heeft waarop hij de toetsaanslagen doorgeeft aan de computer. Hierdoor kan het zijn dat als je sneller typt dan dat het toetsenbord je aanslagen kan afhandelen, je toch een bepaalde regelmaat krijgt. Dit omdat de toetsaanslagen worden bijgehouden in een buffer in het toetsenbord. In plaats van het gebruik van het toetsenbord kan, zoals bij PGP gebeurt, ook bijvoorbeeld de muis worden gebruikt voor het verzamelen van de tussentijden als random data. Of misschien moet je wel meerdere apparaten gebruiken voor het maken van schijnbare random data. Je krijgt dan in elk geval minder voorspelbare data. PGP past sit toe door het bestand met random getallen continue bij te werken. Bestaan echte random getallen wel? Hoe garandeer je, dat random data, echt random is? Er bestaan vele soorten van regels en testen waaraan echte willekeurigheid moet voldoen. Maar zelfs al voldoet de willekeurigheid hieraan, dan hoeft het nog geen echte random data te worden geproduceerd. Voor interessante discussies, berekeningen en filosofieën over random getallen verwijs ik naar de volgende websites: [12], [13] en [14]. 7.3.5 Implementatie van een progressbar Het is gebruikersvriendelijk om bij het aanmaken van een random getal een progressbar te laten zien. Deze progressbar kan gebruikt worden in een window of dialogbox om de voortgang aan te geven. Hieronder een voorbeeld van een progressbar. Import java.awt.*; public class ProgressBar extends Canvas { int mLevel; int mMaximum; Color mFrameColor; public ProgressBar() { this(100); } public ProgressBar(int max) { setForeground(Color.blue); mFrameColor = Color.black; setMaximum(max); setLevel(0); } public void setMaximum(int max) { mMaximum = max; repaint(); } 46
    • public void setLevel(int level) { mLevel = (level > mMaximum) ? mMaximum : level; repaint(); } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { Dimension d = getSize(); double ratio = (double)((double)mLevel / (double)mMaximum); int x = (int)((double)d.width * ratio); g.setColor(mFrameColor); g.drawRect(0, 0, d.width - 1, d.height - 1); g.setColor(getForeground()); g.fillRect(1, 1, x, d.height - 2); g.setColor(getBackground()); g.fillRect(x + 1, 1, d.width - 2 - x, d.height - 2); } public Dimension getMinimumSize() { return new Dimension(10, 1); } } public Dimension getPreferredSize() { return new Dimension(100, 10); } 7.3.6 Opdracht klasse seeder Maak met behulp van de stof die in deze paragraaf is behandeld een klasse Seeder. Deze klasse moet als parameter een integer mee krijgen om het aantal benodigde bytes aan te geven. De Seeder geeft een byte van de aangegeven lengte terug, gevuld met ‘echte’ random data. Op welke manier de byte wordt gevuld moet je zelf bedenken. Je kunt het idee van de syllabus of PGP gebruiken, om de tussentijden van het intoetsen van toetsen (of muisbewegingen) te gebruiken. Ga na wat de voor- en nadelen zijn en op wat voor andere manieren echte random data gegenereerd kan worden. Zorg er ook voor dat er een goede GUI is waarbij de gebruiker kan zien hoe ver het aanmaken van de random data is, zie de progressbar paragraaf 7.3.7. Denk ook aan de risico’s die elk onderdeel met zich meebrengt en probeer deze zo goed mogelijk op te lossen. 7.4 Sleutelbeheer Sleutelbeheer, key management, is één van de grootste uitdagingen voor softwareontwikkelaars die bij cryptografie publieke sleutels willen gebruiken. Denk terug aan het hoofdstuk over RSA, hoofdstuk 5 van deze syllabus behandelt ook een gedeelte van dit probleem. Over sleutelbeheer staat ook het één en ander in het boek [15]. 7.4.1 Werken met sleutels De java.security.Key interface, uit JDK, bevat een cryptografische sleutel en heeft maar drie methoden nodig om mee te werken: 47
    • public String getAlgorithm() Deze methode geeft de naam van het algoritme terug, dat wordt gebruikt voor deze sleutel. Bijvoorbeeld DSA, Digital Signature Algorithm. Meer informatie over DSA kun je vinden in het boek [16]. public byte[] getEncoded() Hiermee vraag je de gecodeerde sleutel op. public String getFormat() Geeft de naam van het algoritme terug waarmee deze sleutel is gecodeerd. Bijvoorbeeld X.509. Voor een beschrijving over X.509 verwijzen we naar het boek [17]. Er zijn verschillende interfaces die de Key interface uitbreiden. Zo kunnen verschillende soorten sleutels gemaakt worden. Zoals we al eerder zagen zijn er verschillende manieren om sleutels te gebruiken. Hiervoor hebben we publieke en privé sleutels nodig. Voor JDK bestaan hiervoor dan ook twee verschillende interfaces: Java.security.publicKey Deze interface stelt de publieke sleutel van een sleutelpaar voor, bruikbaar met een signature of een asymmetrische cipher. Als deze interface wordt gebruikt in combinatie met een signature, wordt er een PublicKey gebruikt om de signature te verifiëren (kijk naar initVerify() in de Signature Klasse). Java.security.privateKey Deze interface stelt de privé sleutel van een sleutelpaar voor. Net zoals bij een publieke sleutel kan deze gebruikt worden met een signature en een asymmetrische cipher. Als deze gebruikt wordt in combinatie met een signature, wordt de privé sleutel gebruikt om een signature aan te maken (kijk naar initSign() in de Signature Klasse, paragraaf 7.5.5.3). JCE bevat nog een semantische uitbreiding van Key: javax.crypto.SecretKey Deze interface stelt een geheime (of privé of sessie sleutel) voor, deze wordt gebuikt met een symmetrische cipher. Zowel publieke- als privé sleutels worden altijd in bij elkaar passende paren aangemaakt. JDK bevat een klasse, java.security.Keypair, waarin een bij passende privé en publieke sleutel zitten. De klasse is eigenlijk heel simpel: public KeyPair(PublicKey publicKey, PrivateKey privateKey) Deze constructor maakt een sleutelpaar, KeyPair, aan met de meegeven publieke- en privé sleutels. public PublicKey getPublic() Deze methode geeft de publieke sleutel terug. public PublicKey getPrivate() Deze methode geeft de privé sleutel terug. 48
    • 7.4.2 Sleutels aanmaken: sleutelgeneratoren Hoe worden nu sleutels gegenereerd? Hiervoor is een speciale klasse aanwezig, genaamd key generator. Deze klasse wordt gebruikt om nieuwe random sleutels aan te maken. Er zijn drie stappen nodig voor het aanmaken van cryptografische sleutels: 1. Verkrijg een sleutelgenerator object voor het algoritme dat je wilt gaan gebruiken. 2. Stel de sleutelgenerator in. 3. Vraag de sleutelgenerator een sleutel of sleutelpaar aan te maken. Er bestaan twee soorten sleutelgeneratoren. De eerste genereert sleutelparen om te gebruiken met asymmetrische ciphers en signatures. De tweede soort genereert losse sleutels om te gebruiken bij symmetrische encryptie. 7.4.2.1 De sleutelpaargenerator De java.security.KeyPairGenerator klasse maakt een bij elkaar passende publieke- en privé sleutel aan en geeft ze terug als een KeyPair. Je kunt een KeyPairGenerator aanmaken met behulp van een van de standaard getInstance() methoden. Bijvoorbeeld voor het genereren van een sleutelpaar voor ElGamal signing, verkrijg je op de volgende manier de KeyPairGenerator: KeyPairGenerator kpg = KeyPairGenerator.getInstance(“ElGamal”); Deze methode, kan zoals elke andere getInstance() methode een NoSuchAlgorithmException geven, als het meegegeven algoritme niet gevonden wordt. De volgende stap is het instellen van de generator. Er bestaan twee methoden om dit te doen: public abstract void initialize(int strength, SecureRandom random) Als er sleutels worden aangemaakt, worden deze aangemaakt voor de meegegeven strength, hierbij wordt de meegegeven bron van random bits gebruikt. Hoewel de sterkte van een sleutel bijna altijd afhangt van zijn bitlengte, is de invulling van de strength parameter algoritme afhankelijk. public void initialize(int strength) Deze methode is zoals de vorige. Alleen maakt deze zelf een nieuwe SecureRandom aan, die als bron dient voor de random bits. Als er nog niet eerder een SecureRandom is aangemaakt in de applicatie, kan deze aanroep wat tijd in beslag nemen, als SecureRandom probeert een seed aan te maken voor zichzelf. Als de KeyPairGenerator eenmaal is ingesteld, kun je een aanvraag doen om een nieuw random sleutelpaar aan te maken: public abstract KeyPair genKeyPair() Deze methode maakt een sleutelpaar aan. Hierbij maakt de methode gebruik van de strength en de bron van random bits, die werden gespecificeerd in de eerdere aanroep van initialize(). Als je een 1024-bit sleutelpaar aan wilt maken, bruikbaar bij een DSA signature, moet je het volgende doen: 49
    • KeyPairGenerator kpg = KeyPairGenerator.getInstance(“DSA”); Kpg.initialize(1024); KeyPair pair = kpg.genKeyPair(); Afhankelijk van het algoritme, de sleutelgrootte, en de gebruikte hardware, kost het werk van de sleutelpaar generator 10 tot 20 seconden. (Herinner dat het eventjes duurt voor de KeyPairGenerator om de SecureRandom in te stellen voor gebruik. Zoals al is besproken in paragraaf 7.3, Random Getallen.) 7.4.2.2 De sleutelgenerator Symmetrische ciphers maken gebruik van een enkele sleutel, in plaats van een sleutelpaar. De JCE bevat daarom een klasse javax.crypto.KeyGenerator genaamd, deze kan gebruikt worden om random een enkele sleutel aan te maken. Zoals zijn broertje, KeyPairGenerator, kan KeyGenerator worden aangemaakt met behulp van een standaard getInstance() methode. Om een KeyGenerator voor een DES cipher aan te maken, gebruik je de volgende regel: KeyGenerator kg = KeyGenerator.getInstance(“DES”) Om de KeyGenerator in te stellen, geef je of een bron voor random data mee of een sterkte of beide. Sommige symmetrische cipher algoritmen hebben een vaste sleutellengte, terwijl anderen een variabele hebben. Als eenmaal de KeyGenerator is ingesteld, kunnen er nieuwe sleutels worden aangemaakt met generateKey(). Let op, KeyPairGenerator heeft een methode initialize(), terwijl KeyGenerator een methode init() heeft: public final void init(SecureRandom) Deze methode stelt de KeyGenerator in zodat deze de meegegeven bron van random bits gebruikt voor het aanmaken van sleutels. public final void init(int strength) Deze methode stelt de KeyGenerator in om sleutels met de meegegeven lengte aan te maken. public final void init(int strength, SecureRandom random) Deze methode stelt de KeyGenerator zo in dat deze de meegegeven bron van random bits gebruikt om sleutels van de meegegeven lengte aan te maken. public final SecretKey generateKey() Deze methode maakt een nieuwe, random SecretKey aan. Als voorbeeld een aanroep om een DES sleutel aan te maken: KeyGenerator kg = KeyGenerator.getinstance(“DES”); kg.init(new SecureRandom()); SecretKey key = kg.generateKey(); 7.4.2.3 Algoritmespecifieke instellingen Beide klassen, java.security.KeyPairGenerator en javax.crypto.KeyGenerator, onder steunen algoritmespecifieke instellingen. Dit betekent dat als je weet welk algoritme je 50
    • wilt gebruiken, je door middel van parameters, die nodig zijn voor een bepaald algoritme, de sleutelgenerator kunt instellen. Java.security.spec.AlgorithmParameterSpec, is een kleine interface die het mogelijk maakt dat je algoritmespecifieke instellingen kunt opgeven. Deze interface definieert geen methoden of constanten. Je moet het zien als een container voor parameters. Je kunt een AlgorithmParameterSpec meegeven aan een sleutelgenerator om hem in te stellen. Het is de taak van de sleutelgenerator om de parameters uit het meegeven object te halen, wat voor een object dat ook is. Java.security.KeyPairGenerator bevat één methode voor algoritmespecifieke instellingen: public void initialize(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException Deze methode stelt de KeyPairGenerator in met behulp van de meegegeven parameters. Als het meegegeven parameterobject niet wordt herkend, wordt er een exception gegeven. In de klasse javax.crypto.KeyGenerator klasse, bestaan er twee methoden voor algoritmespecifieke instellingen: public final void init(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException Deze methode stelt de KeyGenerator in met behulp van de meegegeven parameters. Als het meegegeven parameterobject niet wordt herkend, wordt er een exception gegeven. public final void init(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException Deze methode is hetzelfde als init(AlgorithmParameterSpec), alleen gebruikt de KeyGenerator nu de meegegeven bron van random bits om de sleutels aan te maken. Algoritmespecifieke instellingen kunnen ook gebruikt worden bij Signatures en Ciphers, zoals beschreven in de paragrafen 7.5.4 en 7.6.6.3. 7.4.3 Sleutels overzetten Hoe sla je een sleutel op een diskette op? Hoe stuur je een sleutel over een netwerk? Een oplossing is om gebruik te maken van object serialization. Het is gebruikelijk om simpelweg de sleutel op te slaan of te versturen als een array van bytes. Om dit voor elkaar te krijgen, hebben we een methode nodig om een Key object te vertalen naar een array van bytes en andersom. De klassen javax.crypto.spec.SecretKeySpec, java.crypto.SecretKeyFactory en javax.security.KeyFactory vullen dit gat. Alhoewel de laatste twee klassen Factories worden genoemd, werken ze als vertalers. Laten we eerst naar SecretKeySpec kijken, dit omdat deze het meest eenvoudig is. 7.4.3.1 SecretKeySpec De meest eenvoudige manier om een array van bytes om te zetten naar een geheime sleutel is de javax.crypto.spec.SecretKeySpec klasse. Deze klasse implementeert de SecretKey interface. Je kunt hem van een array van bytes aanmaken met behulp van twee constructoren: 51
    • public SecretKeySpec(byte[] key, String algorithm) Deze constructor maakt een SecretKeySpec aan met behulp van de meegegeven byte array. De sleutel zal voldoen aan het meegegeven algoritme. public SecretKeySpec(byte[] key, int offset, int len, String algorithm) Deze constructor maakt een SecretKeySpec aan en gebruikt hierbij len bytes van de meegegeven byte array, beginnend bij offset. De sleutel zal voldoen aan het meegegeven algoritme. Deze klasse is te gebruiken voor het aanmaken van sleutels voor MACs, zoals wordt beschreven in paragraaf 7.5.3.1. De volgende code maakt bijvoorbeeld een MAC sleutel aan van een array van random data: SecureRandom sr = new SecureRandowm(); Byte[] keyBytes = new byte[20]; Sr.nextBytes(keyBytes); SecretKey key = new secretKeySpec(keyBytes, “HmacSHA1”); Als je minder eenvoudige vertalingen nodig hebt SecretKeys en andere sleutelsoorten, maak je gebruik van de SecretKeyFactory klasse. 7.4.3.2 SecretKeyFactory Een SecretKeyFactory aanmaken gaat met behulp van één van zijn getInstance() methoden: public static final SecretKeyFactory getInstance(String Algorithm) throws NoSuchAlgorithmException Gebruik deze methode om een nieuwe SecretKeyFactory aan te maken voor het meegegeven algoritme. De meegegeven algoritmenaam moet overeenkomen met een symmetrische cipher algoritmenaam, zoals bijvoorbeeld “DES”. public static final SecretKeyFactory getInstance(String Algorithm, String Provider) throws NoSuchAlgorithmException, throws NoSuchProviderException Deze methode maakt een nieuwe SecretKeyFactory aan voor het meegegeven algoritme en maakt hiervoor gebruik van de implementatie van de meegegeven provider. Als eenmaal een SecretKeyFactory is verkregen, ben je vrij in het vertalen van sleutels. De SecretKeyFactory kan vertalen tussen javax.crypto.SecretKey objecten en javax.crypto.spec.KeySpec objecten. KeySpec lijkt heel erg opAlgorithmParameterSpec. Het is een interface die geen methoden en geen constanten definieert. Denk maar aan een container die sleutelgegevens bevat. Als voorbeeld heeft JCE een klasse die DES sleutelgegevens als een byte array voorstelt, javax.crypto.spec.DESKeySpec. Je kunt een KeySpec aanmaken, die een DES sleutelgegevens voorstelt op een volgende manier: // obtain key data in keybytes KeySpec spec = new DESKeySpec(keyBytes); Het vertalen naar sleutels van iets anders Voor het vertalen van een KeySpec naar een SecretKey, maak je gebruik van de methode generateSecret() uit de SecretKeyFactory: 52
    • public final SecretKey generateSecret(KeySpec keySpec) throws InvalidKeySpecException Deze methode maakt gebruik van de sleutel informatie in KeySpec voor het aanmaken van een SecretKey. Als de KeySpec niet wordt herkend wordt er een exception gegeven. Een simpele methode voor het aanmaken van een DES sleutel uit een array van bytes ziet er als volgt uit: public final SecretKey makeDESKey (byte[] input, int offset) throws NuSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException { SecretKeyFactory desFactory = SecretKeyFactory.getInstance(“DES”); KeySpec spec = new DESKeySpec(input, offset); Return desFactory.generate(spec); } Er zijn drie simpele stappen in de makeDESKey() methode: 1. Verkrijg een sleutel-factory voor DES sleutels door middel van SecretKeyFactory.getInstance(). 2. Maak een KeySpec aan die DES sleutelgegevens voorstelt van het meegegeven byte array. 3. Maak een SecretKey van de KeySpec door middel van generateSecret(). Waar komen al die exceptions vandaan? De getInstance() methode kan een NoSuchAlgorithmException geven. Als de byte array meegegeven aan de constructor van DESKeySpec niet de juiste lengte heeft, zal deze een InvalidKeyException geven. En als laatste zal de generateSecret() methode een InvalidKeySpecException geven als deze de KeySpec die hij ontvangt niet herkent. Het vertalen van sleutels naar iets anders De klasse SecretKeyFactory weet ook hoe hij een KeySpec moet maken van een SecretKey: public final KeySpec getKeySpec(SecretKey key, Class keySpec) throws InvalidKeySpecException Deze methode maakt een KeySpec van de meegegeven SecretKey. De keySpec parameter bepaald het objecttype dat terug wordt gegeven door deze methode. Als de SecretkeyFactory de gevraagde klasse, die keySpec voorstelt, niet herkend, of als de SecretKey zelf niet wordt herkent, wordt er door deze methode een InvalidKeyException gegeven. Als voorbeeld geeft de volgende methode weer hoe een DES sleutel moet worden vertaald in een array van bytes: public byte[] makeBytesFromDesKey(SecretKey key) throws NoSuchAlgorithmException, InvalidKeyException { SecretKeyFactory desFactory = SecretKeyFactory.getInstance(“DES”); DESKeySpec = DESKeySpec)desFactory.getKeySpec(key, DeSKeySpec.class); Return spec.getkey(); } 53
    • Nu gebruiken we getKeySpec() om een DESKeySpec aan te maken van de meegegeven SecretKey. We verplichten dat het teruggegeven object een DESKeySpec is door DESKeySpec.class door te geven aan getKeySpec(). Als de sleutel-factory niet weet hoe deze soort van KeySpec aangemaakt moet worden, of als de meegegeven SecretKey niet herkend kan worden, wordt er een exception gegeven. 7.4.3.3 SleutelFabriek java.secutity.KeyFactory lijkt veel op SecretKeyFactory, behalve dat het werkt met publieke en privé sleutels in plaats van geheime sleutels. Zoals gebruikelijk, krijg je een KeyFactory door het aanroepen van een van zijn getInstance() methoden: public static final KeyFactory getInstance(String algorithm) throws NosuchAlgorithmException Gebruik deze methode om een nieuwe KeyFactory aan temaken voor het meegegeven algoritme. De meegegeven algoritmenaam moet overeenkomen met een asymmetrische cipher algoritmenaam of signature algoritmenaam, zoals bijvoorbeeld “DSA”. public static final KeyFactory getInstance(String algorithm, String provider) throws NosuchAlgorithmException Deze methode maakt zoals de vorige methode een nieuwe KeyFactory aan, maar dan met behulp van de implementatie van de meegegeven provider. Om een KeySpec te vertalen naar een PublicKey of een PrivateKey, maak je gebruik van de generatePublic() en generatePrivate() methoden: public final PublicKey generatePublicKey(KeySpec keySpec) throws InvalidKeySpecException Gebruik deze methode om een PublicKey te maken van de meegegeven KeySpec. Als de KeySpec niet wordt herkent door deze KeyFactory wordt er een exception gegeven. public final PrivateKey generatePrivateKey(KeySpec keySpec) throws InvalidKeySpecException Gebruik deze methode om een PrivateKey te maken van de meegegeven KeySpec. KeyFactory heeft nog een methode, getKeySpec(). Deze methode kan zowel publieke als privé sleutels behandelen: public final KeySpec getKeySpec(Key key, Class keySpec) throws InvalidKeySpecException Deze methode maakt een KeySpec aan van de meegegeven Key. Het teruggegeven object zal een instantie zijn van de meegegeven keySpec klasse. Als de KeyFactory de meegegeven sleutel of het type dat hij moet terug geven niet herkent wordt er een exception gegeven. 7.4.4 Sleuteluitwisseling Als inleiding op sleuteluitwisseling, key agreement, kijken we in het boek naar DiffieHellman sleuteluitwisseling. In het boek wordt dit algoritme behandeld [18]. 54
    • In JCE, javax.crypto.KeyAgreement, vinden we een KeyAgreement implementatie, deze is gebaseerd op Diffie-Hellman. Bij deze implementatie, worden x en y behandeld als de privé- en de publieke sleutels (respectievelijk) in een sleutelpaar. Je kunt g en p meegeven als parameters aan de DiffieHellman KeyPairGenerator. Voor het verkrijgen van een KeyAgreement object gebruik je één van de getInstance() methoden: public static final KeyAgreement getInstance(String Algorithm) throws NoSuchAlgorithmException Deze methode maakt een nieuwe KeyAgreement aan voor het meegegeven algoritme. De naam voor het algoritme moet een key agreement zijn, zoals “DH” voor DiffieHellman. public static final KeyAgreement getInstance(String Algorithm, String provider) throws NoSuchAlgorithmException, NoSuchAlgorithmException Deze methode maakt een nieuwe KeyAgreement aan voor het meegegeven algoritme en maakt gebruik van de meegegeven provider. KeyAgreements worden ingesteld met een privé sleutel. Deze wordt gebruikt voor het berekenen van de geheime waarde. Als extra optie kun je een KeyAgreement instellen met een bron van randomdata, een set van algoritmespecifieke parameters of allebei: public void init(Key key) throws InvalidKeyException Deze methode stelt de KeyAgreement in met de meegegeven key. Er wordt een exception gegeven als de sleutel niet van het juiste type is. public void init(Key key, SecureRandom random) throws InvalidKeyException Deze methode stelt de KeyAgreement in met de meegegeven key en de meegegeven SecureRandom. public void init(Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException Deze methode stelt de KeyAgreement in met de meegegeven key en de meegegeven algoritmespecifieke parameters. Public void init(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException Deze init() kan het allemaal. Gebruik deze methode om de KeyAgreement in te stellen met de meegegeven key, de meegegeven SecureRandom en de meegegeven algoritmespecifieke parameters. Een sleuteluitwisselingsprotocol kent verschillende fasen. Zoals bijvoorbeeld bij DiffieHelmann. Eerst wordt er een key pair (x en y) aangemaakt. Daarna wordt de privé sleutel gebruikt voor het instellen van de KeyAgreement; deze wordt gebruikt voor het berekenen van de geheime waarde. 55
    • Verder wordt de privé sleutel ook gebruikt voor het berekenen van tussentijdse waarden van y, voor Diffie-Hellman met drie of vier partijen. Alle y waarden worden behandeld als publieke sleutels. Deze worden doorgegeven aan de doPhase() methode samen met een boolean die aangeeft of de laatste fase is bereikt. Bij een Diffie-Hellman sleutelverwisseling tussen meer dan twee partijen, geeft de doPhase() methode een nieuwe key terug die de tussentijdse y waarde voorstelt. Als je denkt aan allemaal mensen die rond een tafel zitten, ontvang je tussentijdse y waarden (publieke sleutels) van links, voer je een berekening uit op deze waarden (doPhase()), en geef je de nieuwe y waarden (publieke sleutels) door naar rechts: public final Key doPhase(Key key, boolean lastPhase) throws InvalidKeyException, IllegalStateException Deze methode voert een fase uit van het sleuteluitwisselings protocol en maatkt gebruik van de meegegeven sleutel. Indien van toepassing wordt het resultaat van een fase terug gegeven als een andere sleutel. Bij Diffie-Hellman met drie of meer partijen, worden de tussentijdse sleutel waarden teruggegeven als publieke sleutels. De parameter lastPhase geeft aan of de laatste fase van de sleuteluitwisseling actief is. Als alle fasen van het sleuteluitwisselingsprotocol zijn uitgevoerd met behulp van doPhase(), kan de geheime waarde worden berekend. Je kunt deze waarde verkrijgen door het aanroepen van generateSecret(): public final byte[] generateSecret() throws IllegalStateException Deze methode geeft de geheime waarde als een byte array terug van het sleuteluitwisselings protocol. Als de KeyAgreement niet alle fasen heeft uitgevoerd, wordt er een IllegalStateException gegeven. public final int generateSecret(byte[] sharedSecret, int offset) throws IllegalStateException, ShortBufferException Deze methode schrijft de geheime waarde in de meegegeven byte array, beginnend bij offset. Als de array niet lang genoeg is wordt er een ShortBufferException gegeven. Het aantal weggeschreven bytes wordt teruggegeven. public final SecretKey generateSecret(String algorithm) throws IllegalStateException, IllegalStateException, NoSuchALgorithmException Deze methode geeft de geheime waarde terug van het sleuteluitwisselings protocol als een SecretKey. Hiervoor wordt het meegegeven algoritme gebruikt. Als het gevraagde sleutel algoritme niet beschikbaar is wordt er een NoSuchAlgorithmException gegeven. 7.4.5 Identity Sleutelbeheer De oplossing van JDK 1.1 voor het moeilijke probleem van sleutelbeheer is een set van klassen rond java.security.Identity. Vanaf JDK 1.2 is het Identity gebaseerde sleutelbeheer vervangen door keystore gebaseerde sleutelbeheer. Elke aanpak heeft zijn voordelen, deze zullen in deze paragraaf behandeld worden. 56
    • 7.4.5.1 Sleutelbezitters Sleutels zijn normaal het bezit van iets, een persoon, een groep mensen, een bedrijf, een computer, een thread die wordt uitgevoerd, of bijna alles anders. In de JDK stelt de klasse java.security.Identity iets voor dat een sleutel bezit. Principal Identity implementeerd de java.security.Principal interface. Een principal is simpel gezegd iets met een naam: public abstract String getName() Deze methode geeft de naam terug van de Principal. De Principal interface wordt door de gehele java.security.acl package gebruikt. Omdat het de Principal interface implementeert, fungeertde klasse Identity als een brug tussen het aanmaken van een toegangscontrole van java.security.acl en de sleutelbeheer concepten van java.security. Identity Een Identity stelt een persoon, een organisatie, of wat dan ook voor dat een koppeling heeft met een public key. In andere woorden, een Identity is een Principal met een publieke sleutel. Dit is handig om informatie bij te houden over andere mensen, zoals een regel in een telefoonboek. Een Identity heeft een naam, en zoals je nog zult zien, kan hij ook een scope hebben. Een scope is een manier waarop identities worden gegroepeerd zodat verschillende identities in één scope niet dezelfde naam of dezelfde publieke sleutel hebben. Scope wordt iets verderop, in de volgende paragraaf, uitgebreider besproken. De twee constructoren van Identity geven de mogelijkheid voor het opgeven van een naam en, eventueel, een scope: public Identity(String name) Deze constructor maakt de meegeven Identity aan zonder scope. public Identity(String name, IdentityScope scope) throws KeyManagementException Deze constructor maakt de meegegeven Identity aan in de meegegeven scope. Geen verschillende Identities in dezelfde scope kunnen dezelfde naam hebben. Als je probeert om een nieuwe Identity aan te maken met een zelfde naam als al in de scope aanwezig is, wordt er een KeyManagementException gegeven. Een set van methoden staat verandering van de publieke sleutels van de Identities toe: public PublicKey getPublicKey() Deze methode geeft de publieke sleutel van de Identity terug. public void setPublicKey(PublicKey key) throws KeyManagementException Deze methode stelt de publieke sleutel van de Identity in op de meegegeven sleutel. Omdat verschillende Identities binnen dezelfde scope geen gelijke publieke sleutels kunnen hebben, geeft deze methode een KeyManagementException als de publieke sleutel waarde binnen een scope niet uniek is. Stel dat je de publieke sleutel van een Identity wilt bekijken. Je kunt dan bijvoorbeeld het algoritme en de format van de sleutel op de volgende manier afdrukken op het scherm: 57
    • public void printKey(Identity i) { PublicKey k = i.getPublicKey(); System.out.println(“Public key uses “ + k.getAlgorithm() + “ and is encoded with “ + k.getFormat() + “.”); } Identity bevat ook methoden voor het beheren van certificaten. Een Identity kan een certificaat bevatten die de oorsprong van een publieke sleutel garandeert. Dit is te vergelijken met een echt persoon die rondloopt met allerlei papieren voor identificatie. Je kunt een lijst met certificaten, die worden besproken in paragraaf 7.5.5, onderhouden met behulp van drie methoden: public void addCertificate(Certificate certificate) throws KeyManagementException Je kunt een certificaat aan de lijst met certificaten van Identity toevoegen met deze methode. Als de Identity geen publieke sleutel heeft, wordt zijn publieke sleutel ingesteld op de publieke sleutel die het meegegeven certificaat bevat. Als een Identity al een publieke sleutel heeft, moet deze dezelfde zijn als die van het meegegeven certificaat, anders wordt er een exception gegeven. public void removeCertificate(Certificate certificate) throws KeyManagementException Deze methode verwijderd het meegegeven certificaat van zijn Identity. Er wordt een exception gegeven als het certificaat niet aanwezig is in de lijst met certificaten van Identity. public Certificate[] getCertificate() Deze methode geeft een array terug met daarin de lijst met certificaten. Hoe gemakkelijk Identity ook lijkt, het is een abstracte klasse en kan dus niet direct ingesteld worden. Hij heeft ook geen abstracte methoden, dus het is nodig om een concrete subklasse te maken: import java.security.*; public class ConcreteIdentity extends Identity { public ConcreteIdentity(String name) { super(name); } } Signer java.security.Signer is een subklasse van Identity. Deze subklasse voegt de ondersteuning voor het beheren van privé sleutels toe. Twee extra methoden worden gedefinieerd: public PrivateKey getPrivateKey() Deze methode geeft de privé sleutel terug van de signer. public final void setKeyPair(KeyPair pair) throws InvalidParameterException, InvalidKeyException Deze methode stelt de publieke en de privé sleutel van de sigener in. Als er iets mis gaat wordt er een exception gegeven. Deze methode wordt aangeboden in plaats van een setPrivatekey(), omdat publieke en privé sleutels altijd in paren komen. 58
    • 7.4.5.2 De scope van een Identity Identities kunnen een scope hebben, zoals we al in de vorige paragraaf zagen. Een scope is een soort gebied waarin Identities zich kunnen bevinden. Een Identity kan zich in één of meerdere gebieden bevinden en kan in elk gebied weer een andere sleutelset of andere certificaten hebben. Een IdentityScope stelt dit concept voor in de Security API. Een IdentityScope heeft een naam en kan andere Identity objecten bevatten. In een scope kunnen dus ook meerdere scopes zitten. Maar er kunnen geen verschillende Identities in een scope zitten die dezelfde publieke sleutel of naam hebben. 7.4.5.3 De system scope beheren: Javakey JDK 1.1 bevat een command line tool, javakey. Met deze tool kun je een speciale IdentityScope, de system scope, beheren. De klasse die wordt gebruikt voor de system scope wordt bepaald door de system.scope eigenschap in de lib/security/java.security file, deze file staat in de JDK installatie directory. De standaard klasse is sun.security.provider.IdentityDatabase, die weer een subklasse is van IdentityScope. Deze klasse weet hoe hij zich zelf kan ‘serialize’ van en naar de identity.obj file. Alle Identities die worden beheerd door javakey leven in een platte namespace van de scope van het systeem. Meer informatie over het gebruik van javakey is op te vragen door op de systeemprompt javakey –help. In JDK kun je de system scope opvragen met behulp van de static methode getSystemScope() uit de IdentityScope klasse. In JDK 1.2 geeft deze klasse null terug. Mocht je nog JDK 1.1 gebruiken, dna geven we hier een programmaatje wat op het scherm het algoritme en de codering van de publieke sleutel van de genoemde Identity naam, ingetypt op de command line, laat zien. De benodigde informatie over de genoemde identity wordt ontleend aan de system Identity scope. import java.security.*; import java.util.*; public class ShowKey { public static void main(String[] args) { if (args.length < 1 { System.out.println(“Usage: ShowKey name”); return; } IdentityScope systemScope = IdentityScope.getSystemScope(); Identity i = systemScope.getIdentity(args[0]); Key k = i.getPublicKey(); If (k != null) { System.out.println(“Pulic key uses “ + k.getAlgoritm() + “ and is encoded by “ + k.getFormat() + “.”); } } } In dit voorbeeld maken we gebruik van getIdentity() om een Identity van de system scope te verkrijgen. IdentityScope definieert een complete set aan methoden om Identities mee te onderhouden: 59
    • public abstract void addIdentity(Identity identity) throws KeyManagementException Deze methode voegt de meegegeven Indentity toe aan deze scope. Als de naam van de Identity of de publieke sleutel al worden gebruikt binnen deze scope, dan wordt er een exception gegeven. public abstract void removeIdentity(Identity identity) throws KeyManagementException Deze methode verwijdert de meegegeven Indentity van deze scope. Als de Identity niet bestaat in deze scope, dan wordt er een exception gegeven. public abstract int size() Gebruik deze methode om het aantal Identities binnen deze scope op te vragen. public abstract Enumeration identities() Deze methode geeft een Enumeration, opsomming, terug van de identities binnen deze scope. public abstract Identity getIdentity(String name) Deze methode geeft de Identity terug met de meegegeven naam, of null als deze scope de meegegeven naam niet bevat. public abstract Identity getIdentity(PublicKey key) Deze methode geeft de Identity terug met de meegegeven publieke sleutel, of null als deze scope de meegegeven publieke sleutel niet bevat. public abstract Identity getIdentity(Principal principal) Deze methode geeft de Identity terug met de meegegeven Principal, of null als de huidige scope de meegegeven principal niet bevat. Omdat een IdentityScope ook een Indentity is, kan deze ook weer bij een andere scope behoren. Verder kan het nog een publieke sleutels en certificaten bevatten. Dit kan handig zijn als je bijvoorbeeld een IdentityScope voor een geheel bedrijf wilt aanmaken. Elke Identity stelt een medewerker voor binnen de IdentityScope, het bedrijf. Maar ook het bedrijf zelf, of een afdeling, heeft een Identity, het kan zelfs zijn dat deze ook nog een publieke sleutel heeft, in het bijzonder als het een bedrijf is wat software verkoopt dat cryptografisch ondertekend is. Een logische plaats voor het opslaan van de publieke sleutel voor het bedrijf zal in de IdentityScope van het bedrijf zijn. Let op, een IdentityScope kan niet zelf de Signer zijn omdat beide klassen afstammen van Identity. 7.4.6 Keystore Sleutelbeheer Vanaf JDK 1.2 is er een nieuwe methode om het sleutelbeheer probleem op te lossen. Deze is gebaseerd op java.security.KeyStore. Een keyStore is een handige container die sleutels en certificaten kan bevatten. Een KeyStore bevat alle informatie die een enkele persoon, een applicatie of een Identity nodig heeft. Normaal gesproken heb je twee verschillende manieren om van authenticatie gebruik te maken: 60
    • • Jij moet aan anderen bewijzen wie je bent. • Jij moet er zeker van worden dat andere mensen zich kunnen legitimeren. In het eerste geval kun je een privé sleutel gebruiken om je gegevens te ondertekenen. Een certificaat, die je passende publieke sleutel bevat, kan gebruikt worden om je identiteit te bewijzen. In het tweede geval, kun je de certificaten van andere mensen gebruiken om voor jezelf te bewijzen dat zij degenen zijn die zij zeggen dat ze zijn. Het gebruik van certificaten met Java, wordt nog in paragraaf 7.5.5 behandeld. Het kan zijn dat je meer dan één publiek/privé sleutelpaar hebt die je moet beheren. Je kunt bijvoorbeeld een sleutelpaar hebben wat je gebruikt voor je dagelijkse Internet aankopen en een ander sleutelpaar voor het ondertekenen van de software die je schrijft. Een KeyStore bevat twee verschillende typen gegevens. De eerste bevat een privé sleutel en een ketting van certificaten die corresponderen met de passende publieke sleutel. Dit type gegeven zullen we een private key entry noemen. Deze is handig voor het ondertekenen en distribueren van code of andere gegevens. De privé sleutel wordt gebruikt om de gegevens te ondertekenen, de certificaten kunnen worden gezien als bewijsstukken om de signature te ondersteunen. Het tweede type entry van keystore bevat een certificaat van iemand die je vertrouwt. Dit type gegeven zullen we trusted certificate entry noemen. Deze kan samen met de veiligheidsregels tool gebruikt worden om veiligheidsregels op te stellen voor de vertrouwde ondergetekende. KeyStore bevat al deze informatie, georganiseerd door aliassen, of korte namen. Gegevens worden opgeslagen en opgevraagd door middel van een alias, op een zelfde manier waarop een hashtabel of een eigenschappenobject werkt. 7.4.6.1 KeyStore Verkrijgen Keystore is een abstracte klasse, maar je kunt een concrete subklasse verkrijgen door het aanroepen van getInstance(): public static final KeyStore getInstance() throws KeyStoreException Deze methode geeft een KeyStore instantie terug. De getInstance() methode van KeyStore gebruikt een regel in het java.security eigenschappenbestand om te beslissen welke subklasse van KeyStore aan te maken. Die regel kan er als volgt uit zien: Keystore = hvu.fnt.security.SuperDuperKeyStore Als deze regel niet bestaat, maakt getInstance() gebruik van de standaard KeyStore implementatie, sun.security.tools.JavaKeyStore. Laden en opslaan Twee methoden ondersteunen het laden en opslaan van KeyStores. Een wachtzin controleert de integriteit van de gegevens: public abstract void store(OutputStream stream, String password) throws IOException, NoSuchAlgorithmException, CertificateException Gebruik deze methode om de gegevens van KeyStore weg te schrijven naar de meegegeven OutputStream. De opmaak van de gegevens hangt compleet af van de implementatie van KeyStore. De meegegeven wachtzin genereert een integriteittest op de gegevens van keystore, deze moet ook opgeslagen worden. 61
    • public abstract void load(InputStream stream, String password) throws IOException, NoSuchAlgorithmException, CertificateException Deze methode leest gegevens van de meegegeven InputStream. Ook hier hangt de opmaak van de gegevens af van de implementatie van KeyStore. Met deze methode moet het mogelijk zijn om gegevens te lezen die zijn opgeslagen met behulp van de store() methode. Verder doet deze methode een integriteittest op de gegevens van keystore, met behulp van de meegegeven wachtzin. De integriteittest is belangrijk omdat, mits goed geïmplementeerd, je een beetje zekerheid hebt dat niemand met de keystore gegevens heeft geknoeid. De makkelijkste manier is om een message digest van de keystore samen met de keystore op te slaan. Bij het laden van de gegevens kan je dan de opgeslagen message digest vergelijken met een nieuw gemaakte message digest van de keystore gegevens. Deze manier is beschermt tegen aanvallen, maar het kan gemakkelijker zijn om gewoon de keystore gegevens te veranderen en de message digest te verwisselen. Een wachtwoord of wachtzin kan gebruikt worden om dit soort aanvallen tegen te gaan. De wachtzin wordt meegenomen met de mesage digest van de rest van de keystore gegevens, de resulterende message digest wordt dan weer opgeslagen met de keystore gegevens. Bij het laden van de gegevens, is dezelfde wachtzin nodig om weer dezelfde message digest te krijgen. Als de digest waarden niet hetzelfde zijn is of een foute wachtzin gebruikt of is er iets veranderd aan de keystore gegevens of de message digest. Toevoegen van privé sleutelentries Laten we als voorbeeld uitgaan van een sleutelpaar die je wilt toevoegen aan een KeyStore. In plaats van het rechtstreeks toevoegen van de sleutels, voeg je de privé sleutel toe en een ketting van certificaten die verwijzen naar de publieke sleutel. Als je een certificaat hebt die zelf is ondertekend, signed, met een publieke sleutel, dan kan je deze toevoegen als een ketting die maar één certificaat bevat. public abstract void setKeyEntry(String alias, PrivateKey key, String passphrase, Certificate[] chain) throws KeyStoreException Deze methode voegt de meegegeven privé sleutel en ketting van certificaten toe aan de alias. Als de alias al bestaat, worden zijn huidige publieke sleutel en ketting van certificaten overschreven met de nieuwe waarden. De privé sleutel is ‘beschermd’ door middel van de meegegeven wachtzin. De subklassen van KeyStore moeten maar bepalen welke soort van bescherming er wordt gebruikt voor de privé sleutel. Let op, KeyStore geeft niet aan hoe een wachtzin precies moet worden gebruikt om de privé sleutel in de database te beschermen. Deze implementatie wordt over gelaten aan de subklassen. Dit houdt in dat de sterkte van beveiliging kan variëren van oneffectief tot supersterk. We kijken even naar een paar voorbeelden: Brain-dead beveiliging De makkelijkste manier is het opslaan van de privé sleutel en de wachtzin in gewone tekst als de KeyStore wordt bewaard. Op deze manier kun je snel de wachtzin en de sleutel terug halen, er mag alleen toegang zijn tot de sleutel als de juiste wachtzin is gegevens. Deze manier is helemaal niet veilig. Je kunt er erg gemakkelijk achterkomen wat de wachtzin of de privé sleutel is, door alleen even te kijken hoe het KeyStore bestand in elkaar zit. Slappe encryptie Het is ook mogelijk om de privé sleutel te encrypten door de wachtzin te verminken en te combineren met de privé sleutel. Dit zal echte crypto-analisten niet afschrikken, maar het is waarschijnlijk wel effectief tegen het achterhalen van de privé sleutel 62
    • door normale snuffelaars of amateur hackers. Deze manier wordt ook gebruikt door de KeyStore implementatie van Sun, sun.security.tools.JavaKeyStore. Sterke encryptie De beste oplossing is wachtzin gebaseerde encryptie. Dit wordt besproken in paragraaf 7.6.8. Bij deze methode wordt een wachtzin gebruikt om een sessie sleutel aan te maken. Deze sessiesleutel wordt met een symmetrische cipher gebruikt om de originele privé sleutel te coderen voordat deze wordt opgeslagen samen met de KeyStore. Afhankelijk van het cipher algoritme kan dit heel erg effectief zijn voor het verstoppen van de privé sleutel. Dit is een hele andere manier waarop een wachtzin wordt gebruikt dan we al eerder zaken, met store() en load(). In deze methoden wordt de wachtzin gebruikt om de integriteit van de keystore gegevens als geheel te bewaren. Hier wordt de wachtzin gebruikt om een privé sleutel geheim te houden. Adding trusted certificate entries KeyStore kan ook certificaten, die publieke sleutels van andere mensen, bewaren. Je kunt een certificaat toevoegen aan de KeyStore met setCertificateEntry(): public abstract setCertificateEntry(String alias, Certificate cert) throws KeyStoreException Deze methode associeert alias met het meegegeven certificaat. Als de alias al bestaat wordt het al reeds aanwezige certificaat vervangen door het nieuwe meegegeven certificaat. Je kunt niet een gehele ketting van certificaten toevoegen. Als je een ketting van certificaten ontvangt, die naar een publieke sleutel van een bepaald persoon verwijzen, kun je elk certificaat in de ketting toevoegen als een vertrouwd certificaat entry. Retrieving entries Als je eenmaal gegevens hebt opgeslagen in de KeyStore, kun je deze weer opvragen met verschillende get methoden: public abstract PrivateKey getPrivateKey(String alias, String passphrase) throws NoSuchALgorithmException, UnrecoverableKeyException Met deze methode kun je de privé sleutel opvragen die bij de meegegeven alias hoort. De meegegeven wachtzin wordt gebruikt om, ieder willekeurige bescherming die de privé sleutel dan heeft, ongedaan te krijgen. public abstract certificate[] getCertificateChain(String alias) Deze methode geeft de ketting van certifcaten terug die behoren bij de meegegeven alias. public abstract Certificate getCertificate(String alias) Deze methode geeft het certificaat terug die behoort bij de alias. 7.4.6.2 Keytool Vanaf JDK 1.2 is javakey opeens vervangen door twee nieuwe tools, keytool en jarsigner. Jarsigner is nodig bij signedobjects, zie paragraaf 7.7, maar we zullen deze niet verder bespreken omdat dit buiten de lesstof valt. We bespreken wel keytool even in het kort, 63
    • meer informatie over het gebruik van keytool is op te vregen door op de systeemprompt keytool –help in te typen. Alhoewel javakey in JDK 1.2, niet aanwezig is (in JDK 1.3 wel weer), bestaan de klassen Identity en IdentityScope nog wel. Een KeyStore is een simpele database voor privé sleutels, publieke sleutels en certificaten. Elke entry in KeyStore heeft een alias waarmee elke entry wordt geidentificeerd en gerefereerd. Standaard worden KeyStores op de harddisk van je computer opgeslagen. Een KeyStore past in één bestand. Met Keytool kun je deze KeyStore bestanden beheren. Als je bij het gebruik van keytool geen bestand specificeerd wordt het standaard KeyStore bestand gebruikt. Een KeyStore hoeft niet perse in een bestand worden opgeslagen 7.4.7 Opdracht Sleutelbeheer Schrijf met behulp van de behandelde KeyStore een eigen sleutel beheer programma. Het moet de mogelijkhied bevatten om nieuwe aliassen met daarbij een eigen publieke en privé sleutel op te slaan en opte vragen. En ook het opslaan en opvragen van de publieke sleutels van anderen moet mogelijk zijn. Maak zelf de keuze tussen de manier van JDK 1.1 of JDK 1.2 en kijk ook even naar de al bestaande tools, bijvoorbeeld om je KeyStore te vullen of te bekijken. 7.5 Authenticatie Zoals in het boek te lezen is: Authenticatie: Garandeert dat de oorsprong van een bericht of elektronisch document als correct wordt geїdentificeerd, met de verzekering dat de identiteit niet vals is [19]. Om dit voor elkaar te krijgen bestaan er drie verschillende cryptografische begrippen. Namelijk message digests, digitale handtekeningen (signatures) en certificaten. Authenticatie is belangrijk bij een beveiligde applicatie. Dit omdat de persoon waarmee gecommuniceerd wordt zich overal ter wereld kan bevinden, en er geen mondeling of visueel contact is. In de wereld van de cryptografie is het mogelijk om je te identificeren met deze drie concepten. En het is mogelijk ze met behulp van Java te implementeren. Een veel gebruikte methode, vooral bij grotere gedistribueerde systemen, is een loginscherm. Gebruikers moeten zichzelf identificeren aan de applicatie voordat zij er gebruik van kunnen maken. In dit hoofdstuk worden verschillende manieren besproken waarop dit geïmplementeerd kan worden met behulp van cryptografie. Deze methoden zijn gebaseerd op de authenticatie procedures beschreven in de X.509 standaard. Hierover is in het boek [17] meer te lezen. We zullen in het volgende gedeelte gaan kijken naar het gebruik van een message digest om te voorkomen dat een wachtwoord in gewone tekst wordt verzonden van de cliënt naar de server. Dit kan immers door te sniffen eenvoudig worden onderschept. In paragraaf 7.5.4 zullen we dit bekijken aan de hand van digitale signatures in plaats van wachtwoorden. 7.5.1 Message Digest Door middel van een message digest kan van een hoeveelheid invoer data een korte digested versie gemaakt worden van de data. Met JCA kan deze message digest gemakkelijk gebruikt worden. In de klasse java.security.MessageDigest zit een cryptografische message digest. 64
    • 7.5.1.1 Aanmaken van een message digest Om een message digest aan te maken voor een bepaald algoritme, kunnen we gebruik maken van de getInstance(), standaard methoden: public static MessageDigest getInstance(String algorithm) throws NoSuchAlgorithmException Deze methode geeft de MessageDigest terug van een meegegeven algoritme. De eerste provider die dit algoritme ondersteunt wordt gebruikt. public static MessageDigest getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException Deze methode geeft de MessageDigest terug van een meegegeven algoritme. De meegegeven provider wordt hiervoor gebruikt. 7.5.1.2 Data invoer voor een message digest Om gegevens aan de MessageDigest in te voeren, maak je gebruik van een van de update() methoden: public void update(byte input) Deze methode voegt de meegegeven byte toe aan de message digest input data. public void update(byte[] input) Deze methode voegt de meegegeven array van bytes toe aan de message digest input data. public void update(byte[] input, int offset, int len) Deze methode voegt len bytes van de meegegeven array, startend bij offset, toe aan de message digest input data. Update() kan zo vaak als maar nodig is worden aangeroepen voordat de digest waarde berekend moet worden. 7.5.1.3 Digesting Om de digest waarde te bepalen, maak je gebruik van één van de digest() methoden: public byte[] digest() De waarde van de message digest wordt terug gegeven als aan byte array. public byte[] digest(byte[] input) Deze methode bestaat voor het gemak. En is hetzelfde als het aanroepen van update(input), gevolgd door digest(). public int digest(byte[] buf, int offset, int len) throws DigestException Deze methode berekent de message digest en schrijft vervolgens len bytes in de meegegeven array, beginnend bij offset. 65
    • Voor het opnieuw gebruiken van een MessageDigest, voor een volgende set, moet eerst de interne status weer terug gezet worden. Dit kan door gebruik te maken van een aparte methode reset(): public void reset() Deze methode maakt zet e interne status van de MessageDigest terug, zoals deze standaard staat. Daarna kan deze weer gebruikt worden voor het berekenen van een nieuwe digest met een geheel nieuwe dataset. Kortom je kunt een message digest berekenen, voor elke input data, met maar een paar regels code: // Define byte[] inputData first. MessageDigest md = MessageDigest.getInstance(“SHA”) md.update(inputData); byte[] digest = md.digest(); Message digests zijn een soort van de bouwblokken voor digitale handtekeningen. Maar message digests zelf, kunnen ook heel handig zijn. Dit zal blijken uit de volgende paragrafen in dit hoofdstuk. 7.5.1.4 Digest Streams Om message digests op data stromen toe te passen heeft de java.security package specifieke klassen. Deze klassen zijn DigestInputStream en DigestOutputStream, afgeleiden van de FilterInputStream en FilterOutputStream klassen uit java.io. Nu kunnen we de digest streams bijvoorbeeld op de volgende manier gebruiken: // Obtain a message digest object. MessageDigest md = MessageDigest.getInstance(“MD5”); //Calculate the digest for the given file. DigestInputStream in = new DigestInputStream( new FileInputStream(args[0], md); byte[] buffer = new byte[8192]; while (in.read(buffer) != -1) ; byte[] raw = md.digest(); DigestOutputStream werkt op dezelfde manier; alle bytes die worden geschreven naar de stream worden automatisch doorgegeven aan de MessageDigest. 7.5.1.5 Beveiligde wachtwoord login Een standaard probleem bij client/server applicaties is dat de server wil weten wie de clients zijn. In het boek [20] is hierover het één en ander te lezen. Het probleem hierbij is het versturen van het wachtwoord van de client naar de server, dit gebeurt meestal als gewone tekst. Maar je kunt ook een message digest, van het wachtwoord, vanaf de client naar de server sturen. De server kan dan van het wachtwoord dat deze heeft een message digest maken en deze vergelijken met het ontvangen ‘wachtwoord’. Zijn ze gelijk dan is de client geautoriseerd. Een simpele procedure, maar helaas ook vatbaar voor een replay-aanval. Zie voor deze vorm van aanvallen de introductie van deze syllabus, paragraaf 1.6. Om dit probleem te voorkomen, kan er sessiespecifieke informatie worden toegevoegd aan de message digest. Dit komt in de praktijk neer op het toevoegen van een door de client gegenereerd random getal en een timestamp. Deze waarden moeten ook in het open verzonden worden aan de server, zodat deze die gegevens kan gebruiken om de passende message digest te berekenen. 66
    • Het volgende programma laat de procedure zien vanaf de client: import import import import java.io.*; java.net.*; java.security.*; java.util.Date; import Protection; public class ProtectedClient { public void sendAuthentication(String user, String password, OutputStream outstream) throws IOException, NoSuchAlgorithmException { DataOutputStream out = new DataCrutputStream(outStream); long t1 = (new Date()).getTime(); double q1 = Math.random(); byte[] protected1 = Protection.makeDigest(user, password, t1, q1); out.writeUTF(user); out.writeLong(t1); out.writeDouble(q1); out.writeInt(protected1.length); out.write(protected1); out.flush(); } public static void main(String[] args) throws Exception { String host = args[0]; int port = 7999; String user = "Henk"; String password = "geheim”; Socket s = new Socket(host, port); } ProtectedClient client = new ProtectedClient(); client.sendAuthentication(user, password, s.get0utputStream()); s.close(); } ProtectedClient hoeft niet alleen met sockets te werken, met enige aanpassingen is het ook te gebruiken om authenticatieinformatie in een bestand of een e-mail bericht op te slaan. Een gedeelte van de digestion die door ProtectedClient wordt uitgevoerd, moet ook op dezelfde manier worden gedaan door de server. Daarom gebruikt de methode sendAuthentication() van de ProtectedClient, een statische methode, makeDigest(), deze wordt gedefinieerd in de Protection Klasse: import java.io.*; import java.security.*; public class Protection { public static byte[] makeDigest(String user, String password, long tl, double q1) throws noSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA"); 67
    • md.update(user.getBytes()); md.update(password.getBytes()); md.update(makeBytes(t1, q1); return md.digesto; } public static byte[] makebytes(long t, double q) { try { ByteArrayOutputStream byteout = new Byte.ArrayOutputStream(); DataOutputStream dataout = new DataOutputStream(byteOut); dataOut.writeLong(t); dataOut.writeDouble(q); return byteOut.toByteArray(); } } catch (I0Exception e) { return new byte[0]; } } Protection definieert twee statische methoden. De makeDigest() methode maakt een message digest van zijn input gegevens. De methode gebruikt daarbij de methode makeBytes(). Deze methode heeft als taak om long en double te converteren in een array van bytes. Aan de kant van de server is de procedure ongeveer hetzelfde. De ProtectedServer klasse heeft een methode lookupPassword(). Deze geeft het wachtwoord terug van de meegegeven user. In ons voorbeeld maken we gebruik van het terug geven van een wachtwoord voor de meegegeven gebruiker Henk. In een echte applicatie, zal deze methode aan een database of bestand worden gekoppeld die de gebruikersnamen en de wachtwoorden bevat: Import java.io.*; import java.net.*; import java.security.*; import Protection; public class ProtectedServer { public boolean authenticate(InputStream instream) throws I0Exception, NoSuchAlgoritException { DataInputStream in = new DataInputStream(inStream); String user = in.readUTF(); long t1 = in.readlong(); double q1 = in.readdouble(); int length in.readint(); byte[] protected1 = new byte[length]; in.readFully(protected1); } String password = lookupPassword(user); byte[] local = Protection.makeDigest(user, password, tl, q1); return MessageDigest.isEqual(protected1, local); protected String lookupPassword(String user) 68
    • { if user = “Henk” return “geheim”; } public static void main(String[] args) throws Exception { int port = 7999; ServerSocket s = new ServerSocket(port); Socket client = s.accept(); ProtectedServer server = new ProtectedServer(); if (server.authenticate(client.getInputStream()); System.out.println(“Client logged in.”); else System.out.println(“Client failed to log in.”); s.close(); } } 7.5.1.6 Dubbele sterkte wachtwoord login Er is ook een sterkere manier om wachtwoordinformatie te beschermen met behulp van message digests. Hierbij wordt gebruik gemaakt van een extra timestamp en random getal. Eerst wordt er een digest berekend, zoals in het eerste voorbeeld. Dan worden de digest waarde, een ander random getal en een andere timestamp gevoed aan een tweede digest. Hierna wordt de tweede digest waarde naar de server verzonden, samen met de timestamps en de random getallen. Waarom is dit beter dan de vorige manier die we hebben besproken? Om dit te begrijpen moet je denken op wat voor een manier je wilt proberen om deze methode te kraken. Bedankt dat een message digest een eenrichtingsfunctie is. In het ideale geval zou dit betekenen dat het onmogelijk is om er achter te komen welke input een bepaalde digest waarde heeft geproduceerd. In de praktijk kost het heel veel tijd om er achter te komen welke input een bepaalde digest waarde heeft geproduceerd. Dus, de beste manier is om het te proberen met een dictionary attack. Dit betekent zoals je al in de inleiding gelezen hebt, dat je één voor één wachtwoorden probeert. Eerst haal je ze door het simpele beveiligings schema, wat net beschreven is, en probeer je hiermee elke keer in te loggen. Op dit moment is het belangrijk om na te gaan hoeveel tijd het kost om een enkel wachtwoord uit te proberen. Bij het verdubbelen van de sterkte, het berekenen van twee digest waarden in plaats van één, wordt er voor gezorgd dat de tijd om het wachtwoord te kraken wordt verdubbeld. Meer informatie hierover is ook te vinden in de paragraaf over wachtzinnen, zout wordt zuur, verderop in paragraaf 7.6.8.1. Geen van de beide behandelde methoden voorkomt een dictionary attack op het wachtwoord. Een methode die dit wel voorkomt is te vinden op [21]. 7.5.2 Opdracht dubbele sterkte wachtwoord login Maak met behulp van de voorbeeldcode van de beveiligde wachtwoord login een dubbele sterkte wachtwoord login. Hiervoor hoeven alleen de klassen aangepast te worden. De klassen moeten dan gebruik maken van een extra timestamp, een extra random getal en de extra digest, zoals beschreven in paragraaf 7.4.1.6. 7.5.3 Message Authentication Codes: MACs Een bericht authenticatie code genaamd Message Authentication Code (MAC) is eigenlijk een versleutelde message digest. Evenals de zojuist besproken, message digest maakt een MAC gebruik van verschillende input gegevens om een digest waarde te berekenen. Een 69
    • verschil tussen MAC en message digest is dat MAC gebruik maakt van een sleutel om de digest waarde te berekenen. Dit maakt MAC bruikbaar voor het beschermen van de integriteit van gegevens die worden verzonden over een onveilig netwerk als het Internet. De javax.crypto.Mac klasse bevat een MAC. 7.5.3.1 MAC aanmaken Voor het maken van een MAC, maak je gebruik van een van de standaard methoden van zijn getInstance(): public static final Mac getInstance(String algorithm) throws NoSuchALgorithmException Deze methode geeft een nieuwe MAC terug voor het meegegeven algoritme. public static final Mac getInstance(String algorithm, String provider) throws NoSuchALgorithmException, NoSuchProviderException Deze methode geeft een nieuwe MAC terug voor het meegegeven algoritme en maakt gebruik van de meegegeven provider. Als je eenmaal de MAC hebt verkregen, dan moet je hem instellen met een sleutel. Je kunt eventueel ook gebruik maken van algoritme specifieke instellingen. public final void init(Key key) throws InvalidKeyException Gebruik deze methode voor het instellen van de MAC met de meegegeven sleutel. Er wordt een exception gegeven als de meegegeven sleutel niet gebruikt kan worden. public final void init(Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParamaterException Deze methode stelt de MAC met de meegegeven sleutel en algoritme specifieke parameters in. 7.5.3.2 MAC datainvoer Een Mac kent verschillende update() methoden om data toe tevoegen. Deze zijn net zoals de update() methoden bij MessageDigest: public final void update(byte input) throws IllegalStateException Deze methode voegt de meegegeven byte toe aan de input gegevens van de MAC. Als de MAC niet is ingesteld wordt er een exception gegeven. public final void update(byte[] input) throws IllegalStateException Gebruik deze methode om de gehele meegeven array van bytes toe te voegen aan de input gegevens van de MAC. public final void update(byte[] input, int offset, int len) throws IllegalStateException Deze methode voegt len bytes van de meegegeven array, beginnend bij offset, aan de MAC. 70
    • 7.5.3.3 Berekenen van de Code Om uiteindelijk de eigenlijke MAC waarde te laten berekenen, gebruik je een doFinal() methode: public final byte[] doFinal() throws IllegalStateException Deze methode geeft de MAC waarde terug en reset daarna de status van Mac weer. Je kunt een nieuwe Mac berekenen, met gebruik van dezelfde sleutel als eerder, door het aanroepen van update() met nieuwe gegevens. public final byte[] doFinal(byte[] output, int outOffset) throws IllegalStateException, ShortBufferException Deze methode plaatst de MAC waarde in een meegegeven array, beginnend op outOffset. Daarna reset de methode de status van MAC. public final byte[] doFinal(byte[] intput) throws IllegalStateException Deze methode voert de gehele meegegeven input array aan de MAC. Waarna de Mac waarde wordt berekend en teruggegeven. Hierna reset de methode de interne status van de MAC. Om de resultaten van eerdere aanroepen van update() ongedaan te maken, zonder een MAC waarde te berekenen, gebruik je de reset() methode: public final void reset() Deze methode zet de interne status van de MAC weer terug op de beginstand. Als je gebruik wil maken van een andere sleutel om een MAC waarde te berekenen, kan je Mac opnieuw instellen door het aanroepen van init(). 7.5.3.4 Voorbeeld van een MAC Het volgende voorbeeld laat het aanmaken van een MAC sleutel zien en berekend een MAC waarde: SecureRandom sr = new SecureRandom(); Byte[] keyBytes = new byte[20]; Sr.nextBytes(keyBytes); SecretKey key = new SecretKeySpec(keyBytes); Mac m = Mac.getInstance(“HmacSHA1”); m.init(key); m.update(inputData); byte[] mac = m.doFinal(); 7.5.4 Signatures Een signature voorziet in twee beveiligingsservices, authenticatie en integriteit. Meer over signatures is te lezen in paragraaf 1.4. De Java Security API bevat een klasse, java.security.Signature, waarmee het mogelijk is om cryptografische signatures te maken. De klasse werkt in twee verschillende modes, afhankelijk van het feit of je een signature wilt aanmaken of wilt verifiëren. Zoals ook bij de andere cryptografische klassen, heeft Signature twee standaard methoden: 71
    • public static Signature getInstance(String algorithm) throws NoSuchAlgorithmException Deze methode geeft een Signature terug voor het meegegeven algoritme. De eerste provider die het algoritme ondersteunt wordt gebruikt. public static Signature getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NosuchProviderException Deze methode geeft een Siganture terug voor het meegegeven algoritme. De meegegeven provider wordt gebruikt. De methoden om een Signature in te stellen: public final void initSign(PrivateKey privateKey) throws InvalidKeyException Gebruik bij het aanmaken van een signature deze methode om de Signature in te stellen met de meegegeven private key. public final void initSign(PrivateKey privateKey, SecureRandom random) throws InvalidKeyException Deze methode is hetzelfde als de vorige, alleen kan er hier een bron van Random bits worden meegegeven die gebruikt worden om de signature in te stellen. public void final initVerify(PublicKey publicKey) throws InvalidKeyException Gebruik deze of de volgende methode om een signature te verifiëren. Om een publieke sleutel te verifieren moet deze worden meegegeven aan deze methode. De publieke sleutel wordt dan vergeleken met de privé sleutel die is gebruikt bij het aanmaken van de signature. public void final initVerify(Certificate certificate) throws InvalidKeyException Zelfde als de vorige methode, alleen wordt hier gebruik gemaakt van het publieke sleutelgedeelte van het meegegeven certificaat. Voor het gebruiken van algoritmespecifieke instellingen voor een Signature object, wordt een AlgorithmParamaterSpec meegegeven aan de setParameter() methode. public final void setParameter(AlgorithmParameterSpec params) throws InvalidAlgorithmParamaterException Algoritmespecifieke parameters voor een Siganature object kunnen worden meegegeven aan dit object. Als de Signature de AlgorithmParameterSpec niet herkent wordt er een exception gegeven. public final void setParameter(String param, Object value) throws InvalidParameterException Met deze methode kan de waarde van een meegegeven parameter, param, worden gewijzigd in de meegegeven waarde. Dit maakt het mogelijk om alleen een specifieke parameter te wijzigen 72
    • Het voeren van gegevens aan een Signature gebeurt op dezelfde manier als bij een message digest door gebruik te maken van de update() methoden. Een SignatureException wordt gegeven als de Signature nog niet is ingesteld: public final void update(byte input) throws SignatureException Een enkele byte toevoegen aan de input van de Signature gaat door middel van deze methode. public final void update(byte[] input) throws SignatureException Deze methode voegt de meegegeven array van bytes toe aan de input van de Signature. public final void update(byte[] input, int offset, int len) throws SignatureException Deze methode voegt len bytes van de meegegeven array toe aan de input data van de Signature, beginnend bij offset. 7.5.4.1 Aanmaken van een Signature Ook het aanmaken ven een Signature lijkt veel op het aanmaken van een message digest. De methode sign() geeft de signature terug: public final byte[] sign() throws SignatureException Deze methode berekent een signature. Hiervoor maakt hij gebruik van de input data gegeven door de eerdere aanroepen van update(). Er wordt een SignatureException gegeven als de Signature niet goed is ingesteld. public final int sign(byte[] outbuf, int offset, int len) throws SignatureException Deze methode is dezelfde als de vorige, alleen worden nu len bytes in de meegegeven array geschreven, beginnend bij offset. Voor het aanmaken van een Signature, heb je de privé sleutel van de ondergetekende en het te ondertekenen bericht nodig. De procedure is vrij simpel: 1. Verkrijg een Signature object door het aanroepen van de standaardmethode getInstance(). Je zult een algoritme moeten specificeren. Een signature gebruikt meestal twee algoritmes. Eén om de message digest te berekenen en één om de message digest te coderen. De SUN provider die wordt geleverd met JDK ondersteunt DSA encryptie van een SHA-1 message digest. Dit wordt simpel aangegeven met DSA. 2. Stel de Signature in met de privé sleutel van de ondergetekende met behulp van de initsign() methode. 3. Gebruik een update() methode om de gegevens van het bericht aan de signature te voeren. Update() kan zo vaak als maar nodig worden aangeroepen. Hiervoor bestaan drie verschillende methoden. 4. Bereken de signature met behulp van de sign() methode. Deze methode geeft een array van bytes terug, of schrijft een aantal bytes in een array, die de signature voorstellen. Het is aan jou om de signature ergens op te slaan. 73
    • 7.5.4.2 Verifiëren van een Signature Een signature van geverifieerd worden met gehulp van de methode verify(): public final boolean verify(byte[] signature) throws SignatureException Deze methode gaat na of de meegegeven byte array (signature) klopt met de input data, die door de eerdere aanroepen van update() gegeven zijn. Als de Signature wordt goedgekeurd, wordt true teruggegeven. Als de Signature niet goed is ingesteld wordt een SignatureException gegeven. Het verifiëren van een signature lijkt veel op het maken van een signature. Eigenlijk zijn de stappen 1 tot en met 3 hetzelfde. De methode neemt aan dat er al een signature waarde bestaat. De volgende procedure verifieert of het ontvangen bericht dezelfde signature geeft. 1. Verkrijg een Signature object door het aanroepen van de standaard methode getInstance(). 2. Stel de Signature in met de privé sleutel van de ondergetekende met behulp van de initsign() methode. 3. Gebruik een update() methode om data aan de signature te voeren. 4. Kijk of je signature goed is door het aanroepen van de verify() methode. Deze methode accepteert eenbyte array, die de signature zijn, om te verifiëren. De methode geeft een Boolean terug die true is als de signature past bij het bericht. Anders wordt er false teruggegeven. 7.5.4.3 De klasse SignedObject JDK 1.2 bevat een nuttige klasse, java.security.SignedObject, wat elk Serializable object en een bijbehorende signature bevat. Je kunt een SignedObject maken met behulp van een Serializeable object, een privé sleutel en een Signature: public SignedObject(Serializeable object, PrivateKey signingKey, Signature singningEngine) throws IOException, InvalidKeyException, SignatureException Deze constructor maakt een SignedObject aan waarin het meegegeven Serializable object zit. Het object is serialized en daarna intern opgeslagen. Het serialized object wordt ondertekend met behulp van de meegegeven signature en privé sleutel. Een signature van een SignedObject kan geverifieerd worden met de methode verify(): public final boolean verify(PublicKey verificationKey, Signature verificationEngine) throws InvalidKeyException, SignatureException Deze methode controleert of de interne signature van het SignedObject past bij het object dat deze bevat. Hiervoor gebruikt de methode de meegegeven publieke sleutel en Signature. Zoals al eerder is vermeld hoeft hiervoor de Signature niet ingesteld te worden. De methode geeft een true terug als de signature van het SignedObject past bij het object dat deze bevat; dus dan is de integriteit van het object geverifieerd. Het object dat een SignedObject bevat kan verkregen worden door het aanroepen van de methode, getObject(): 74
    • public Object getObject() throws IOException, ClassNotFoundException Deze methode geeft het object dat SignedObject bevat terug. Het object is intern opgeslagen als een byte array; deze methode deserializes het object en geeft het terug. Om er zeker van de integriteit van het object te zijn, kun je de verify() methode aanroepen voor het aanroepen van deze methode. SignedObjects kunnen bijvoorbeeld worden gebruikt bij het versturen van gegevens zoals een gebruikersnaam een timestamp en andere login-gegevens tussen een client en een server. Deze gegevens worden dan in één object geplaatst en dit object kan dan weer in een SignedObject worden geplaatst waarna deze verstuurd kan worden. 7.5.5 Werken met certificaten Om een signature te verifiëren, heb je de publieke sleutel van de eigenaar nodig. Maar hoe weet je nu of de uitgave van deze sleutels wel veilig is. In het boek staat een stuk over certificaten en waarvoor deze worden gebruikt [15]. Met de komst van JDK 1.2 was het mogelijk om in Java X.509v3 certificaten te importeren en te verifiëren. Het is alleen nog niet mogelijk om een certificaat te produceren met behulp van de publieke API. 7.5.5.1 Java.security.cert.Certificate Bij JDK 1.1 werd de support voor certificaten geïntroduceerd, gebaseerd rond de java.security.Certificate interface. In JDK 1.2, werd deze interface vervangen, we zullen de oude versie dan ook niet behandelen. De klasse is vervangen door een abstracte klasse, java.security.cert.Certificate. Deze klasse is een stuk eenvoudiger dan zijn voorganger, en het bevat de mogelijkheid om een certificaat te verifiëren. Ondersteuning voor X.509 certificaten wordt geleverd in een aparte klasse, deze wordt in paragraaf 7.5.5.4 behandeld. Allereerst kan java.security.cert.Certificate een publieke sleutel bevatten: public abstract PublicKey getPublicKey() Deze methode geeft de publieke sleutel die het certificaat bevat terug. Een gecodeerde versie van de certificaat kan verkregen worden door het aanroepen van de methode getEncoded(). De data die deze methode terug geeft kan ook naar een bestand worden geschreven: public abstract byte[] getEncoded() throws CertificateEncodingException Deze methode geeft een gecodeerde versie van de certificaat terug. 7.5.5.2 Aanmaken van een Certificaat Vreemd genoeg, bestaat er geen programmeercode voor het maken van een certificaat van af scratch. Pas met JDK 1.3 kwam er een mogelijkheid, in de klasse java.security.cert.certificate: protected Object writeReplace() throws ObjectStreamException Deze methode vervangt een certificaat dat serialized moet worden. Hij geeft het vervangende certificaat Object, dat serialized moet worden, terug. Er wordt een exception gegeven als het nieuwe object die het certificaat voorsteld niet aangemaakt kan worden. 75
    • Het is ook mogelijk om een X.509 certificaat te lezen uit een bestand, dit gebeurt met de getInstance() methode in de klasse X509Certificate. Hier komen we paragraaf 7.5.5.4 op terug. 7.5.5.3 Verifiëren van een Certificaat Om de inhoud van een certificaat te verifiëren, gebruik je één van de verify() methoden: public abstract void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException Deze methode gebruikt de meegegeven publieke sleutel om de inhoud van het certificaat te verifiëren. De publieke sleutel moet passen bij de uitgever van het certificaat. Deze heeft dus niets te maken met de publieke sleutel die in de certificaat zit. De meegeleverde publieke sleutel wordt gebruikt om de interne signature van het certificaat te verifiëren. Deze signature beschermt de integriteit van de gegevens van het certificaat. public abstract void verify(PublicKey key, string sigProvider) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException Dit is dezelfde methode als de vorige, maar gebruikt speciaal de meegegeven provider om de implementatie van het signing-algoritme te ondersteunen. 7.5.5.4 X.509 certificaten Er zijn verschillende standaarden voor de inhoud van een certificaat. De meest populaire is X.509, uitgebracht door International Telecommunications Union (ITU). Er zijn drie versies van deze standaard. Hieronder volgen methoden waarmee de inhoud van een certificaat opgevraagd kan worden: int getVersion() Methode om de versie van een certificaat op te vragen. Geeft versie X.509 v1, v2, of v3. BigInteger getSerialNumber() Methode om het serienummer van de uitgever op te vragen. Dit nummer is uniek. String getSigAlgName() Methode om het gebruikte cryptografische algoritme wat gebruikt is voor de Signature op te vragen. Principal getIssuerDN() Hiermee kan de naam van de uitgever van het certificaat worden opgevraagd. Date getNotBefore(), Date getNotAfter() Methode om de geldigheidsperiode, begin en eind datum op te vragen. 76
    • Principal getSubjectDN() Methode om de naam van aanvrager van het certificaat op te vragen. PublicKey getPublicKey() Deze methode is een afgeleide van Certificate, hiermee kan de publieke sleutel van de aanvrager worden verkregen. Boolean[] getIssuerUniqueID() Methode om de unieke code van de uitgever op te vragen. Alleen bij versie 2 en 3. Boolean[] getSubjectUniqueID() Methode om de unieke code van de aanvrager op te vragen. Alleen bij versie 2 en 3. Boolean[] getKeyUsage(), int getBasicConstraints() Methoden om extra gegevens op te vragen, alleen versie 3. Byte[] getSignature() Methode voor het opvragen van een Signature van alle voorgaande velden. Voor het opvragen van een X.509 certificaat uit een bestand, kan de methode getInstance() gebruikt worden: public static final X509Certificate getInstance(InputStream InStream) throws CertificateException Deze methode doet een aanvraag voor een concrete sub-klasse van X509Certificate en stelt deze in met de meegegeven input stream. public static final X509Certificate getInstance(byte[] certData) throws CertificateException Deze methode werkt zoals de voorgaande, alleen wordt nu de meegegeven byte[] gebruikt bij het instellen van het nieuwe certificaat. De manier waarop getInstance() werkt is een beetje vreemd. Er wordt namelijk een object gemaakt en door gegevens toe te voegen aan het java.seurity eigenschappenbestand. Dit bestand is te vinden in de lib/security directory, in de JDK installatie directory. Standaard ziet de toegevoegde regel er als volgt uit: cert.provider.x509 = sun.security.x509.X509CertImpl Laten we er even van uit gaan date je getInstance() aanroept door middel van een input stream. Een sun.security.x509.X509CertImpl. wordt aangemaakt, door middel van een constructor die de input stream accepteert. Het is nu aan de X509CertImpl om de gegevens van de inputstream te lezen om zichzelf in te stellen. X509CertImplweet hoe hij zichzelf moet aanmaken van een DER-gecodeerd certificaat. Wat is DER? In de X.509 standaard, wordt een certificaat gespecificeerd als een gegevensstructuur waarbij gebruik wordt gemaakt van de ASN.1 (Abstract Syntax 77
    • Notation) taal. Er zijn een paar verschillende manieren waarop ASN.1 gegevensstructuren kunnen worden omgezet in een byte stream, en DER (Distinguished Encoding Rules) is hier een van. Het resultaat hiervan is dat X509CertImpl een X.509 kan herkennen, ook als het DERgecodeerd is. 7.5.5.5 Certificate Revocation Lists Vanaf JDK 1.2 komt er nog een te kort koming van JDK 1.1 certificaat ondersteuning aan het licht: Certificate Revocation Lists (CRLs). Hier wordt de vraag beantwoord over wat er met gestolen of verloren geraakte certificaten gebeurt. Een CRL is simpel gezegd gewoon een lijst met daarop alle certificaten die niet meer geldig zijn. (Helaas bestaat er nog geen standaard voor de manier waarop CRLs worden gepubliceerd; waarschijnlijk gebeurt dit door de CAs op een of andere manier.) Vanaf versie 1.2 bevat JDK twee klassen voor de ondersteuning van CRLs. De eerste, java.security.cert.X509CRL, implementeert een CRL zoals deze is gespecificeerd in de X.509 standaard. Een X509CRL kan worden gemaakt vanuit een bestand met behulp van getInstance(), netzoals met X509Certificate: public static final X509CRL getInstance(InputStream inStream) throws CRLException, X509ExtensionException Deze methode maakt een concrete subklasse aan van X509CRL en stelt deze in op de meegegeven input stream. public static final X509CRL getInstance(byte[] crlData) throws CRLException, X509ExtensionException Deze methode werkt zoals de voorgaande, alleen wordt de meegegeven byte gebruikt om de X509CRL in te stellen. De getInstance() methode werkt in veel opzichten hetzelfde als die van X509Certificate. De eigenlijke sub-klasse van X509CRL die wordt terug gegeven door getInstance() wordt (opnieuw) bepaald door een gegeven in het bestand java.security. He relevante gegeven voor CRLs is: crl.provider.x509=sun.security.x509.X509CRLImpl. X509CRL is in verschillende manieren gelijk aan X509Certificate. Het bevat de methoden getEncoded() en verify() die hetzelfde doen als in X509Certificate. Daarnaast bevat het ook methoden die informatie over de CRL zelf teruggeven, zoals getIssuerDN() en getSigAlgNam(). Om er achter te komen of een bepaald certificaat is ingetrokken, kun je gebruik maken van de methode isRevoked(): public abstract boolean isRevoked(BigInteger serialNumber) Deze methode geeft true terug als een certificaat die past bij het meegegeven seriële nummer is ingetrokken. De seriële nummers zijn uniek aan een Certificaten Authoroteit (CA). Elke CA geeft zijn eigen CRLs uit. Dus wordt deze methode gebruikt om seriële nummers na te gaan van één zelfde CA. Als je meer informatie nodig hebt over een ingetrokken certificaat, kan je de methoden getRevokedCertificate() en getRevokedCertificates() gebruiken. Deze geven instanties terug van java.security.cert.RevokedCertificate, die gebruikt kunnen worden om de gegevens van de intrekking te bekijken: 78
    • public abstract RevokedCertificate getRevokedCertificate(BigInteger serialNumber) throws CRLException Deze methode geeft de RevokedCertificate terug die correspondeert met het meegegeven seriële nummer. public abstract Set getRevokedCertificates() throws CRLException Deze methode geeft een verzameling van alle ingetrokken certificaten terug, die deze X509CRL bevat. 7.6 Encryptie Voor het versleutelen van gegevens is een Cipher nodig. Er zijn, zoals bekend is, drie verschillende versleutelingen mogelijk, namelijk: • Symmetrische (privé sleutels) encryptie. • Asymmetrische (publieke sleutel) encryptie. • Hybride (combinatie van privé en publieke sleutels) encryptie. 7.6.1 Stroom- en blokvercijfering Bij symmetrische versleuteling zijn er twee mogelijkheden om gegevens te versleutelen. Dit kan namelijk per blok gaan of over een gehele stroom van gegevens. De versleuteling van blokken kan, mits de juiste mode wordt gebruikt, ook worden gebruikt om een gegevensstroom te versleutelen (bijvoorbeeld CFB). 7.6.2 Padding Bij blokciphers is het soms nodig dat de te coderen tekst een veelvoud van een aantal bytes is, een veelvoud van één blok (bijvoorbeeld 64 bits). Om de tekst aan te vullen tot het benodigde aantal bytes wordt padding gebruikt. Er zijn veel verschillende manieren om padding te implementeren. Wij behandelen één manier. Alle padding methodes zijn wel ongeveer hetzelfde. Waar het om gaat is het aanvullen van het laatste blok met (random) data. Deze data moet op één of andere manier na het weer decoderen van de tekst worden verwijderd. Er moet dus ergens in het padding gedeelte van de tekst worden bijgehouden waar de padding staat. Aan de hand van PKCS#5 wordt dit wat uitgelegd. 7.6.3 PKCS#5 We hebben het hier over blokvercijfering van bytes met een lengte van 8 bits. PKCS#5, Public-Key Crypthography Standard, maakt gebruik van een padding methode die makkelijk in elkaar zit. Het idee is om het aantal resterende bytes in een blok te vullen met bytes die het nummer van het nog resterende aantal bytes van het blok voorstellen. Voorbeelden: Stel je gebruikt 64 bits blokken, en het laatste blok (8 bytes) is gevuld met 5 bytes aan gewone tekst. Dan worden de laatste 3 bytes opgevuld met 3. Bevat het laatste blok 2 bytes aan gewone tekst, dan worden de overige 6 bytes gevuld met 6. Data die precies stopt op een blokgrens krijgt een extra padding blok mee. Dit blok bevat 8 bytes gevuld met 8. Het lijkt misschien vreemd dat dit gehele extra blok met padding data wordt toegevoegd. Maar als bijvoorbeeld het vorige blok met gewone tekst gevuld was en de laatste 3 bytes waren elk gevuld met 3, dan worden deze bij decodering verwijderd. Om deze reden wordt padding altijd toegevoegd bij coderen, het maakt niet 79
    • uit wat de originele lengte van de gewone tekst is. Padding wordt ook altijd weer verwijderd bij het decoderen. Informatie over de gebruikte padding methode van een Cipher kun je opvragen door de getPadding() methode te gebruiken. Bij de SunJava providers PKCS#5 padding, ‘PKCS5Padding’ genoemd. Meer informatie over PKCS#5 is te vinden op de website van RSA Data Security, Inc. [22]. 7.6.4 Blokvercijfering modes Bij het bespreken van DES hebben we al verschillende modes van blokvercijfering bekeken, zie hoofstuk 2 van deze syllabus. 7.6.5 Algoritmen Het mooie van de opbouw van de provider in de Secirity API is dat het mogelijk is om verschillende cryprografische algoritmes te gebruiken, zonder je programma te hoeven veranderen. Voor meer uitleg over deze provider verwijs ik naar het hoofdstuk over providers. De SunJCE provider geeft de mogelijkheid om gebruik te maken van drie algoritmen. Maar andere providers bieden weer andere algoritmen. Je kunt zelf kiezen welke je nodig denkt te hebben. De meeste algoritmes worden in dit dictaat of in het boek besproken. Hier volgt een kort overzicht van de mogelijke algoritmen en hun providers. Zie de inleiding voor de websites van deze bedrijven. Algoritme Provider(s) DES SunJCE, Cryptix, IAIK, JCP DESede (trriple DES) SunJCE, Cryptix (DES-EDE3), IAIK (3DES), JCP PBEWithMD5AndDES SunJCE RSA Cryptix, IAIK, JSAFE Blowfish Cryptix IDEA Cryptix, IAIK, JCP SPEED Cryptix RC2 IAIK, Cryptix RC4 IAIK, Cryptix, JCP CAST5 Cryptix LOKI91 Cryptix SAFER Cryptix Square Cryptix 7.6.6 Cipher Javax.crypto.Cipher is onderdeel van JCE, helaas zit hier een exportverbod op. Ik verwijs voor een alternatief voor JCE naar de inleiding, paragraaf 7.2. De uitleg die nu volgt geldt eigenlijk voor JCE van Sun, maar andere providers die JCE hebben geïmplemteerd 80
    • hebben dit gebaseerd op de documentatie van Sun. Dit houdt in dat het op dezelfde manier gebruikt kan worden. Ook Cipher is een abstracte klasse. Net zoals de klassen van JCA die we al eerder hebben bekeken. Werken met een Cipher kun je onderscheiden in drie stappen: 1. Verkrijg een Cipher door het aanroepen van GetInstance(), standaard methode. 2. Start de Cipher voor het versleutelen of ontsleutelen door middel van init(). 3. Versleutel of ontsleutel de datadoor gebruik te maken van de update() en doFinal() methoden. Het aanmaken van een Cipher gaat bijvoorbeeld als volgt: Cipher cipher = Cipher.getInstance(“DES/ECB/PKCS5Padding”); Cipher.init(Cipher.ENCRYPT_MODE, key); Byte[] raw = cipher.doFinal(stringBytes); Zoals je kunt zien wordt bij het aanroepen van getInstance()meer dan alleen maar een algoritmenaam meegegeven. Er wordt een algoritme (DES), een mode (ECB) en een padding methode (PKCS5Padding) mee gegeven. Aan GetInstance() kunnen twee soorten strings worden mee gegeven. 1. Alleen de naam van het algoritme dat je wilt gebruiken. De provider die de implementatie heeft geleverd zorgt voor een standaard mode en padding methode. 2. De naam van het algoritme, mode en de padding methodegescheiden door een ‘/’ zoals in het voorbeeld te zien is. 7.6.6.1 Verkrijgen van een Cipher De standaardmethoden van Cipher lijken erg op die in JCA, dus ze zijn gedeeltelijk al bekend: public staticCipher getInstance(String algorithm) throws NoSuchAlgorithmException, NoSuchPaddingException Deze standaardmethode geeft een Cipher terug voor het aangegeven algoritme. De naam van het algoritme bevat normaal extra informatie, zoals een padding methode en een cipher mode. public static Cipher getInstance(String algorithm, String provider) throws NoSuchAlgoritmException, NoSuchPaddingException Deze methode is hetzelfde als de vorige, maar het maakt gebruik van de aangegeven provider voor de implementatie van het aangegeven algoritme. Net zoals er standaard algoritmen zijn, zijn er ook standaard namen voor de cipher modes en padding methoden die worden ondersteund door JCE. Let op dat er bij de OFB en CFB mode ook de mogelijk is om het aantal te gebruiken bits op te geven. Wordt er geen bitgrootte meegegeven, dan wordt de blokgrootte van de cipher gebruikt. Hieronder volgt een overzicht van de standaardnamen. Alle padding methoden verwijzen naar JCE cipher algoritmen, DES en DESede. Naam Omschrijving ECB Electronic code book mode 81
    • CBC Cipher block chaining mode PCBC Propagating cipher block chaining mode CFBn Cipher feedback mode, using n bits per operation OFBn Output feedback mode, using n bits per operation* NoPadding No Padding PKCS5Padding PKCS#5-style padding *Bij OFB moet de blokgrootte dezelfde grootte hebben als de cipher blokgrootte. Dit is standaard als er geen bitgrootte wordt aangegeven. 7.6.6.2 Basis informatie Verder zijn er ook nog de methoden die informatie geven over de cipher. public final Provider getProvider() Deze methode geeft de cryptografische provider van de Cipher. public final int get BlockSize() Deze methode geeft de blokgrootte van een cipher, in bytes. public final int get OutputSize(int inputLen) throws IllegalStateException Deze methode berekent de outputgrootte voor de eerst volgende aanroep van update()of doFinal(), door een inputgrootte mee te geven. De grootten worden gegeven in bytes. Als de cipher nog niet is aangemaakt komt er een exception. Deze methode geeft een maximale grootte, maar het aanroepen van update() of DoFinal() met deze grootte als input, kan resulteren in een kortere outputlengte dan gegeven door deze methode. public final byte[] getIV() Deze methode geeft de IV die wordt gebruikt om data te coderen. Deze methode geldt alleen voor cipher modes die IV gebruiken. Een Cipher in ECB mode, zal null terug krijgen van deze methode omdat ECB geen IV gebruikt. De methode kan direct na het aanmaken van de Cipher voor encryptie worden aangeroepen om de IV te achterhalen. Deze zelfde IV moet ook weer worden gebruikt om de Cipher voor decryptie aan te maken. 7.6.6.3 Instellen van een Cipher De cipher kan ingesteld worden voor het coderen of decoderen van gegevens, dit gebeurt door gebruik temaken van constanten die gedefinieerd zijn in de Cipher klasse: public static final int ENCRYPT_MODE public static final int DECRYPT_MODE Gebruik een van deze twee constanten en een init() methode om een Cipher in te stellen om te coderen of te decoderen. 82
    • Cipher levert vier overloaded init()methoden. Je kunt de Cipher op elk moment geheel opnieuw instellen door het aanroepen van een van de init() methoden. Algemeen Twee van de init() methoden van Cipher zijn algoritme afhankelijk. Als je in je applicatie met zorg omgaat met de met deze methoden, dan is het mogelijk om te wisselen van het gebruikte algoritme zonder dat de applicatie aangepast hoeft te worden. Als we kijken naar de modulaire afkomst van de architectuur van de provider, dan zou het mooi zijn als de gebruikers van je applicatie het sterkste geïnstalleerde algoritme kunnen kiezen om te gebruiken met jouw applicatie. public final void init(int opmode, Key key) throws InvalidKeyException Deze methode stelt de Cipher in om te coderen of te decoderen, met behulp van de gegeven sleutel. Opmode moet ENCRYPT_MODE of DECRYPT_MODE zijn. Er wordt een exception gegeven als er een verkeerd type sleutel wordt meegegeven. public final void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException Zoals de vorige methode, alleen zal de Cipher nu de meegegeven SecureRandom gebruiken voor het aanmaken van eigen random getallen. Specifiek Soms is het niet mogelijk om een Cipher, in een algoritme afhankelijke manier, goed in te stellen. Als dit het geval is, dan kan de Cipher ingesteld worden door middel van parameters die worden gedefinieerd in een java.security.AlgorithmParameterSpec object. In paragraaf zullen zien we een voorbeeld wat gebaseerd is op deze techniek bij wachtzin encryptie, paragraaf 7.6.8. public final void init(int opmode, Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException Met deze methode is het mogelijk om de Cipher in te stellen met algoritme afhankelijke parameters. public final void init(int opmode, Key key, AlgorithmParameterSpec params, secureRandom random) throws InvalidKeyException, invalidAlgorithmPara-meterException Zoals de vorige methode, alleen zal de Cipher nu de meegegeven SecureRandom gebruiken voor het aanmaken van eigen random getallen. Feedback ciphers moeten worden gemaakt met behulp van IV, om gegevens juist te kunnen decoderen. Om IV te kunnen gebruiken is een speciaal parameter object nodig, javax.spec.IvparameterSpec. Dit parameter object bevat dan de IV. De volgende code geeft een voorbeeld van een mogelijke implementatie van een Cipher voor het decoderen met behulp van IV: //Eerst moeten er een IV, een byte array, een sessionkey //en een DES key bestaan. Cipher cipher = Cipher.getInstance(“DES/CBC/PKCS5Padding”); IvParameterSpec spec = new IvParameterSpec(iv); cipher.init(Cipher.DECRYPT_MODE, sessionKey, spec); 83
    • 7.6.6.4 Een Cipher vullen met gegevens Een Cipher vervormt gegevens per blok, door te coderen of te decoderen. De twee methoden, update() en doFinal(), worden gebruikt om de gegevens aan de Cipher te voeren. Er zijn vier overloaded versies van update(): public final byte[] update(byte[] input) throws IllegalStateException Deze methode voegt, de meegegeven array van, invoer gegevens toe aan de Cipher. Als de Cipher genoeg data heeft om een blok mee te vullen, dan doet de Cipher dit. Wvervolgens geeft de Cipher de omgevormde gegevensblokken terug. Gegevens die over zijn gebleven omdat er geen geheel blok meer mee gevuld kan worden, worden bewaard om gebuikt te worden bij een volgende aanroep van update() of doFinal(). public final byte[] update(byte[] input, int inputOffset, int inputLen) throws IllegalStateException Zelfde als de vorige methode, behalve dat nu inputLen bytes, van de meegegeven byte array, worden meegegeven, beginnend op inputOffset. public final int update(byte[] input, int inputOffset, int inputLen, byte[] output) throws IllegalStateException, ShortBufferException Hetzelfde als de voorgaande update() methoden. Alleen wordt de output geschreven in de meegegeven output array. Is het output array te klein om de resultaten van update() te bevatten, dan wordt er een ShortBufferException gegeven. De methode geeft het totale aantal bytes terug, die in de output array zijn geschreven. public final int update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws IllegalStateException, ShortBufferException Zoals de voorgaande methoden, alleen wordt hier de output geschreven in de meegegeven output array, beginnend bij outputOffset. Zoals bij de vorige methode wordt er weer een ShortBufferException gegeven als de output array te klein is. Laten we nu wat voorbeelden gaan bekijken, hoe update() daadwerkelijk werkt. We gaan er in de volgende voorbeelden vanuit dat er al een DES key is aangemaakt. Cipher cipher = Cipher.getInstance(“DES/ECB/PKCS5Padding”); cipher.init(Cipher.ENCRYPTMODE, key); byte[] plain5 = “comic”.getbytes(); byte[] plain7 = “serious”.getbytes(); byte[] step1 = cipher.update(plain5); byte[] step2 = cipher.update(plain7); De blokgrootte van DES is 8 bytes (64 bits). Bij de eerste aanroep van update(), worden er maar 5 bytes mee gegeven, dit is niet genoeg om een blok te vullen. Er worden dus geen gegevens terug gegeven en de lengte van de array step1 is 0. De volgende aanroep van update() voegt 7 bytes toe, in het totaal zijn er dus nu 12 bytes. Dit is voldoende om één blok te vullen en terug te geven, met gecodeerde gegevens. De array step2 heeft een grootte van 8 bytes en bevat het eerste blok aan gecodeerde tekst. Wat is er gebeurd met de laatste 4 bytes? De Cipher bevat deze nog steeds, je kunt ze coderen door het aanroepen van de doFinal() methode, als ze het einde zijn van de ongecodeerde tekst. 84
    • Maar er is ook een andere, misschien betere, manier dan het vorige voorbeeld. Het ligt eraan voor welk doel je de implementatie wilt gebruiken: Cipher cipher = Cipher.getInstance(“DES/ECB/PKCS5Padding”); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] plain5 = “comic”.getbytes(); byte[] plain7 = “serious”.getbytes(); int outputLenght = cipher.getOutputSize(plain5.length + plain7.length); byte[] ciphertext = new byte[outputLength]; int length1 = cipher.update(plain5, 0, plain5.length, ciphertext); int length2 = cipher.update(plain7, 0, plain7.length, ciphertext); Eerst vragen we Cipher hoe groot de output zal zijn van de volledige input. Dit is de totale lengte van alle platte tekst arrays, 12 bytes. Omdat er gebruik wordt gemaakt van een padding cipher, zal het tweede niet volledige blok aangevuld worden met padding gegevens. Hierdoor berekent Cipher een output grootte van 16 bytes. We maken vervolgens een array aan met deze grootte, genaamd ciphertext. Vervolgens schrijven wij de outputdata in de array. De eerste aanroep van update(), schrijft geen gegevens en geeft 0 terug. De tweede aanroep codeert één blok en schrijft deze in de meegegeven array. Om Cipher te vertellen dat hij het coderen of decoderen kan afronden hebben we een methode doFinal() nodig. Er zijn zes verschillende methodes doFinal(), maar ze doen standaard allemaal ongeveer hetzelfde: public final byte[] doFinal() throws IllegalStateException, IllegalBlockSizeException, BadPaddingException Deze methode vertelt de Cipher om een codeer- of decodeeroperatie af te ronden. Alle overgebleven gegevens van eerdere aanroepen van update() worden verwerkt. De gegevens worden aangevuld met padding data, als er gebruik wordt gemaakt van een padding cipher. De output wordt teruggegeven als een byte array. Als de Cipher niet bestaat, wordt er een IllegalStateException gegeven. Bij coderen wordt er een IllegalBlocksizeException gegeven, als de blokgrootte van de input data niet een meervoud is van de blokgrootte van de gebruikte cipher en als er geen padding wordt gebruikt. Bij decoderen wordt er een IllegalBlocksizeException gegeven, als de grootte van de input data geen geheel aantal blokken vormt. Een BadPaddingException wordt gegeven door padding Ciphers als de gedecodeerde platte tekst geen geldige padding bevat. public final int doFinal(byte[] output, int outputOffset) throws IllegalStateException, IllegalBlockSizeException, ShortbufferException, BadPaddingException Zoals de vorige, alleen wordt de output weggeschreven in de meegegeven array, beginnend bij outputoffset. Het aantal output bytes wordt terug gegeven. Er wordt een ShortBufferException gegeven als de output array te klein is. public final byte[] doFinal(byte[] input) throws IllegalStateException, IllegalBlockSizeException, BadPaddingException Gebruik deze methode om de meegegeven input gegevens aan de Cipher toe te voegen en om daarna een codeer- of decodeeroperatie af te sluiten. Het is gelijk aan 85
    • het aanroepen van update(input), gevolgd door doFinal(), alleen wordt de output van beide stappen hier wordt teruggegeven. public final byte[] doFinal(byte[] input, int inputOffset, int inputLen) throws IllegalStateException, IllegalBlockSizeException, BadPaddingException Deze methode is dezelfde als de vorige, behalve dat er gebruik wordt gemaakt van inputLen bytes van de meegegeven array, beginnend bij inputOffset. public final int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output) throws IllegalStateException, IllegalBlockSizeException, ShortbufferException, BadPaddingException Zelfde als de vorige, alleen worden nu de output gegevens geschreven in de meegegeven array. Er wordt een ShortBufferException gegeven als de output array te klein is. public final int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws IllegalStateException, IllegalBlockSizeException, ShortbufferException, BadPaddingException Zelfde als de voorgaande methode, alleen wordt er begonnen met het schrijven van de output gegevens op de meegegeven outputOffset. Om te kijken hoe doFinal() nu daadwerkelijk werkt kijken we weer even naar de voorbeelden, we voegen doFinal() toe aan het einde: Cipher cipher = Cipher.getInstance(“DES/ECB/PKCS5Padding”); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] plain5 = “comic”.getbytes(); byte[] plain7 = “serious”.getbytes(); int outputLenght = cipher.getOutputSize(plain5.length + plain7.length); byte[] ciphertext = new byte[outputLength]; int length1 = cipher.update(plain5, 0, plain5.length, ciphertext); int length2 = cipher.update(plain7, 0, plain7.length, ciphertext); int length3 = cipher.doFinal(ciphertext, length1 + length2); Zoals bij het vorige voorbeeld hebben we 12 bytes aan de Cipher toegevoegd door update() te gebruiken. Eén blok is gecodeerd en er blijven 4 bytes over. De aanroep van doFinal() zorgt ervoor dat de Cipher in het laatste blok de nodige padding gegevens toevoegt zodat er een volledig 8-byte blok ontstaat. Dit blok wordt vervolgens gecodeerd en weggeschreven in onze ciphertext array. De waarde van length3 is 8, de lengte van het gecodeerde tekstblok gemaakt door het aanroepen van doFinal(). Het voorbeeld is bit georiënteerd. In veel gevallen kun je gegevens ook coderen of decoderen met maar één enkele aanroep van doFinal(), zoals het volgende voorbeeld: Cipher cipher = Cipher.getInstance(“DES/ECB/PKCS5Padding”); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] plaintext = “comicserious”.getBytes(); byte[] ciphertext = cipher.doFinal(plaintext); 86
    • 7.6.7 Familie van Cipher 7.6.7.1 Stroom Cipher Soms is het niet mogelijk om al je data in een keer te coderen of decoderen. Kan dit wel, dan heb je alleen maar één aaroep nodig van doFinal(), zoals we in het voorgaande voorbeeld hebben gezien. Soms moet je de data stukje voor stukje coderen. Het is niet handig om alle data in één keer in het geheugen te laden en te coderen. JCE bevat twee klassen die het probleem van het coderen of decoderen van gegevensstromen oplossen. javax.crypto.CipherInputStream en javax.crypto.CipherOutputStream kunnen gemakkelijk gebruikt worden voor het coderen of decoderen van de gegevens. Het zijn subklassen van de standaard klassen FilterInputStream en FilterOutputStream, hierdoor kun je ze gemakkelijk gebruiken met de rest van de stream klassen uit de java.io package. Je maakt een stream aan door een onderliggende stroom te specificeren (zoals met alle ‘filtered streams’) en er moet een Cipher object worden gestart. Let wel op dat je de cipher stream klassen niet door de war haalt met stream ciphers. CipherInputStream en CipherOutputStream zijn stream klassen die elke cipher kunnen gebruiken om gegevens te coderen of te decoderen. Het volgende voorbeeld laat de werking van een Cipher Stream zien. Het is een programma genaamt Cloak. Cloak codeert en decodeert bestanden. Het leest de privé sleutel uit het bestand SecretKey.ser. Als dat bestand niet bestaat, maakt Cloak een nieuwe sleutel aan en bewaart deze in een nieuw bestand, SecretKey.ser. Het inputbestand wordt gelezen met een normale FileInputStream. Het bestand wordt gecodeerd of gedecodeerd met behulp van een CipherOutputStream: import java.io.*; import java.security.*; import javax.crypto.*; public class Cloak { public static final int kBufferSize = 8192; public static void main(String[] args) throws Exception { // Check argument. if (args.length < 3) System.out.println(“Usage: Cloak –e -d inputfile outputfile”); return; } //Get or create key. Key key; try { ObjectinputStream in = new ObjectInputStream(new FileInputStream(“SecretKey.ser”)); key = (Key)in.readObject(); in.close(); } Catch(Exception e) { KeyGenerator generator = KeyGenerator.getInstance(“DES”); generator.init(new SecureRandom()); key = generator.generatekey(); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(“SecretKey.ser”)); out.writeObject(key); 87
    • } out.close(); //Get a cipher object. Cipher cipher = Cipher.getInstance(“DES/ECB/PKCS5Padding”); // Encrypt or decrypt. if (args[O].indexOf(“e”) != -1) cipher.init(Cipher.ENCRYPT_MODE, key); else cipher.init(Cipher.DECRYPT_MODE, key); } FileInputStream in = new FileInputStream(args[1]); FileOutputStream fileout = new FileOutputStream(args[2]); CipherOutputStream out = new CipherOutputStream(fileOut, cipher); byte[] buffer = new byte[kBufferSize]; int length; while ((length = in.read(buffer)) != -1) out.write(buffer, 0, length); in.close(); out.close(); } 7.6.7.2 javax.crypto.SealedObject JCE 1.2 bevat een utility die gebruikt maakt van encryptie, javax.crypto.SealedObject. Instances van deze klasse werken als containers voor andere objecten. Het object dat in de container zit wordt gecodeerd om deze te beveiligen. Je kunt een SealedObject aanmaken om elk willekeurig Serializable object te bevatten: public SealedObject(Serializable object, Cipher c) throws IOException, IllegalBlockSizeException Deze constructor maakt een SealedObject aan rond het meegegeven Serializable object. De meegegeven cipher wordt gebruikt om het object te coderen. De cipher moet al wel zijn ingesteld om te coderen. Als er een fout optreed bij het serializen of coderen van het object, dan wordt er een Exception gegeven. Om het originele, ongecodeerde, object weer terug te krijgen, gebruik je getObject(): public final Object getObject(Cipher c) throws IOException, ClassNotFoundException, IlegalBlockSizeException, BadPaddingException Deze methode decodeert het object dat het SealedObject bevat met de meegegeven Cipher. Er worden exceptions gegeven als de Cipher niet goed is ingesteld of als er een fout is opgetreden met de padding. Laten we als voorbeeld nemen dat we een object willen serializen om het vervolgens over een netwerkconnectie te versturen. Om te voorkomen dat spionnen de inhoud van het object kunnen bekijken. Of om te voorkomen dat zij het object kunnen deserializen. Hiervoor kun je SealedObject gebruiken. Zonder cryptografische beveiliging zal de code er als volgt uitzien: //set up the socket connection ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); 88
    • out.writeObject(secretObject); Het versturen van een gecodeerd object komt er als volgt uit te zien: //set up the socket connection and obtain the key ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); Cipher cipher = Cipher.getInstance(“DES/ECB/PKCS5Padding”); cipher.init(Cipher.ENCRYPT_MODE, key); SealedObject so = new SealedObject(secretObject, cipher); out.writeObject(so); Aan de andere kant van de netwerkconnectie, moet je het SealedObject weer deserializen en zijn inhoud terug krijgen, gebruik hiervoor getObject(): //set up the socket connection and obtain the key ObjectInputStream in = new ObjectInputStream(socket.getInputStream()); SealedObject so = (SealedObject)in.readObject(); Cipher cipher = Cipher.getInstance(“DES/ECB/PKCS5Padding”); cipher.init(Cipher.DECRYPT_MODE, key); Object secretObject = so.getObject(cipher); 7.6.8 Wachtzin Encryptie Wachtzin encryptie (passphrase encryption) is een snelle en directe manier om data te coderen. In plaats van het gebruiken van een privé sleutel uit een bestand, wordt de wachtzin gebruikt om een sleutel te genereren. Een wachtzin is een zin die door een persoon onthouden en ingetypt kan worden. Hierdoor is opslag van de sleutel op een bepaalde plaats overbodig. Een wachtzin is net als een wachtwoord, behalve dat deze meestal langer is. Er wordt een waarde afgeleidt van de wachtzin. Deze afgeleide waarde wordt gebruikt voor het aanmaken van een sleutel voor een symmetrische cipher. Encryptie met wachtzinnen kent, zoals al eerder genoemd in deze syllabus en de stof van het boek, ook veel nadelen. Maar het kan heel goed gebruikt worden voor simpele encryptie waar dit veilig genoeg is. 7.6.8.1 Zout maakt zuur Om de efficiëntie van een dictionary attack zo klein mogelijk te maken kunnen we een beetje zout gebruiken. Een aanvaller kan de sleutel achterhalen door te kijken of hij elk stukje gecodeerde tekst kan decoderen. Dit kan omdat voor elk stukje tekst dezelfde wachtzin wordt gebruikt. Het zout is extra toegevoegde data aan de wachtzin. Nu worden de wachtzin en het zout samen verwerkt tot de message digest. Om nu er achter te komen wat de sleutel is moet het woordenboek van de aanvaller veel meer woorden bevatten. Namelijk één voor elke mogelijke wachtzin en één voor elke waarde van zout. Om dit te begrijpen moet je je een simpele dictionary voorstellen wat door de aanvaller gebruikt wordt. Deze bevat maar drie mogelijkheden voor een DES sleutel gebaseerd op algemene wachtzinnen. Voor het voorbeeld maken we gebruik van md5(). Dit geeft aan dat we een md5 (message digesting) operatie uitvoeren. Voor meer informatie over md5 verwijs ik naar de stof over DES in hoofdsuk 2: md5(gandalf) md5(sex) md5(secret) Als de aanvaller gegevens vindt die met een wachtzin zijn gecodeerd, kan hij de drie van tevoren gecreëerde sleutels uit het woordenboek gebruiken om de gegevens te decoderen. Hierna kan hij kijken of er ook nog iets zinnigs uitkomt. Laten we kijken naar hoe het 89
    • zout het leven van de aanvaller zuur maakt. We gaan uit van twee bits aan zout, die een nummer van 0 tot en met 3 voorstellen. Het woordenboek van de aanvaller moet de volgende DES sleutel mogelijkheden bevatten: md5(0, gandalf) md5(0, sex) md5(0, secret) md5(1, gandalf) md5(1, sex) md5(1, secret) md5(2, gandalf) md5(2, sex) md5(2, secret) md5(3, gandalf) md5(3, sex) md5(3, secret) Door het toevoegen van twee bits zout, wordt de grootte van het woordenboek vergroot met vier. Als je gebruik maakt van 64 bits zout, zoals beschreven in deze paragraaf, wordt grootte van de database vermenigvuldigd met 2^64, en dat is een groot getal. Herhalingen zijn een andere manier om dictionary attacks tegen te gaan. We nemen weer hetzelfde voorbeeld als eerst van een beperkt woordenboek. Een herhalingsteller houdt bij hoe vaak een wachtzin digested moet worden om een sleutel te produceren. Het volgende woordenboek, als voorbeeld, bevat de mogelijkheden voor enkele, dubbele en drievoudige herhaling: md5(gandalf) md5(sex) md5(secret) md5(md5(gandalf)) md5(md5(sex)) md5(md5(secret)) md5(md5(md5(gandalf))) md5(md5(md5(sex))) md5(md5(md5(secret))) Net zoals bij zout, wordt de herhaling gebruikt om woordenboek aanvallen nutteloos te maken. JCE 1.2 bevat een implementatie van wachtzin encryptie, gebaseerd op PKCS#5, een standaard gepubliceerd door RSA Data Security, Inc. Deze zijn we al in een eerdere paragraaf 7.6.2 tegen gekomen. Er worden geen speciale methoden gebruikt bij PKCS#5 wachtzin encryptie. Het is gebaseerd op de MD5 message digest en een DES cipher in CBC mode. Je zou het zelf kunnen schrijven, maar JCE 1.2 bevat al een implementatie en je hoeft het wiel niet opnieuw uit te vinden. 7.6.9 Opdracht Maak een programma wat gebruik maakt van wachtzin encryptie om een bestand te coderen en te decoderen. Implementeer hiervoor ook wat zout zodat het moelijker wordt om de codering te kraken, zie hiervoor paragraaf 7.6.8. 90
    • 7.7 Provider 7.7.1 Inleiding Provider Om alle, in Java geschreven, Security klassen op een eenduidige manier te kunnen aanspreken. Heeft men een algemene interface geschreven, waarmee men handlers kan opvragen die met standaard aanroepen sleutels genereren, een signature aanmaken, etc. Deze algemene adaptatie klasse wordt ook wel een ‘Provider’ genoemd (hij levert je namelijk het juiste algoritme aan). Het grote voordeel van deze constructie is de transparantie. Dat wil zeggen dat als we nu morgen besluiten dat we in plaats van DES bijvoorbeeld AES willen gebruiken, dan hoeven we alleen maar een ander algoritme aan te vragen bij de provider. Dit zou je als volgt kunnen doen, in dit voorbeeld laten we zaken als mode en padding buiten beschouwing: MessageDigest test = MessageDigest.getInstance(“DES”); Als we het gebruikte algoritme willen veranderenm hoeven we hier alleen maar DES in AES te veranderen: MessageDigest test = MessageDigest.getInstance(“AES”); Voor de rest hoeven we niets in onze code te wijzigen, hoogstens wat algoritme specifieke zaken, mochten deze voorkomen in de code, die we gebruikt hebben. Voor het aanmaken van bijvoorbeeld een cipher kunnen we de volgende regel gebruiken: Cipher cipher = Cipher.getInstance(“DES/ECB/PKCS5Padding”); Bij getInstance kunnen we drie opties meegeven namelijk, de provider, de mode en de padding. Voor meer informatie over Cipher, kijk in paragraaf 7.6.6. 7.7.2 Een simpel voorbeeld van een provider In onderstaand voorbeeld laten we kort zien hoe een provider geïmplementeerd kan worden. Dit doen we aan de hand van het niet bestaand ‘ACMEcrypt’ algoritme. //Hier geven we de naam van de package aan die we maken, //in dit geval een provider met de naam ACME.crypto. package ACME.crypto; import java.security.*; public class Provider extends java.security.Provider { public Provider() { //Naamgeving van de provider, versie en uitgebreide naam. super (“ACME”, 1.2, “ACME voorbeeld provider”); //Voeg een chiper van het algoritme toe met mode en padding //welke geïmplementeerd is in de package ACME.crypto alwaar //de functie ACMEcrypt deze functie implementeert. put (“Chiper.ACMEcrypt/mode/padding”, “ACME.crypto.ACMEcrypt”); // voeg een alias voor deze chiper toe put (“Alg.Alias.Cipher.ACMEcrypt/mode/padding”, “ACME.crypto.ACMEcrypt”); } } In bovenstaand voorbeeld wordt met de naamgeving heb volgende bedoeld: 91
    • ACME.crypto is de naam van de package waarin de provider komt. ACME is de korte naam van de provider. 1.2 is het versienummer van de provider. ACME voorbeeld provider is de lange naam c.q. korte beschrijving van de provider. Chiper = ACMEcrypt/mode/padding is het Algoritme ACMEcrypt, gevolgd door de mode en de padding. ACME.crypto.ACMEcrypt geeft aan dat de functie ACMEcrypt is geïmplementeerd in de package ACME.crypto. Feitelijk komen in de provider functie 2 commando’s voor namelijk: super en put. Super is er om de naam en de versie van de provider in te stellen. Put voegt één voor één het algoritme toe, afhankelijk van het eerste woord wordt van de functie aangegeven wat de functie is. Het daadwerkelijk implementeren van een algoritme binnen de java.security architectuur behandelen we verder niet. Dit omdat alle bestaande algoritmen al wel een provider hebben die we gemakkelijk kunnen gebruiken. Om een provider te kunnen gebruiken moeten we java vertellen dat deze er is, dit kan op 2 manieren: Statisch Edit de java.security file in jdk/lib/security en voeg een regel toe, bijvoorbeeld: security.provider.getal = ACME.crypto Getal, stelt hier het volgnummer voor, java gaat deze af bij om te kijken of een bepaald algoritme misschien in deze klasse zit. Dynamisch Voeg de volgende regels toe aan je programma, om tijdens de uitvoer je java.security tijdens de uitvoer aan te passen: java.security.Provider p = new onze.security.provider(); Security.addProvdier(p) Deze code voegt onze provider aan het einde van de huidige provider lijst toe, als je op een bepaalde positie wilt tussenvoegen gebruik dan insertProvderAt() in plaats van addProvider(). 7.8 Signed Applets 7.8.1 Applets Vanaf Java versie 1.1 is het mogelijk om gebruik te maken van signed applets. Een signed applet is een cryptografisch verzegelde verzameling van klassen en andere ondersteunde, benodigde, bestanden, zoals bijvoorveeld grafische of geluidsbestanden. Het mooie van een signed applets is dat deze wel buiten het beperkte applet gebied van de normale Java 1.0 wereld kunnen werken. Dit betekent dat zij veel meer interessante mogelijkheden bevatten. Zo is het nu wel mogelijk om toegang te krijgen tot diskbestanden en netwerverbindingen. In deze syllabus zullen we niet ver ingaan op signed applets. We geven nog wel even kort aan hoe het werkt. Als je meer wilt weten over signed applets, verwijs ik naar de website 92
    • van Sun [23] of kijk op de websites van Netscape Navigator [24] of Microsoft Internet Explorer [25]. 7.8.2 Werking van een signed applet Theoretisch komt de werking van een signed applet op het volgende neer: 1. Een software ontwikkelaar moet eerst een certificaat aanvragen bij een vertrouwde Certificaten Organisatie zoals Verisign [26] ervoor moet wel een klein bedrag worden betaald (momenteel $19.95). Voor dit bedrag wordt wel nagetrokken of een persoon die een certificaat aanvraagt ook echt die persoon is. 2. Terwijl iemand op aan het internet surfen is komt hij op een pagina waar een signed applet wordt aangeroepen. De ontwikkelaar van de applet heeft een certificaat aangevraagd en daarmee zijn applet verzegeld door gebruik te maken van zijn private key. 3. Nu zegt de browser van de surfende persoon dat de applet is verzegeld door de betreffende ontwikkelaar. De browser vraagt de surfer of hij of zij toestaat dat de applet buiten de standaard wereld van Java werkt. Maar waarom is een signed applet nu wel veilig? Je kunt er van uitgaan dat een signed applet is verzegeld. Hierdoor is het niet mogelijk dat de applet is veranderd door iemand anders die misschien vervelende dingen met je voor heeft. En omdat het certificaat is geregistreerd en ondertekend door een vertrouwde Certificaten Organisatie, kun je er van uitgaan dat de ontwikkelaar ook echt degene is die de applet heeft gemaakt. 7.8.3 Ondersteuning Op dit moment is het nog niet echt gemakkelijk om met een signed applet te werken. De drie meest gebruikte Internet browsers (HotJava van Sun, Netscape Navigator en Microsoft Internet Explorer) ondersteunen signed applets wel. Maar in elke browser wordt het weer op een andere manier geïmplementeerd. Hierdoor is het nodig om voor elke browser een aparte browser specifieke implementatie te maken. Daarnaast is er ook nog interactie nodig met Certificaten Organisaties. Verder zijn signed applets nog lang niet volwassen en er zitten nog veel bugs in. Hierdoor wordt het moelijk om er mee te werken. 7.9 Eindopdracht Als eindopdracht voor het Java gedeelte moet er een programma geschreven worden wat beveiliging nodig heeft. Je kunt bijvoorbeeld denken aan een beveiligd chatprogramma, een simpele clietn/server applicatie voor bijvoorbeeld het versturen van bestanden over het netwerk of een ‘bankprogramma’ waarmee je geld kunt overmaken. Let vooral op de volgende punten: • Je moet veilig met een client op de server kunnen inloggen. • Alle gegevens die je over een netwerk verstuurd moeten gecodeerd worden. • De server moet kunnen nagaan wie er inlogt en of deze persoon wel te vertrouwen is. • De server moet aan sleutel beheer doen. Je kunt bij deze opdracht ook je voorgaande opdrachten gebruiken of code die in deze sylabus staat. Maak eerst een klein ontwerp en probeer dit vervolgens zo veilig mogelijk te implementeren. En let vooral goed op de beveiliging van je programma en je gegevens. 93
    • 7.10 Literatuurlijst 1. Java(TM) 2 Platform, Standard Edition http://java.sun.com/j2se/1.3/ Download pagina voor JDK 1.3. Deze URL staat niet op CD, de JDK wel. 2. Java 2 Platform SE v1.3 http://java.sun.com/j2se/1.3/docs/api/ API en klassen uitleg voor JDK 1.3. Deze URL staat niet op CD, de API documentatie wel. 3. Java(TM) 2 SDK, Standard Edition http://java.sun.com/products/jdk/1.2/ Download pagina voor JDK 1.2. Deze URL staat niet op CD. Java(TM) 2 Platform, Standard Edition, v1.2.2 API Specification http://java.sun.com/j2se/1.2/docs/api/ Sun JDK 1.2 API uitleg. Deze URL staat niet op CD. 4. Cryptix - Welcome to Cryptix http://www.cryptix.org/ Website van Cryptix voor het downloaden van een JCE implementatie. 5. Java(TM) Cryptography Extension http://java.sun.com/products/jce/ Website over JCE 1.2. Deze URL staat niet op CD. 6. Generated Documentation (Untitled) http://java.sun.com/security/JCE1.2/spec/apidoc/ API en klassen uitleg voor JCE 1.2. Deze URL staat niet op CD. 7. New Features http://java.sun.com/j2se/1.3/docs/relnotes/features.html#security Op deze site kun je de changelog van JDK 1.3 vinden. Deze URL staat niet op CD. 8. IAIK Java Crypto Software http://jcewww.iaik.tu-graz.ac.at/ Download pagina voor de JCE implementatie van IAIK. Deze URL staat niet op CD. 9. RSA Security | Products | RSA BSAFE | Crypto-J http://www.rsasecurity.com/products/bsafe/cryptoj.html RSA’s Java Crypto Toolkit. Deze URL staat niet op CD. 10. The Intel Random Number Generator http://ftp.cryptography.com/intelRNG.pdf PDF bestand: intelRNG.pdf White paper van Intel over Random Number Generatoren. 11. Boek ‘Netwerkbeveiliging en cryptografie’ van William Stallings, Academic Service 1999 (ISBN 90-395-1105-5) Paragraaf 9.2,’Secure Hash Algorithm (SHA)’ Beschrijving van SHA 12. Random number generators -- The pLab Project Home Page. Deze URL staat niet op CD. http://random.mat.sbg.ac.at/ Deze site, gehost door de universiteit van Salzburg, bevat informatie over random nummer generatoren en tests voor random getallen. Verder zijn er verwijzingen naar literatuur en andere websites over willekeurigheid. 94
    • 13. Randomness for crypto http://www.cs.berkeley.edu/~daw/rnd/ Deze website bevat verwijzingen naar scripties, source code en hardware specificaties in relatie tot random getallen. Deze URL staat niet op CD. 14. Welcome to lavarand! http://lavarand.sgi.com/ Voor een wat algemenere kijk naar random nummers, kan je naar deze stripachtige pagina’s kijken. Het beschrijft hoe je met Lava Lites® random getallen kunt produceren. Deze URL staat niet op CD. 15. Boek ‘Netwerkbeveiliging en cryptografie’ van William Stallings, Academic Service 1999 (ISBN 90-395-1105-5) Paragraaf 6.3,’Sleutelbeheer’ Beschrijving van sleutelbeheer in het algemeen. 16. Boek ‘Netwerkbeveiliging en cryptografie’ van William Stallings, Academic Service 1999 (ISBN 90-395-1105-5) Paragraaf 10.3,’Digital Signature Standard’ Beschrijving van DSA. 17. Boek ‘Netwerkbeveiliging en cryptografie’ van William Stallings, Academic Service 1999 (ISBN 90-395-1105-5) Paragraaf 11.2,’X.509 Authenticatieservice’ Beschrijving over X.509 algoritme. 18. Boek ‘Netwerkbeveiliging en cryptografie’ van William Stallings, Academic Service 1999 (ISBN 90-395-1105-5) Paragraaf 6.4,’Diffie Hellman sleuteluitwisseling’ Beschrijving over Diffie Hellman. 19. Boek ‘Netwerkbeveiliging en cryptografie’ van William Stallings, Academic Service 1999 (ISBN 90-395-1105-5) Paragraaf 1.1,’Aanvallen services en mechanismen’ Er staat in een overzicht van beveiligingsservices uitgelegd wat authenticatie is. 20. Boek ‘Netwerkbeveiliging en cryptografie’ van William Stallings, Academic Service 1999 (ISBN 90-395-1105-5) Paragraaf 11.1,’Kerberos’ Hier worden verschillende authenticatie dialogen besproken. 21. SRP: The Open-Source Password Authentication Standard http://srp.stanford.edu/srp/ Methode om een dictionary attack te voorkomen. Deze URL staat niet op CD. 22. RSA Laboratories | Public Key Cryptography Standards http://www.rsasecurity.com/rsalabs/pkcs/ Hier staat informatie over PKCS#5. Deze URL staat niet op CD. 23. java.sun.com - The Source for Java(TM) Technology http://www.java.sun.com/ De website van Sun. Deze URL staat niet op CD. 24. Netcenter http://www.netscape.com/ Website van Netscape Navigator. Deze URL staat niet op CD. 25. Welcome to Microsoft's Homepage http://www.microsoft.com/ie/ Website van Microsoft. Deze URL staat niet op CD. 95
    • 26. VeriSign http://www.verisign.com/ Website van VeriSign. Deze URL staat niet op CD. 96