Tutoraufgabe 1 (Werkzeugkasten):

Ähnliche Dokumente
Tutoraufgabe 1 (Werkzeugkasten): Programmierung WS18/19 Übungsblatt 4 (Abgabe Freitag, den um 12:00) Allgemeine Hinweise:

Tutoraufgabe 1 (Programmanalyse): Programmierung WS17/18 Übungsblatt 5 (Abgabe ) Allgemeine Hinweise:

Tutoraufgabe 1 (Programmanalyse):

Tutoraufgabe 1 (Programmanalyse):

Programmierung WS14/15 Lösung - Präsenzübung C. Aschermann, F. Frohn, J. Hensel, T. Ströder

Erste Java-Programme (Scopes und Rekursion)

Programmierung WS12/13 Lösung - Präsenzübung M. Brockschmidt, F. Emmes, C. Otto, T. Ströder

Tutoraufgabe 1 (Programmanalyse):

Probeklausur Java Einführung in die Informatik. Wintersemester 2016/2017

Tutoraufgabe 1 (Zweierkomplement): Lösung: Programmierung WS16/17 Lösung - Übung 2

Tag 8 Repetitorium Informatik (Java)

Tutoraufgabe 1 (Seiteneekte):

Tutoraufgabe 1 (Überladen von Methoden):

Methoden und Wrapperklassen

Objektorientierte Programmierung. Kapitel 22: Aufzählungstypen (Enumeration Types)

Probeklausur Java Einführung in die Informatik. Wintersemester 2017/2018

AuD-Tafelübung T-B5b

Programmierung für Mathematik (HS13)

Tutoraufgabe 1 (Seiteneekte):

Beispielprüfung CuP WS 2015/2016

Institut für Programmierung und Reaktive Systeme 5. Dezember Programmieren I. 5. Übungsblatt

Programmierung für Mathematik HS11

Tutoraufgabe 1 (Listen):

Tutoraufgabe 1 (Typcasting):

Javakurs für Anfänger

Programmierung WS17/18 Lösung - Präsenzübung 09./

Tutoraufgabe 1 (Verifikation):

Übung Programmierung WS 2007/08 - Blatt 6

Institut für Informatik

JAVA BASICS. 2. Primitive Datentypen. 1. Warum Java? a) Boolean (logische Werte wahr & falsch)

Programmieren in Java -Eingangstest-

Tutoraufgabe 1 (Fibonacci-Zahlen):

Folienpaket 7 Themenschwerpunkte: Methoden in OOP /2016 Dr. Daniel Haase - Vorkurse Informatik V3/V4

n 1. Grundzüge der Objektorientierung n 2. Methoden, Unterprogramme und Parameter n 3. Datenabstraktion n 4. Konstruktoren n 5. Vordefinierte Klassen

Technische Universität Braunschweig Institut für Programmierung und Reaktive Systeme

Übungsblatt 13. Abgabe / Besprechung in Absprache mit dem Tutor

Algorithmen und Programmierung III

Praktikum zu Einführung in die Informatik für LogWings und WiMas Wintersemester 2013/14

Tag 5. Repetitorium Informatik (Java) Dozent: Marius Kamp Lehrstuhl für Informatik 2 (Programmiersysteme)

Tutoraufgabe 1 (Casting): Programmierung WS17/18 Übungsblatt 2 (Abgabe ) Allgemeine Hinweise:

Institut für Programmierung und Reaktive Systeme. Java 2. Markus Reschke

Aufgabe 1 (Programmanalyse):

Themen der Übung. Methoden und Wrapperklassen. Vorteile von Methoden. Methoden. Grundlagen

ADT: Java Collections und ArrayList

12 Abstrakte Klassen, finale Klassen und Interfaces

Lernteam OOP3 SW Programmieren 1 - H1103 Felix Rohrer

2 Programmieren in Java I noch ohne Nachbearbeitung

Aufgabe 1 (Programmanalyse, Punkte)

Abschnitt 11: Beispiel: Die Klasse String (Teil 1)

Präsenzübung Programmierung WS 2016/2017

int x = 3; int y = 11; public A () { this.x = z; y *= z;

Vorkurs Informatik WiSe 17/18

Java Übung. Übung 3. Werner Gaulke. 2. Mai Universität Duisburg-Essen Kommedia, Übung EinPro SS06, Einführung in Java - Übung.

Martin Unold INFORMATIK. Geoinformatik und Vermessung

Tutorium 2. Strings. Skript zur Vorlesung Einführung in die Programmierung

Teil 5 - Java. Programmstruktur Operatoren Schlüsselwörter Datentypen

Klausur Einführung in die Informatik I für Elektrotechniker 16. Juli 2003

Strings in Java. Die String Klasse und Methoden. A. Müller

Tutoraufgabe 1 (Überladen von Methoden):

Einführung in C. Alexander Batoulis. 5. Mai Fakutltät IV Technische Universität Berlin

Einstieg in die Informatik mit Java

Präsenzübung Programmierung WS 2017/2018

Javakurs für Anfänger

Tutoraufgabe 1 (Pilze):

Einführung in Java, Teil 7

Vorkurs Informatik WiSe 16/17

Programmieren I + II Regeln der Code-Formatierung

Aufgabenblatt 5. Kompetenzstufe 1. Allgemeine Informationen zum Aufgabenblatt:

1. Grundzüge der Objektorientierung 2. Methoden, Unterprogramme und Parameter 3. Datenabstraktion 4. Konstruktoren 5. Vordefinierte Klassen

Übungsblatt 13. Abgabe / Besprechung in Absprache mit dem Tutor

1 Aufgaben 1.1 Umgebungsvariable setzen: CLASSPATH

UE Algorithmen und Datenstrukturen 1 UE Praktische Informatik 1. Übung 3

Einstieg in die Informatik mit Java

hue12 January 24, 2017

Programmieren I + II Regeln der Code-Formatierung

Nachholklausur zur Vorlesung: Einführung in die objektorientierte Programmierung mit Java WS1415

Fakultät IV Elektrotechnik/Informatik

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 16/17. Kapitel 13. Listen. Listen 1

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 15/16. Kapitel 12. Listen. Listen 1

Klausur Grundlagen der Programmierung

Praktikum 4: Grafiken und Ereignisse

Klassen und Objekte. Einführung in Java. Folie 1 von Mai Ivo Kronenberg

Probeklausur zur Vorlesung

EPROG 2.Teilprüfung. Aufgabe 1:

Programmierung WS18/19 Lösung - Präsenzübung

Tutoraufgabe 1 (Hoare-Kalkül):

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 11/12 1. Kapitel 11. Listen. Listen

Anregungen zu Übung 2

Selbststudium OOP7 & ALG2 Auftrag

Einstieg in die Informatik mit Java

Vorname: Nachname: Matrikelnummer: Studiengang (bitte ankreuzen): Informatik Bachelor Informatik Lehramt Mathematik Bachelor Sonstige:

Tutoraufgabe 1 (Code-Analyse):

Programmiermethodik 1. Klausur

55 Ring-Queue. size. push. clear. get. Reinhard Schiedermeier / Klaus Köhler, Das Java-Praktikum, dpunkt.verlag, ISBN

Name:... Matr.-Nr... Bearbeitungszeit: 120 Minuten. Lesen Sie die Aufgaben jeweils bis zum Ende durch; oft gibt es hilfreiche Hinweise!

Vorkurs Informatik WiSe 15/16

Transkript:

Prof. aa Dr. J. Giesl S. Dollase, M. Hark, D. Korzeniewski Tutoraufgabe 1 (Werkzeugkasten): In dieser Aufgabe wird eine Klasse implementiert, die eine Werkzeugkiste verwaltet. In einer Werkzeugkiste können Materialien (Schrauben, Nieten, etc.), einfache Werkzeuge (Zangen, Schraubendreher, etc.) und Elektrowerkzeuge (Bohrmaschinen, Schleifgerät, etc.) sein. Die meisten Materialien sind sehr klein. Deswegen können alle Materialien zusammen in einem einzelnen Fach der Werkzeugkiste untergebracht werden. Elektrowerkzeuge hingegen sind sehr groß. Jedes Elektrowerkzeug nimmt daher immer je drei benachbarte Fächer ein. Beachten Sie in allen Teilaufgaben die Prinzipien der Datenkapselung. a) Schreiben Sie einen Aufzählungstyp Tool für die drei Arten von Werkzeugen: PowerTool, SimpleTool und Materials. b) Schreiben Sie eine Klasse Toolbox, die vier Attribute hat: ein Array von Tool-Objekten als Fächer der Werkzeugkiste, eine ganzzahlige Variable für die freie Kapazität der Werkzeugkiste, ein String als Name der Werkzeugkiste und eine Konstante, die angibt, wie viele Fächer ein Elektrowerkzeug belegt. Schreiben Sie außerdem zwei Konstruktoren: Ein Konstruktor, der eine Kapazität übergeben bekommt und eine leere Werkzeugkiste mit entsprechender Kapazität erstellt. Ein Konstruktor, der eine beliebige Anzahl Tool-Objekte übergeben bekommt und eine Werkzeugkiste erstellt, die genau diese Werkzeuge enthält und keine zusätzlichen freien Fächer hat. Freie Fächer entstehen hier also nur, falls auch null als Tool-Objekt übergeben wird. Die Einschränkung, dass Elektrowerkzeuge immer drei Fächer benötigen, kann hier ignoriert werden, denn bei idealer Platzeinteilung kann man oft viel mehr auf gleichem Raum unterbringen. Beide Konstruktoren bekommen außerdem einen String übergeben, der als Name der Werkzeugkiste gesetzt wird. c) Schreiben Sie Methoden, um die freie Kapazität zu lesen, um den Namen der Kiste zu lesen und um das Werkzeug in Fach i zu lesen. Falls i keine gültige Fachnummer ist, soll null zurückgegeben werden. Schreiben Sie außerdem eine Methode, um den Namen zu ändern. d) Schreiben Sie eine Hilfsmethode checkroomforpowertool, die den ersten Index i ermittelt, an dem ein Elektrowerkzeug in die Werkzeugkiste passen würde. Als Rückgabewert hat die Methode einen boolean, der angibt, ob drei freie Plätze in Folge gefunden werden konnten. Als Eingabe bekommt die Methode ein Objekt der Klasse Wrapper, die auf der Webseite zur Verfügung steht. Sie speichert einen int-wert und bietet Getter und Setter Methoden für diesen int-wert. Als Seiteneffekt soll dieses Wrapper-Objekt so geändert werden, dass es den gefundenen Index i speichert. e) Diskutieren Sie die Sichtbarkeit der Methode checkroomforpowertool. f) Schreiben Sie eine Methode addtool, die ein Werkzeug zu einer Werkzeugkiste hinzufügt. Elektrowerkzeuge werden an die erste Stelle gespeichert, an der drei Fächer in Folge frei sind. Das Objekt wird in jedes dieser drei Fächer geschrieben. Normale Werkzeuge werden an den ersten freien Platz geschrieben. Materialien werden nur dann neu hinzugefügt, wenn kein Fach mit Materialien gefunden wurde, bevor ein freies Fach gefunden wurde. Die Methode sollte außerdem die Kapazität aktualisieren. g) Schreiben Sie ausführliche javadoc-kommentare für die gesamte Klasse Toolbox. Lösung: Listing 1: Toolbox.java 1 /** 2 * Objekte dieser Klasse repraesentieren eine beschriftete Werkzeugkiste. 3 * 4 * In den Faechern koennen je ein einfaches Werkzeug, eine grosse Menge Materialien 5 * oder, in drei nebeneinander liegenden Faechern, ein Elektrowerkzeug untergebracht werden. 1

6 */ 7 public class Toolbox { 8 /** 9 * Anzahl Faecher, die ein Elektrowerkzeug belegt. 10 */ 11 public static final int PowerToolSize = 3; 12 13 /** 14 * Array, das die Faecher der Werkzeugkiste repraesentiert. 15 */ 16 private Tool [] tools ; 17 /** 18 * Anzahl freier Faecher in der Werkzeugkiste. 19 */ 20 private int capacity ; 21 /** 22 * Beschriftung der Werkzeugkiste. 23 */ 24 private String name ; 25 26 /** 27 * Erstelle eine neue, leere Werkzeugkiste mit einer bestimmten Anzahl Faecher 28 * @param name Beschriftung der Kiste 29 * @param capacity Anzahl Faecher fuer die Kiste 30 */ 31 public Toolbox ( String name, int capacity ) { 32 this. name = name ; 33 this. capacity = capacity ; 34 this. tools = new Tool [ capacity ]; 35 36 /** 37 * Erstelle eine neue Werkzeugkiste mit festgelegtem Inhalt. 38 * @param name Beschriftung der Kiste 39 * @param tools Werkzeuge, die in der Kiste enthalten sein sollen. 40 */ 41 public Toolbox ( String name, Tool... tools ) { 42 this. name = name ; 43 this. capacity = 0; 44 this. tools = tools ; 45 for ( Tool tool : tools ) { 46 if( tool == null ) { 47 this. capacity += 1; 48 49 50 51 52 /** 53 * Lese das Werkzeug im i- ten Fach. 54 * @param i Nummer des Fachs 55 * @return Das Werkzeug im i- ten Fach 56 */ 57 public Tool gettool ( int i) { 58 if (0 <= i && i < this. tools. length ) { 59 return this. tools [i]; 60 else { 61 return null ; 62 63 64 65 /** 66 * Lese Anzahl freier Faecher 67 * @return Anzahl freier Faecher 68 */ 69 public int getcapacity () { 70 return this. capacity ; 71 72 73 /** 74 * Lese Beschriftung 75 * @return Beschriftung der Werkzeugkiste 76 */ 77 public String getname () { 78 return this. name ; 79 80 /** 81 * Setze Beschriftung 82 * @param name Neue Beschriftung 83 */ 84 public void setname ( String name ) { 85 this. name = name ; 86 87 88 /** 89 * Finde den ersten moeglichen Platz fuer ein Elektrowerkzeug. 2

90 * @param index Ausgabeparameter fuer den freien Platz. Falls Rueckgabewert 91 * false ist, dann ist dieser Wert ungueltig. 92 * @return ob ein gueltiger Index gefunden wurde. 93 */ 94 private boolean checkroomforpowertool ( Wrapper index ) { 95 index. set (0); 96 boolean room = true ; 97 while ( index. get () <= this. tools. length - Toolbox. PowerToolSize ) { 98 for ( int j = index. get (); j < index. get () + Toolbox. PowerToolSize ; ++j) { 99 if( this. tools [j]!= null ) { 100 room = false ; 101 break ; 102 103 room = true ; 104 105 if( room ) { 106 return true ; 107 108 index. set ( index. get ()+1); 109 110 return false ; 111 112 113 /** 114 * Fuege ein Werkzeug an erster passender Stelle zur Kiste hinzu, falls Platz ist. 115 * @param t Das Werkzeug, das hinzugefuegt werden soll. 116 */ 117 public void addtool ( Tool t) { 118 switch (t) { 119 case PowerTool : 120 Wrapper i = new Wrapper (0); 121 if( this. checkroomforpowertool (i)) { 122 for ( int k = 0; k < Toolbox. PowerToolSize ; ++k) { 123 this. tools [i. get () + k] = t; 124 125 this. capacity -= Toolbox. PowerToolSize ; 126 127 break ; 128 case Materials : 129 for ( int k = 0; k < this. tools. length ; ++k) { 130 if( this. tools [k] == null ) { 131 this. tools [k] = t; 132 this. capacity -= 1; 133 break ; 134 135 if( this. tools [k] == Tool. Materials ) { 136 break ; 137 138 139 break ; 140 case SimpleTool : 141 for ( int k = 0; k < this. tools. length ; ++k) { 142 if( this. tools [k] == null ) { 143 this. tools [k] = t; 144 this. capacity -= 1; 145 break ; 146 147 148 break ; 149 150 151 1 public enum Tool { 2 PowerTool, SimpleTool, Materials 3 1 public class Wrapper { 2 private int i; 3 4 public Wrapper ( int i) { 5 this.i = i; 6 7 8 public void set ( int i) { 9 this.i = i; 10 11 public int get () { Listing 2: Tool.java Listing 3: Wrapper.java 3

12 return this.i; 13 14 e) Die Methode sollte private sein, da sie stark mit der internen Struktur verknüpft ist. Eine Änderung der internen Struktur der Klasse könnte eine Änderung der Signatur nach sich ziehen. Dass der Rückgabewert existiert ein Platz für ein Elektrowerkzeug aber auch für den Benutzer der Klasse interessant ist, reicht nicht als Grund, die Methode öffentlich zu machen. Es wäre besser, eine zusätzliche Methode checkroomforpowertool ohne Parameter zu ergänzen. Aufgabe 2 (Digitale Signaturen): (1 + 7 + 7 + 4 + 2* + 4 = 23 + 2* Punkte) Alice möchte für einige Leute digitale Zertifikate ausstellen. Diese Zertifikate möchte Alice später überprüfen können, um sich davon zu überzeugen, dass sie wirklich von ihr ausgestellt wurden. Natürlich könnte Alice alle Daten speichern und zum Überprüfen in ihrer Datenbank nachsehen. Das klingt für Alice aber viel zu aufwendig, daher entscheidet sie sich, digitale Signaturen zu verwenden. Jedes Zertifikat enthält daher einen Inhalt und eine Signatur. Alice benötigt nun zur Überprüfung nur ein Secret 1. Aus dem Inhalt des Zertifikats und dem Secret wird mit Hilfe eines speziellen Algorithmus und einer kryptografischen Hashfunktion eine Signatur berechnet. Ohne das Secret von Alice ist es praktisch unmöglich, die korrekte Signatur zu erzeugen. Um später zu prüfen, dass sie das Zertifikat selbst ausgestellt hat, muss sie also nur die Signatur erneut berechnen und mit der Signatur des Zertifikats abgleichen. Andere können diese Überprüfung nicht vornehmen, da man das Secret zur Überprüfung benötigt. Es handelt sich also um ein symmetrisches Signaturverfahren. 2 In dieser Aufgabe werden die nötigen Klassen implementiert, um mit Hilfe der in Java verfügbaren Hashfunktionen digital signierte Zertifikate zu erzeugen. Ein Zertifikat besteht aus drei Teilen: Einem Header, der den Namen des verwendeten Signaturalgorithmus enthält, einen Body, der Paare von Schlüsseln und Werten enthält, und schließlich der Signatur. Header und Body bilden zusammen den Inhalt des Zertifikats. Der Aufbau von Zertifikaten wird also durch die folgende Grammatik in EBNF beschrieben: Header = (" HMAC_MD5 " " HMAC_SHA1 " " HMAC_SHA256 ") Key_Value_Pair = " " String " : " String " " Body = Key_ Value_ Pair { "," Key_ Value_ Pair Signatur = Hexadezimalzahl Inhalt = Header ";" Body ";" Zertifikat = Inhalt Signatur Die folgenden beiden Ausdrücke sind syntaktisch korrekte Zertifikate. HMAC_MD5 ; i : 42, string : string ;9 b55eef8e51651bb7f265204d281354c HMAC_SHA256 ; i : 1, str : value ; 93 d0de88bef2c1cc63d485e330e067d3096aaa6fcc8c722d2de4d87991a0b54e Auf der Webseite finden Sie eine Klasse Hasher.java, die Sie nutzen können. Die Klasse vereinfacht den Umgang mit den Hashfunktionen von Java und bietet zusätzlich Methoden, um zwischen byte[] und Strings mit Hexadezimalzahlen zu konvertieren. Alle öffentlichen Methoden dieser Klasse verfügen über ausführliche Erklärungen als Javadoc Kommentare. Zusätzlich gibt es eine main-methode in der Klasse Hasher, mit der Sie Ihren Code testen können. Hinweise: Beachten Sie bei Ihrem Entwurf der Klassen die Datenkapselung und versehen Sie jedes Attribut und jede Methode mit public, private, static und final soweit sinnvoll. 1 Ein Passwort oder kryptografischer Schlüssel 2 Dies ist im Gegensatz zu asymmetrischen Verfahren, bei denen es einen privaten Schlüssel zum Erzeugen und einen öffentlichen Schlüssel zum Überprüfen der Signaturen gibt. 4

Sie dürfen, unter Beachtung der Datenkapselung und soweit nötig, Hilfsmethoden oder Attribute zu den von Ihnen geschriebenen Klassen hinzufügen. Die vorgegebene Klasse Hasher darf nicht verändert werden! Halten Sie sich unbedingt an die vorgegebenen Namen für Klassen, Methodennamen und so weiter, damit Ihr Code getestet werden kann. Ihr Code muss nicht robust sein. Wenn falsche Parameter übergeben werden, darf sich Ihr Code beliebig verhalten. Falls z.b. ein String erwartet wird, der eine Zahl darstellt, aber "a" übergeben wird, darf Ihr Programm abstürzen. a) Schreiben Sie einen Aufzählungstyp (Enum) Algorithm. Dieser soll die drei möglichen Signaturalgorithmen HMAC_MD5, HMAC_SHA1 und HMAC_SHA256 repräsentieren können. b) Zunächst benötigen wir eine einfache Klasse für die Schlüssel-Wert-Paare, die den Body des Zertifikats bilden. Schreiben Sie dazu eine Klasse Pair. Ein Pair-Objekt soll jeweils einen Schlüssel und einen Wert (als Strings) speichern, die über die Selektoren getkey bzw. getvalue gelesen werden können. Einmal erstellt, sollen Schlüssel und Wert eines Objekts nicht mehr geändert werden können. Es soll zwei Konstruktoren geben, die jeweils als ersten Parameter den Schlüssel als String erhalten und als zweiten Parameter einen String oder ein Integer-Objekt (das dann in einen entsprechenden String überführt werden muss). Schließlich soll es eine tostring Methode geben, die eine Stringrepräsentation des Objekts gemäß der oben gezeigten EBNF Regeln für das Nicht-Terminal Key_Value_Pair erzeugt, und eine Methode fromstring für die umgekehrte Richtung. Der Aufruf Pair.fromString(" a : something ") sollte also ein Pair-Objekt mit dem Schlüssel "a" und dem Wert "something" zurückgeben. Hinweise: In der Klasse String gibt es eine Methode split(string pattern). Diese liefert ein Array von Strings, das entsteht, wenn man den String bei jedem vorkommen von pattern aufspaltet. Ruft man split(",") z.b. auf dem String ",a,bcd,e" auf, erhält man das Array {"", "a", "bcd", "e". Gehen Sie davon aus, dass weder der Schlüssel noch der Wert das Symbol enthalten. Andernfalls darf sich Ihr Code beliebig verhalten. c) Schreiben Sie eine Klasse Certificate, die ein Zertifikat repräsentiert. Ein Zertifikat besteht aus einem Algorithm, der für die Signatur verwendet werden soll, einer beliebigen, aber für ein Objekt festen Anzahl von Schlüssel-Wert-Paaren und einer Signatur. Der Algorithm und die Schlüssel-Wert-Paare sollen dem Konstruktor übergeben werden. Nutzen sie vararg-parameter, damit eine beliebige Anzahl Schlüssel-Wert-Paare übergeben werden kann. Die Signatur soll außerhalb der Klasse nicht zugreifbar sein. Auch der Algorithm ist extern nicht relevant. Für die Schlüssel-Wert-Paare soll es statt Selektoren eine Funktion get geben, die einen Schlüssel als String übergeben bekommt und den zugehörigen Wert zurückliefert, falls es ein entsprechendes Schlüssel- Wert-Paar in dem Zertifikat gibt. Ansonsten soll null zurückgegeben werden. Außerdem soll die Klasse eine Methode fromstring besitzen, die ein Objekt der Klasse aus einem String gemäß der EBNF Regeln für das Nicht-Terminal Zertifikat erstellt. Ruft man zum Beispiel Certificate.fromString auf dem ersten Beispiel-Zertifikat oben auf, sollte man ein Objekt vom Typ Certificate erhalten, bei dem der Algorithm HMAC_MD5 ist, die Signatur 9b55eef8e51651bb7f265204d281354c und das genau zwei Schlüssel-Wert-Paare besitzt. Die Schlüssel sollten "i" und "string" sein und die zugehörigen Werte "42" bzw. "string". Hinweise: Gehen Sie davon aus, dass weder die Schlüssel noch die Werte die Symbole oder ; enthalten. Andernfalls darf sich Ihr Code beliebig verhalten. 5

d) Schreiben Sie in der Klasse Certificate eine Methode getsignedstring(string secret), die eine Signatur als String aus dem gegebenen secret mit dem Algorithm des aktuellen Certificate-Objekts erstellt, die Signatur des aktuellen Certificate-Objekts mit der Hexadezimalstring-Darstellung dieser String-Signatur belegt und das vollständige Zertifikat als String zurück liefert, wie in der EBNF- Grammatik angegeben. Hat das aktuelle Certificate-Objekt bereits eine Signatur, z.b. weil es aus einem String erstellt wurde, soll diese nicht verändert werden! Schreiben Sie dazu zunächst eine nur intern verwendete Hilfsmethode getheaderbodystring, die eine String-Repräsentation des Inhalts des aktuellen Certificate-Objekts gemäß der EBNF Regeln für das Nicht-Terminal Inhalt zurückliefert. Für ein Objekt mit den Schlüssel-Wert-Paaren a : 42 und foo : bar und dem Algorithm HMAC_MD5 würde die Methode den String HMAC_MD5; a : 42, foo : bar ; zurückliefern. Um die Signatur zu berechnen, verwenden Sie die passende Funktion aus der Klasse Hasher. Ist der Algorithm des aktuellen Certificate-Objekts z.b. HMAC_SHA256, müssten Sie Hasher.sha256Hmac(String tosign, String secret) mit passenden Parametern aufrufen. Als erster Parameter sollte dabei das Ergebnis von getheaderbodystring übergeben werden. Schreiben Sie außerdem eine Methode validatesignature(string secret). Diese soll erneut eine Signatur berechnen und diese mit der in dem Objekt gespeicherten Signatur vergleichen. Sind beide gleich, soll true zurückgeliefert werden, sonst false. Hinweise: Sie können die Methode substring(int beginindex, int endindex) verwenden. Dieser erzeugt einen Teilstring, der genau die Zeichen von beginindex bis endindex-1 enthält. s.substring(0, s.length()) würde also den kompletten String s kopieren, "abcd".substring(1,3) würde den String "bc" zurückgeben. Verwenden Sie die Methode bytearraytohex aus der Klasse Hasher um byte-arrays in Strings (mit der entsprechenden Hexadezimalzahl) zu konvertieren. Ebenso enthält Hasher eine Methode für die umgekehrte Transformation. e) Alice bietet einen Webservice an, über den Bob und Chuck ihre Zertifikate überprüfen können. Leider ist Chuck nicht vertrauenswürdig und könnte versuchen, Zertifikate zu fälschen. Da Chuck die Zeit mitstoppen könnte, die eine Überprüfung dauert, muss Alice ihren Code gegen Timing-Attacken absichern. Bei einer Timing-Attacke stoppt Chuck die Laufzeit einer Operation und kann daraus Rückschlüsse auf geheime Informationen ziehen. In diesem Fall ist die kritische Information, wie weit die neu berechnete Signatur mit der vorhandenen übereinstimmt. Die Methode equals der Klasse String vergleicht zwei Strings nur bis zum ersten Unterschied. Je länger der Vergleich dauert, desto mehr Bytes der Signatur sind richtig. Chuck kann also Byte für Byte die Signatur fälschen. So braucht er nur 256 32 Versuche, um eine SHA-256 Signatur zu fälschen, statt 256 32 Versuche. Doch es ist noch schlimmer! Für einen Angriff würde es schon reichen, wenn man weiß, ob nur ein einziges Byte der gefälschten Signatur auch in der korrekten Signatur an gleicher Position auftritt. Dies würde Chuck ermöglichen, die Signatur in höchstens 32 32 + 256 Versuchen zu fälschen, weil nicht jeder der 256 möglichen Byte-Werte in der aus 32 Byte bestehenden Signatur auftreten kann. Also muss es genau so lang dauern ein richtiges Byte zu verarbeiten, wie es braucht ein falsches Byte zu verarbeiten. Verändern Sie die Methode validatesignature(string secret) so, dass keine der oben beschriebenen Timing-Attacken mehr möglich sind. Kommentieren Sie ihren Code, sodass klar wird, wie die Timing- Attacke vermieden wird. Hinweise: Die Länge von secret oder des Inhalts ist keine kritische Information. In der Praxis werden grundsätzlich Geheimnisse mit der gleichen Länge wie die Block-Größe des Hash-Algorithmus verwendet. Die Block-Größe aller hier verwendeten Algorithmen ist 512 Bit. Diese Aufgabe benötigt große Präzision. Kleinste Fehler führen dazu, dass kritische Informationen verraten werden. Beispielsweise benötigt true && 1 == 1 eine längere Zeit zur Auswertung als false && 1 == 1 6

f) Versehen Sie die Klassen Certificate und Pair mit einer ausführlichen Javadoc Dokumentation. Private Methoden und private Attribute müssen nicht zwingend dokumentiert werden. Generieren Sie mit Javadoc eine HTML Version der Dokumentation und schicken Sie diese zusammen mit dem Programmcode an ihre Tutorin/ihren Tutor. Die generierte HTML Version braucht nicht ausgedruckt zu werden. Lösung: Listing 4: Certificate.java 1 /* -------------- c) ---------------------------- */ 2 3 /** 4 * Diese Klasse repraesentiert ein Zertifikat mit einer HMAC Signatur. 5 * 6 * Um ein Zertifikat zu erstellen, wird der Konstruktor mit dem gewuenschten 7 * Signaturalgorithmus aufgerufen und anschliessend das signierte Zertifikat 8 * mit { @link # getsignedstring ( String ) getsignedstring abgerufen. 9 * 10 * Um ein Zertifikat zu validieren, wird eine Instanz mit der Methode 11 * { @link # fromstring ( String ) fromstring aus dem Zertifikatsstring erzeugt 12 * und die Signatur mit der Methode { @link # validatesignature ( String ) validatesignature 13 * ueberprueft. 14 */ 15 public class Certificate { 16 private final Pair [] values ; 17 private String signature ; 18 private final Algorithm algo ; 19 20 /** 21 * Generiert ein neues Zertifikat. 22 * 23 * @param algo Der gewuenschte Signaturalgorithmus 24 * @param values Die Daten des Zertifikats 25 */ 26 public Certificate ( Algorithm algo, Pair... values ) { 27 this. values = values ; 28 this. algo = algo ; 29 30 31 /** 32 * Ruft den Wert zu einem Schluessel ab. 33 * 34 * @param key Der Schluessel 35 * @return Den Wert zum gegebenen Schluessel oder null, falls nicht existent 36 */ 37 public String get ( String key ) { 38 for ( Pair kv : values ) { 39 if(kv. getkey (). equals ( key )) { 40 return kv. getvalue (); 41 42 43 return null ; 44 45 46 /** 47 * Erstellt eine Instanz aus einem Zertifikatsstring. 48 * @param str Der Zertifikatsstring 49 * @return Eine Instanz, die den String repraesentiert 50 */ 51 public static Certificate fromstring ( String str ) { 52 String [] parts = str. split (";"); 53 54 String [] values = parts [1]. split (","); 55 56 Pair [] valuepairs = new Pair [ values. length ]; 57 58 for ( int i = 0; i < valuepairs. length ; ++i) { 59 valuepairs [i] = Pair. fromstring ( values [i ]); 60 61 62 Certificate sc = new Certificate ( Algorithm. valueof ( parts [0]), valuepairs ); 63 sc. signature = parts [2]; 64 return sc; 65 66 /* -------------- c) ende ----------------------- */ 67 68 /* -------------- d) ---------------------------- */ 69 70 /** 7

71 * Ruft den Zertifikatsstring ab und generiert bei Bedarf die Signatur 72 * @param secret Das Geheimnis fuer die Signatur 73 * @return Der signierte Zertifikatsstring 74 */ 75 public String getsignedstring ( String secret ) { 76 if( this. signature == null ) { 77 this. signature = Hasher. bytearraytohex ( this. computesignature ( secret )); 78 79 return this. getheaderbodystring () + this. signature ; 80 81 82 /** 83 * Berechnet die Signatur fuer diese Instanz mit dem gegebenen Geheimnis. 84 * Die gespeicherte Signatur wird nicht veraendert. 85 * @param secret Das Geheimnis fuer die Signatur 86 * @return Die digitale Signatur 87 */ 88 private byte [] computesignature ( String secret ) { 89 byte [] signature ; 90 switch ( this. algo ) { 91 default : 92 case HMAC_SHA256 : signature = Hasher. sha256hmac ( this. getheaderbodystring (), secret ); 93 break ; 94 case HMAC_SHA1 : signature = Hasher. sha1hmac ( this. getheaderbodystring (), secret ); 95 break ; 96 case HMAC_MD5 : signature = Hasher. md5hmac ( this. getheaderbodystring (), secret ); 97 break ; 98 99 return signature ; 100 101 102 /** 103 * Gibt den String, der signiert wird zurueck. 104 * @return Der zu signierende String 105 */ 106 private String getheaderbodystring () { 107 String str = algo. tostring () + ";"; 108 for ( Pair kv : values ) { 109 str += kv + ","; 110 111 str = str. substring (0, str. length () -1); 112 str += ";"; 113 return str ; 114 115 116 /** 117 * ueberprueft ob die gespeicherte Signatur fuer das gegebene Geheimnis gueltig ist. 118 * Diese Variante ist anfaellig fuer Timing - Attacken. 119 * @param secret Das Geheimnis mit dem geprueft wird. 120 * @return True, wenn die Signatur gueltig ist, sonst false. 121 */ 122 public boolean insecurevalidatesignature ( String secret ) { 123 String expected = Hasher. bytearraytohex ( this. computesignature ( secret )); 124 125 return expected. equals ( this. signature ); 126 127 /* -------------- d) ende ----------------------- */ 128 129 /* -------------- e*) --------------------------- */ 130 131 /** 132 * ueberprueft, ob die gespeicherte Signatur fuer das gegebene Geheimnis gueltig ist. 133 * Diese Variante ist sicher gegen Timing - Attacken auf die Anzahl richtiger 134 * Bytes in der Signatur. 135 * 136 * @param secret Das Geheimnis mit dem geprueft wird. 137 * @return True, wenn die Signatur gueltig ist, sonst false. 138 */ 139 public boolean validatesignature ( String secret ) { 140 byte [] expected = this. computesignature ( secret ); 141 byte [] actual = Hasher. hexstringtobytearray ( this. signature ); 142 if( actual == null expected. length!= actual. length ) { 143 return false ; 144 145 boolean result = true ; 146 // iteriere ueber das komplette Array, damit nicht erkannt werden kann, 147 // wie lang der korrekte Praefix ist. 148 for ( int i = 0; i < actual. length ; ++i) { 149 // kein if, sondern boolesche Operationen, da so das Verarbeiten eines korrekten 150 // Bytes genau so lang dauert wie das eines Falschen. 151 result = actual [i] == expected [i] && result ; 152 153 154 return result ; 8

155 156 /* -------------- e*) ende ---------------------- */ 157 158 Listing 5: Pair.java 1 /* -------------- b) ---------------------------- */ 2 3 /** 4 * Repraesentiert ein Schluessel - Wert - Paar. Die Daten koennen nachtraeglich nicht veraendert werden. 5 */ 6 public class Pair { 7 private final String key ; 8 private final String value ; 9 10 /** 11 * Erstellt ein neues Paar fuer einen String Wert 12 * @param key Der Schluessel 13 * @param value Der Wert als String 14 */ 15 public Pair ( String key, String value ) { 16 this. key = key ; 17 this. value = value ; 18 19 20 /** 21 * Erstellt ein neues Paar fuer einen Integer Wert und konvertiert 22 * den Integer zu einem String. 23 * @param key Der Schluessel 24 * @param value Der Wert als Integer 25 */ 26 public Pair ( String key, Integer value ) { 27 this. key = key ; 28 this. value = value. tostring (); 29 30 31 /** 32 * Ruft den Schluessel ab 33 * @return Der Schluessel 34 */ 35 public String getkey () { 36 return key ; 37 38 39 /** 40 * Ruft den Wert ab 41 * @return Der Wert 42 */ 43 public String getvalue () { 44 return value ; 45 46 47 /** 48 * Erstellt eine String repraesentation 49 * @return Schluessel : Wert 50 */ 51 public String tostring () { 52 return " " + key + " : " + 53 " " + value + " "; 54 55 56 /** 57 * Erstellt eine neue Instanz aus einem String, wie ihn 58 * { @link # tostring () tostring zurueck gibt. 59 * @param str String - Repraesentation eines Paares 60 * @return Eine Instanz mit Schluessel und Wert aus dem String. 61 */ 62 public static Pair fromstring ( String str ) { 63 String [] parts = str. split (" "); 64 return new Pair ( parts [1], parts [3]); 65 66 Listing 6: Algorithm.java 1 /* -------------- a) ---------------------------- */ 2 3 /** 4 * Dieser Aufzaehlungstyp repraesentiert die drei verfuegbaren Signaturalgorithmen. 5 */ 6 public enum Algorithm { 9

7 HMAC_SHA256, HMAC_MD5, HMAC_SHA1 ; 8 Tutoraufgabe 3 (Programmanalyse): Lösen Sie die folgende Aufgabe ohne Einsatz eines Computers. Bedenken Sie, dass Sie in einer Prüfungssituation ebenfalls keinen Computer zur Verfügung haben. Betrachten Sie das folgende Programm: public class A { public static void main ( String [] args ) { A a1 = new A (); System. out. println ( a1.f (5)); System. out. println (a1.d); System. out. println ( a1.f( Long. valueof (2))); A a2 = new A (1,1); System. out. println (a2.i); System. out. println (a2.d); private Integer i; private double d; public A() { this.i = 1; this.d = 4; public A( Integer x, double y) { this.i = x; this.d = y; public A( int x, double y) { this.i = 3; this.d = x + y; public int f( Integer x) { return this.i + x; public int f( double i) { this.d = i; return this.i; Geben Sie die Ausgabe dieses Programms an, wenn die main-methode ausgeführt wird. Begründen Sie Ihre Antwort. Lösung: a) Die erste Ausgabe ist 1. Da die implizite Typanpassung Vorrang vor dem Autoboxing hat, wird die zweite f Methode ausgeführt. Der Rückgabewert dieser Methode ist der Wert des i Attributs, welcher im ersten Konstruktor auf 1 gesetzt wurde. b) Die zweite Ausgabe ist 5.0. Bei der Ausführung der zweiten f Methode wurde das d Attribut auf den übergebenen Wert 5.0 gesetzt. c) Die dritte Ausgabe ist wieder 1. Hier wird zunächst das Long Objekt durch Unboxing in einen long Wert umgewandelt, der anschließend durch implizite Typanpassung in einen double Wert konvertiert wird. Also wird wieder die zweite f Methode ausgeführt und das (unveränderte) i Attribut ausgegeben. d) Die vierte Ausgabe ist 3. Dem Konstruktor werden zwei int Werte übergeben, sodass der dritte Konstruktor ausgeführt wird, da der zweite Konstruktor gegenüber dem dritten ein zusätzliches Autoboxing erfordern würde. Dieser belegt das i Attribut mit 3. e) Die fünfte Ausgabe ist 2.0. Auf dem für die letzte Ausgabe beschriebenen Ausführungsweg wurde der dritte Konstruktor mit den int Werten 1 und 1 aufgerufen. Deren Summe wird durch implizite Typanpassung zu 2.0 konvertiert und dem d Attribut zugewiesen. 10

Aufgabe 4 (Programmanalyse): (4 Punkte) Lösen Sie die folgende Aufgabe ohne Einsatz eines Computers. Bedenken Sie, dass Sie in einer Prüfungssituation ebenfalls keinen Computer zur Verfügung haben. Betrachten Sie das folgende Programm: public class B { public static void main ( String [] args ) { B b = new B (); b.a( Long. valueof (100)); b.a( Double. valueof (100)); b.a( Integer. valueof (100)); double r1 = b.b (100 D); int r2 = ( int ) b.b (100); c( Integer. valueof (100), "0"); c (100L, "0"); c (100L, 0 ); public void a( int p) { System. out. println ("a1"); public void a( double p) { System. out. println ("a2"); public void a( Double p) { System. out. println ("a3"); public int b( double p) { System. out. println ("b1"); return 0; public double b( int p) { System. out. println ("b2"); return 0; public static void c( Long p1, int p2) { System. out. println ("c1"); public static void c( long p1, String p2) { System. out. println ("c2"); public static void c( Long p1, String p2) { System. out. println ("c3"); 11

Geben Sie die Ausgabe dieses Programms an, wenn die main-methode ausgeführt wird. Begründen Sie Ihre Antwort! Lösung: a) Die erste Ausgabe ist a2, da der Parameter vom Typ Long durch Unboxing zu long und anschließend durch implizite Typumwandlung zu double wird. b) Die zweite Ausgabe ist a3, da die Signatur der Methode genau passt. c) Die dritte Ausgabe ist a1, da der Parameter vom Typ Integer durch Unboxing zu int wird. d) Die vierte Ausgabe ist b1, da die Signatur der Methode genau passt. Insbesondere ist der Typ des Rückgabewertes irrelevant. e) Die fünfte Ausgabe ist b2, da die Signatur der Methode genau passt. Insbesondere ist der Typ des Rückgabewertes irrelevant. f) Die sechste Ausgabe ist c2, da der erste Parameter vom Typ Integer durch Unboxing zu int und anschließend durch implizite Typumwandlung zu long wird. g) Die siebte Ausgabe ist c2, da die Signatur der Methode genau passt. h) Die achte Ausgabe ist c1, da der zweite Parameter vom Typ char durch implizite Typumwandlung zu int wird. Tutoraufgabe 5 (Rekursion): Betrachten Sie folgende Methode: public static int arraysum ( int [] a) { int res = 0; for ( int i = 0; i < a. length ; i ++) { res += a[i]; return res ; Schreiben Sie eine statische Methode arraysumrecursive, welche ein int-array erhält und eine int-zahl zurückliefert, sodass für jedes int-array a die Aufrufe arraysum(a) und arraysumrecursive(a) das gleiche Ergebnis liefern. Sie dürfen in dieser Aufgabe keine Schleifen verwenden. Die Verwendung von Rekursion ist hingegen erlaubt (inklusive der Definition von Hilfsmethoden). Hinweise: Wenn Sie Ihr Programm mit der Anweisung import java.util.arrays; beginnen, können Sie die vordefinierte statische Methode Arrays.copyOfRange benutzen. Hierbei liefert Arrays.copyOfRange(a, i, j) ein neues Array mit den Werten a[i], a[i+1],..., a[j-1] zurück. Lösung: Listing 7: ArraySum.java import java. util. Arrays ; /** * Klasse, welche eine rekursive Summen - Methode fuer Arrays enthaelt. */ 12

public class ArraySum { public static int arraysumrecursive ( int [] a) { return arraysumhelp (a, 0); private static int arraysumhelp ( int [] a, int i) { if ( i >= a. length ) { return 0; return a[ i] + arraysumhelp (a, i + 1); public static int alternativearraysum ( int [] a) { if( a. length <= 0 ) { return 0; else if ( a. length == 1) { return a [0]; else { return a [0] + alternativearraysum ( Arrays. copyofrange (a, 1, a. length )); public static void main ( String [] args ) { int [] arr = {1, 2, 3, 4; System. out. println ( alternativearraysum ( arr )); System. out. println ( arraysumrecursive ( arr )); Aufgabe 6 (Rekursion): (5 Punkte) Gegeben sei die Klasse Minimum in der Datei Minimum.java. Vervollständigen sie die statische Methode arraymin, die das kleinste Element eines int Arrays zurückgibt. In dieser Aufgabe sei das kleinste Element des int[] Arrays null bzw. des int[] Arrays der Länge 0 die größte darstellbare int Zahl. Das Benutzen von Schleifen ist nicht gestattet. Hinweise: Den größten darstellbaren int Wert können Sie durch den Aufruf Integer.MAX_VALUE erhalten. Wenn Sie Ihr Programm mit der Anweisung import java.util.arrays; beginnen, können Sie die vordefinierte statische Methode Arrays.copyOfRange benutzen. Hierbei liefert Arrays.copyOfRange(a, i, j) ein neues Array mit den Werten a[i], a[i+1],..., a[j-1] zurück. Die Benutzung von vordefinierten Java Methoden außer den hier explizit genannten ist nicht gestattet. Um Ihr Programm zu testen, legen Sie die auf der Website bereitgestellte Datei Test.class in dasselbe Verzeichnis wie Minimum.java. Führen sie nach dem Kompilieren von Minimum.java den Befehl java Test aus. Lösung: 1 import java. util. Arrays ; 2 public class Minimum { Listing 8: Minimum.java 13

3 public static int arraymin ( int [] inputarray ){ 4 if( inputarray == null inputarray. length <= 0){ 5 return Integer. MAX_ VALUE ; 6 7 int n = inputarray. length ; 8 if(n == 1){ 9 return inputarray [n -1]; 10 11 int min1 = arraymin ( Arrays. copyofrange ( inputarray,0,n /2)); 12 int min2 = arraymin ( Arrays. copyofrange ( inputarray,n/2,n )); 13 int result = min1 < min2? min1 : min2 ; 14 return result ; 15 16 Aufgabe 7 (Codescape): (Codescape) Lösen Sie die Räume von Deck 3 des Spiels Codescape. Ihre Lösung für Räume dieses Codescape Decks wird nur dann für die Zulassung gezählt, wenn Sie die Lösung bis Freitag, den 23.11.2018 um 12:00 abschicken. Lösung: 14