Teil von  SELFPHP
  +++ SELFPHP CronJob-Service :: Jetzt auch als Professional-Version verfügbar! +++

:: Anbieterverzeichnis ::

Globale Branchen

Informieren Sie sich über ausgewählte Unternehmen im Anbieterverzeichnis von SELFPHP  

 

:: SELFPHP Forum ::

Fragen rund um die Themen PHP? In über 120.000 Beiträgen finden Sie sicher die passende Antwort!  

 

:: Newsletter ::

Abonnieren Sie hier den kostenlosen SELFPHP Newsletter!

Vorname: 
Name:
E-Mail:
 
 

:: Qozido ::

Die Bilderverwaltung mit Logbuch für Taucher und Schnorchler.   

 
 
Rijndael – Komplettes Beispielprojekt Verschlüsselung


Systemvoraussetzung

  • Linux
  • Windows
  • PHP 4 >= 4.3.0
  • PHP 5
  • MySQL
  • libmcrypt 2.4.x oder 2.5.x

Datei(en)

rijndael.php, rijndael.inc.php, rijndael.css, rijndael.sql

Problem

Bisher haben Sie gesehen, wie man Daten verschlüsselt und sie in Textdateien speichert. Sicherlich hätten Sie es gerne komfortabler und die Daten nicht als Textdateien, sondern in einer Datenbank vorliegen. Diesem Thema werden wir uns nun widmen.


Lösung

Das folgende Beispiel ist eine komplette Lösung zur Verschlüsselung. Die verschlüsselten Daten werden dabei in eine MySQL-Datenbank gespeichert und können über ein Drop-Down-Menü jeweils ausgewählt werden. Weiterhin speichert das Programm das Datum und die Uhrzeit von folgenden Ereignissen:

  • Erstellungsdatum der letzten Verschlüsselung
  • Datum der letzten erfolgreichen Entschlüsselung
  • Datum der letzten fehlgeschlagenen Verschlüsselung

Somit können Sie genau sehen, wie auf den entsprechenden Datensatz zugegriffen wurde. Sie können bei der Verschlüsselung einen Info-Text eingeben, sodass Sie später im Drop-Down-Menü den entsprechenden Datensatz schneller finden. Weiterhin haben Sie die Möglichkeit, zwischen einer Verschlüsselungsstärke von 128, 192 oder 256 Bit zu wählen.

Bei der Verschlüsselung können Sie wahlweise reinen Text oder eine Datei angeben. Sollte es sich um eine Datei handeln, wird der Inhalt der Datei verschlüsselt und in die Datenbank gespeichert.

Um maximale Sicherheit zu gewährleisten, wird das Passwort für die Entschlüsselung nicht mit in die Datenbank gespeichert. Sollten Sie dieses Passwort verlieren, so sind Ihre Daten nicht mehr zu entschlüsseln. Also achten Sie sehr gut auf Ihr Passwort!

Das Programm ist bereits so aufgebaut, dass Sie eigene Menüfelder hinzunehmen können, um das Programm an Ihre Bedürfnisse anzupassen.

Hier im Buch verzichten wir auf die Quellcode-Darstellung der HTML-Datei, da der Programmcode bereits viele Seiten einnimmt und die HTML-Seite nur ein paar PHP-Blöcke zur Darstellung bereithält – dies müssen wir nicht gesondert aufzeigen.

Im Folgenden sehen Sie drei Screenshots, die allerdings nicht die komplette Programmseite wiedergeben, sondern nur Ausschnitte sind.

Den vollen Umfang der Seite inkl. Menüs sehen Sie auf der folgenden gesonderten Seite.



Abbildung 12.2: Screenshot Verschlüsselung



Abbildung 12.3: Screenshot Entschlüsselung



Abbildung 12.4: Screenshot Info

Sie finden bei der beiliegenden ZIP-Datei eine Datei mit dem Namen rijndael.sql. Diese Datei enthält die Struktur der Tabelle für die Datenbank. Am einfachsten ist es, wenn Sie diese Datei mit phpMyAdmin einlesen und sich somit die Tabelle erstellen lassen.

Sollten Sie den Tabellennamen in dem SQL-Statement ändern, so müssen Sie diesen Namen auch in der Konfiguration ändern. Dann müssen Sie die Parameter für den Datenbankzugriff angeben und können das Programm sofort ausprobieren.

Dieses Programm können Sie nach Herzenslust erweitern und modifizieren. Wie zu Beginn des Buches erwähnt, haben wir bewusst auf Klassen verzichtet, daher finden Sie hier im Beispiel auch hauptsächlich Funktionen.

Das Programm bietet sich aber geradezu an, in eine Klasse implementiert zu werden – also wenn Sie sich üben wollen oder bereits genug Erfahrung besitzen, so modifizieren sie es.

Nun wollen wir uns aber dem Programmcode widmen. Wir werden uns zunächst alle Funktionen anschauen, bevor wir zu dem Teil kommen, in dem sich die einzelnen Verzweigungen für das Programm befinden.

function encryptAES($content,$key,$aes)
   @param   string     $content
   @param   string     $key
   @param   integer   $aes
   @return   mixed

Die nachfolgende Funktion kennen Sie bereits aus dem vorangegangenen Beispiel. Daher werden wir sie nicht noch einmal näher beschreiben. Falls noch Fragen bestehen, so schauen Sie bitte im vorherigen Beispiel nach, dort finden Sie eine sehr detaillierte Erklärung zu dieser Funktion. Einen kleinen Unterschied gibt es in dieser Funktion aber dennoch.

Diesmal speichern wir die Daten nicht in eine Textdatei, sondern in einem Array (41, 43, 55, 65). Wir speichern zum einen den verschlüsselten Text (35) und zum anderen eine MD5-Prüfsumme (65) des unverschlüsselten Textes. Falls Sie sich jetzt fragen sollten wofür wir diese Prüfsumme benötigen, so ist die Antwort schnell gegeben. Wir brauchen sie bei der Entschlüsselung.

Wir möchten alles protokollieren – vor allem aber die misslungenen Entschlüsselungen. Vielleicht hat ja jemand versucht, die Daten über das Programm zu entschlüsseln, hatte aber das falsche Passwort. Wenn Sie z. B. versuchen, den folgenden verschlüsselten Text mit einem falschen Passwort zu entschlüsseln,

-ÉÚE7ækéªç¡Xûïãöù|‰LÂڈô¼õ`GO. . . ]Ò°Æ<2‚&
wð@Sʤîáî?2>:k¢æÂçíu‘ê?¼

so erhalten Sie als Ergebnis z. B. Folgendes als Rückgabetext (ist jedes Mal verschieden):

·E²Æ]G&æ

Jetzt stehen wir vor einem Problem. Wie erkenne ich, ob der Text richtig entschlüsselt wurde? An diesem Punkt kommt die MD5-Prüfsumme ins Spiel. Anhand dieser Prüfsumme, die wir aus dem unverschlüsselten Text erzeugt haben, können wir beide Texte miteinander vergleichen.

Ist die Prüfsumme des entschlüsselten Textes genau wie die MD5-Prüfsumme, die wir beim Verschlüsseln erzeugt haben, so muss das Passwort richtig gewesen sein. Wären die beiden Prüfsummen unterschiedlich, so war die Entschlüsselung bzw. das Passwort fehlerhaft.

Aus diesem Grund speichern wir nicht nur den verschlüsselten Text in die Datenbank, sondern auch die MD5-Prüfsumme (65). Diese Funktion gibt also ein Array mit dem verschlüsselten Text und der Prüfsumme zurück (67).

017:
018:
019:
020:
021:
022:
023:
024:
025:
026:
027:
028:
029:
030:
031:
032:
033:
034:
035:
036:
037:

038:

039:
040:
041:

042:
043:

044:
045:
046:
047:
048:
049:
050:
051:
052:
053:
054:
055:
056:
057:
058:
059:
060:
061:
062:
063:
064:
065:
066:
067:
068:
069:
function encryptAES($content,$key,$aes) {
    
    
// Setzt den Algorithmus
    
switch ($aes) {
        case 
128:
           
$rijndael 'rijndael-128';
           break;
        case 
192:
           
$rijndael 'rijndael-192';
           break;
        default:
           
$rijndael 'rijndael-256';
    }

    
// Setzt den Verschlüsselungsalgorithmus
    // und setzt den Output Feedback (OFB) Modus
    
$cp mcrypt_module_open($rijndael'''ofb''');
    if(!
$cp)
        return 
'Modul konnte nicht geladen werden';
    
    
// Ermittelt den Initialisierungsvector, der für die Modi CBC, CFB und 
         OFB benötigt wird. 
    // Der Initialisierungsvector muss beim Entschlüsseln den selben Wert 
         wie beim Verschlüsseln haben.
    // Windows unterstützt nur MCRYPT_RAND
    
if (strtoupper(substr(PHP_OS03)) === 'WIN')
        
$enc['iv'] = mcrypt_create_iv(mcrypt_enc_get_iv_size($cp), 
                         MCRYPT_RAND);
    else
        
$enc['iv'] = mcrypt_create_iv(mcrypt_enc_get_iv_size($cp), 
        
                MCRYPT_DEV_RANDOM);
        
    
// Ermittelt die Anzahl der Bits, welche die Schlüssellänge des Keys festlegen
     
$ks mcrypt_enc_get_key_size($cp);
  
     
// Erstellt den Schlüssel, der für die Verschlüsselung genutzt wird
     
$key substr(md5($key), 0$ks);
  
     
// Initialisiert die Verschlüsselung
     
mcrypt_generic_init($cp$key$enc['iv']);
  
     
// Verschlüsselt die Daten
     
$enc['encrypted'] = mcrypt_generic($cp$content);
      
     
// Deinitialisiert die Verschlüsselung 
     
mcrypt_generic_deinit($cp);
  
     
// Schließt das Modul
     
mcrypt_module_close($cp);
  
    
// Erstellt einen Hash-Wert um später prüfen zu können, ob ein misslungene
    // Entschlüsselung durchgeführt wurde
    
$enc['md5']    =    md5($content);
  
    return 
$enc;
    
}
Beispiel 12.14: rijndael.inc.php

function decryptAES($content,$iv, $key,$aes)
   @param   string     $file
   @param   string     $key
   @param   integer   $aes
   @param   string     $ivFile
   @return   mixed

Auch in dieser Funktion hat sich kaum was geändert. Im vorherigen Beispiel konnten Sie bereits verfolgen, wie diese Funktion arbeitete. Sie entschlüsselt unseren Text und gibt ihn der aufgerufenen Stelle zurück.

085:
086:
087:
088:
089:
090:
091:
092:
093:
094:
095:
096:
097:
098:
099:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
function decryptAES($content,$iv$key,$aes) {
    
    
// Setzt den Algorithmus
    
switch ($aes) {
        case 
128:
           
$rijndael 'rijndael-128';
           break;
        case 
192:
           
$rijndael 'rijndael-192';
           break;
        default:
           
$rijndael 'rijndael-256';
    }

    
// Setzt den Verschlüsselungsalgorithmus
    // und setzt den Output Feedback (OFB) Modus
    
$cp mcrypt_module_open($rijndael'''ofb''');
    
    
// Ermittelt die Anzahl der Bits, welche die Schlüssellänge des Keys festlegen
    
$ks mcrypt_enc_get_key_size($cp);
  
    
// Erstellt den Schlüssel, der für die Verschlüsselung genutzt wird
    
$key substr(md5($key), 0$ks);
  
    
// Initialisiert die Verschlüsselung
    
mcrypt_generic_init($cp$key$iv);

    
// Entschlüsselt die Daten
    
$decrypted mdecrypt_generic($cp$content);
  
    
// Beendet die Verschlüsselung 
    
mcrypt_generic_deinit($cp);
  
    
// Schließt das Modul
    
mcrypt_module_close($cp);
  
    return 
trim($decrypted);
  
}
Beispiel 12.15: rijndael.inc.php

function insertBase($encrypted,$iv,$infotext,$aes,$md5,$dbTable)
   @param   string     $encrypted
   @param   string     $iv
   @param   string     $infotext
   @param   integer   $aes
   @param   string     $md5
   @param   string     $dbTable
   @return   bool

Die Funktion insertBase() ist für das Speichern eines verschlüsselten Textes in die Datenbank verantwortlich. Sie erwartet als Parameter den verschlüsselten Text, den IV-Tag aus der Verschlüsselung (encryptAES()), den Infotext aus dem Webformular, die Verschlüsselungsstärke (128, 192 oder 256 Bit), die MD5-Prüfsumme aus der Verschlüsselung (encryptAES()) und zum Schluss den Tabellennamen in der Datenbank.

Allerdings müssen wir den IV-Tag und den verschlüsselten Text für die Datenbank vorbereiten (141, 142), da innerhalb dieser beiden Variablen eine Vielzahl von Anführungsstrichen etc. vorkommen kann und diese mit einem Backslash (\) geschützt werden müssen.

Würden wir darauf verzichten, so würde das Einfügen in die Datenbank scheitern. Wir setzen also unseren SQL-String (144-152) mit den gelieferten Daten zusammen und fügen anschließend die Daten in die Datenbank ein (153).

140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
function insertBase($encrypted,$iv,$infotext,$aes,$md5,$dbTable) {
    
$encrypted addslashes($encrypted);
    
$iv addslashes($iv);
  
    
$sqlString  =    "INSERT INTO 
                        $dbTable
                     SET
                        infotext  =  '$infotext',
                        textaes   =  '$encrypted',
                        block     =  '$aes',
                        encrypt   =   NOW(),
                        ivTag     =  '$iv',
                        md5       =  '$md5'"
;
    
$sqlInsert    = @mysql_query($sqlString);
    
    return 
true;
}
Beispiel 12.16: rijndael.inc.php

function checkDecrypt($decrypted,$md5,$id=0,$database=false)
   @param   string     $decrypted
   @param   string     $md5
   @param   integer   $id
   @param   bool       $database
   @return   mixed

Die Funktion checkDecrypt() ist unsere Protokollfunktion. Sie überprüft, ob der entschlüsselte Text identisch mit der Prüfsumme ist, die beim Verschlüsseln erstellt wurde. Ist dies der Fall (176), so wird diese erfolgreiche Entschlüsselung mit Datum und Uhrzeit gespeichert (177). Waren die beiden Prüfsummen nicht identisch, so wird die fehlgeschlagene Entschlüsselung ebenfalls mit Datum und Uhrzeit gespeichert (180).

Die Funktion hat noch einen weiteren Zweck. Wenn Sie einen Text verschlüsseln, so wird der Text nicht einfach verschlüsselt und in die Datenbank geschrieben, sondern vorher einem Test unterzogen. Die Funktion prüft dann, ob die gerade erstellte Verschlüsselung auch wieder mit dem Passwort entschlüsselbar ist.

Ist das der Fall, so gibt die Funktion TRUE zurück und die Daten werden gespeichert. Konnte der Text nicht wieder entschlüsselt werden, so meldet die Funktion FALSE und speichert die Daten nicht, sondern gibt einen Hinweistext aus.

Daher ist der Aufruf der Funktion auch unterschiedlich. Wenn Sie einen Text entschlüsseln wollen (175), so geben Sie der Funktion die beiden folgenden optionalen Parameter mit:

  • $id Die Datenbank-ID des verschlüsselten Textes
  • $database true, wenn Sie die Daten entschlüsseln wollen

Wollen Sie hingegen nur prüfen, ob der gerade verschlüsselte Text auch wieder entschlüsselbar ist (183), so lassen Sie diese beiden Parameter einfach weg. Sie werden dann mit den Standardwerten 0 (Null) und FALSE gefüllt.

173:
174:
175:
176:
177:

178:
179:
180:

181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
function checkDecrypt($decrypted,$md5,$id=0,$database=false) {
    
    if(
$database) {
        if(
md5($decrypted) == $md5) {
            
$sqlUpdate = @mysql_query("UPDATE rijndael SET decrypt = NOW() 
                                     WHERE id = $id");
            
$message   "Daten konnten erfolgreich entschlüsselt werden.";        
        } else {
            
$sqlUpdate = @mysql_query("UPDATE rijndael SET decryptError = NOW() 
                                     WHERE id = $id");
            
$message   "Daten konnten nicht entschlüsselt werden!";
        }
    } else {
        if(
md5($decrypted) == $md5) {
            return 
true;
        } else {
            return 
false;
        }
    }
    
    return 
$message;
    
}
Beispiel 12.17: rijndael.inc.php

function sendIV($iv,$md5,$rijndael)
   @param   string     $iv
   @param   string     $md5
   @param   integer   $rijndael
   @return   void

Sie haben jederzeit die Möglichkeit, sich den IV-Tag per Download zuschicken zu lassen. Sie müssen lediglich das richtige Passwort kennen. Die Daten werden entschlüsselt, bevor Sie an diese Funktion übergeben werden, und mit den beiden MD5-Prüfsummen verglichen. Stimmen beide Werte überein, so wird diese Funktion aufgerufen.

Die Funktion erwartet als Parameter den IV-Tag, die MD5-Prüfsumme sowie die Verschlüsselungsstärke (128, 192 oder 256 Bit). Basierend auf den Werten wird eine „Datei“ erstellt (210-213), die unter anderem die Verschlüsselungsstärke (211), das Datum (211), an dem diese Download-Datei erstellt wurde, und den IV-Tag (213) beinhaltet. Der Dateiname wird aus der MD5-Prüfsumme gebildet (216) und erhält als Dateiendung *.iv. Im Folgenden sehen Sie eine derartige Beispieldatei.

Datei: 659a3c8c5d480399a2dd89b73c88ccf0.iv

; IV-Tag Datei
; Erstellt am 05.04.2006 13:37:49
; Verschlüsselung 256 Bit
[óQÞiÍÛGem])žª '¸,*êèà¬keq) 2¡

Wie Sie sicherlich noch aus dem vorangegangenen Beispiel wissen, benötigen Sie zur Entschlüsselung alle drei Werte. Zum einen den IV-Tag, zum anderen den verschlüsselten Text sowie die Verschlüsselungsstärke.

208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
function sendIV($iv,$md5,$rijndael){

    
$message .= "; IV-Tag Datei\n";
    
$message .= "; Erstellt am "date("d.m.Y H:i:s") . "\n";
    
$message .= "; Verschlüsselung " $rijndael "\n";
    
$message .= $iv;
    
    
header("Content-Type: text");
    
header("Content-Disposition: attachment; filename=\"$md5.iv\"");

    echo 
$message;
    
    exit;
}
Beispiel 12.18: rijndael.inc.php

function sendEncrypt($content,$md5)
   @param   string   $content
   @param   string   $md5
   @return   void

Weiterhin haben Sie jederzeit die Möglichkeit, sich den verschlüsselten Text per Download zuschicken zu lassen. Auch hier müssen Sie das richtige Passwort kennen. Die Daten werden entschlüsselt, bevor Sie an diese Funktion übergeben werden, und mit den beiden MD5-Prüfsummen verglichen. Stimmen beide Werte überein, so wird diese Funktion aufgerufen.

Die Funktion erwartet als Parameter den verschlüsselten Text sowie die MD5-Prüfsumme. Basierend auf den Werten wird ein Header (234, 235) gesendet und der verschlüsselte Text ausgegeben (237). Der Dateiname (235) wird aus der MD5-Prüfsumme gebildet und erhält als Dateiendung *.aes. Im Folgenden haben wir eine solche eine Beispieldatei aufgeführt.

Datei: 659a3c8c5d480399a2dd89b73c88ccf0.aes

-ÉÚE7ækéªç¡X [2DC?]ûïãöù|‰LÂڈô¼õ`GO. . . ]Ò°Æ<2‚&
wð@Sʤîáî?2>:k¢æÂçíu‘ê?¼

Wie erwähnen es hier nur noch einmal vorsichtshalber: Zum Entschlüsseln benötigen Sie alle drei Werte. Zum einen den IV-Tag, zum anderen den verschlüsselten Text sowie die Verschlüsselungsstärke.

232:
233:
234:
235:
236:
237:
238:
239:
240:
function sendEncrypt($content,$md5) {

    
header("Content-Type: text");
    
header("Content-Disposition: attachment; filename=\"$md5.aes\"");

    echo 
$content;
    
    exit;
}
Beispiel 12.19: rijndael.inc.php

Grundeinstellung

Die Grundeinstellung ist relativ simpel und bezieht sich lediglich auf die Datenbank. Die benötigten Werte wie Benutzername (8), Datenbank (7), Host (6) sowie Passwort (9) müssen Sie ergänzen. Falls Sie beim Anlegen der Tabelle einen anderen Namen als „rijndael“ gewählt haben, müssen sie diesen selbstverständlich auch ergänzen (10).

001:
002:
003:
004:
005:
006:
007:
008:
009:
010:
011:
012:
013:

014:
<?PHP

/**
*    Datenbank Zugangsdaten
*/
define("DB_HOST","localhost");  // MySQL Hostname
define("DB_NAME","db_name");    // MySQL Datenbankname
define("DB_USER","db_user");    // MySQL Benutzername
define("DB_PASS","db_passwd");  // MySQL Passwort
$db['table'] = 'rijndael';      // MySQL Tabellenname


$dbCon = @MYSQL_CONNECT(DB_HOST,DB_USER,DB_PASS
       or die(
"Datenbank momentan nicht erreichbar");
$db_check = @MYSQL_SELECT_DB(DB_NAME
       or die(
"Datenbank momentan nicht erreichbar");
Beispiel 12.20: rijndael.php

Verschlüsseln

Wurde als Aufgabe die Verschlüsselung gewählt (84), so werden im Vorfeld die übermittelten Variablen überprüft. Zum einen darf das Passwort nicht leer sein (86) und zum anderen müssen beide zum Vergleich abgefragten Passwörter identisch sein (98). Weiterhin darf der Infotext, der für die Darstellung der Drop-Down-Darstellung benötigt wird, nicht leer sein (92).

Je nach Ergebnis der Überprüfung werden unterschiedliche Fehlermeldungen generiert und ausgegeben. Sie können diese Fehlermeldungen noch modifizieren, indem Sie das Beispiel aus diesem Buch zur Fehlerüberprüfung bei Formularen nehmen.

Falls Sie die Textverschlüsselung und nicht die Dateiverschlüsselung gewählt haben, so wird auch hier eine Überprüfung vorgenommen (104) und ein eventueller Fehler ausgegeben. Sollte es sich bei Ihrer Auswahl um eine Dateiverschlüsselung handeln, so müssen wir in diesem Fall noch überprüfen, ob überhaupt eine Datei angegeben wurde (110).

Wurde keine Datei angegeben, wird die IF-Abfrage (113) greifen und einen Fehler ausgeben. Wurde eine Datei angegeben, so wird der else-Zweig (118) weiterverarbeitet. Zuerst bilden wir aus der aktuellen Uhrzeit einen temporären Namen (120) für den Upload der Datei, die wir dann mit move_upload_file() (121) speichern und anschließend in eine Variable einlesen (122). Nachdem wir den Inhalt der Datei eingelesen haben, können wir diese Datei wieder löschen (123).

Jetzt haben wir alle notwendigen Informationen für unsere Verschlüsselung zusammen und können im nächsten Schritt die Daten in die Datenbank speichern, nachdem wir sie verschlüsselt haben. Da alle geforderten Variablen vollständig sind, wird auch die IF-Abfrage (127) nicht fehlschlagen und ausgeführt.

Sollte als Verschlüsselung die Textverschlüsselung gewählt (129) worden sein, speichern wir den Inhalt der POST-Variablen (130) in die Variable $content. Falls eine Dateiverschlüsselung gewählt wurde, so ist die Variable bereits gefüllt mit dem Text aus der Datei (122). Wir speichern noch unsere übermittelten POST-Variablen in bereits bestehende Variablen (131-133), um nicht ständig auf die POST-Variablen zugreifen zu müssen. Erst dann inkludieren wir unsere rinjndael.inc.php (135), die ja alle notwendigen Funktionen für die Verschlüsselung enthält.

Wir verschlüsseln jetzt unseren Text (136) mit dem übergebenen Passwort und prüfen im Anschluss, ob der verschlüsselte Text auch wieder mit diesem Passwort entschlüsselt werden kann (138). War dieser Test erfolgreich, also der Vergleich der beiden MD5-Prüfsummen identisch (140), speichern wir den verschlüsselten Datensatz mit der Funktion insertBase() (141) in die Datenbank. Je nachdem, erhalten wir als Rückgabe entweder TRUE oder FALSE.

Somit ist unsere Verschlüsselung abgeschlossen und der Datensatz liegt sicher in der Datenbank. Da wir beim Speichern vorher geprüft haben (140), ob der Text auch wieder entschlüsselbar ist, können wir beruhigt an dieser Stelle den Vorgang beenden.

084:
085:
086:
087:
088:
089:
090:
091:
092:
093:
094:
095:
096:
097:
098:
099:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:

142:
143:
144:
145:
146:
if(isset($_POST['typ']))
{
    if(empty(
$_POST['password']))
    {
        
$error true;
        
$message .= 'Bitte geben Sie ein Passwort ein<br>';
    }
    
    if(empty(
$_POST['info']))
    {
        
$error true;
        
$message .= 'Bitte geben Sie einen Infotext ein<br>';
    }
    
    if(
$_POST['password'] != $_POST['passwordCheck'])
    {
        
$error true;
        
$message .= 'Passwörter stimmen nicht überein<br>';
    }
    
    if(empty(
$_POST['textfield']) && $_POST['typ'] == "1")
    {
        
$error true;
        
$message .= 'Bitte geben Sie einen Text ein<br>';
    }
    
    if (
$_POST['typ'] == "2")
    {
        
        if(
$_FILES['file']['error'])
        {
            
$error true;
            
$message .= 'Bitte geben Sie eine Datei an<br>';
        }
        else
        {
            
$filetmp time() . '.tmp';
            
move_uploaded_file($_FILES['file']['tmp_name'], "./$filetmp");
            
$content file_get_contents($filetmp);
            
unlink($filetmp);
        }
    }
    
    if(!
$error)
    {
        if(
$_POST['typ'] == "1")
        
$content $_POST['textfield'];
        
$password $_POST['password'];
        
$rijndael $_POST['rijndael'];
        
$info $_POST['info'];
        
        include_once(
"rijndael.inc.php");
        
$enc    =    encryptAES($content,$password,$rijndael);
        
        
$decrypted decryptAES($enc['encrypted'],$enc['iv'],$password,$rijndael);
        
        if(
checkDecrypt($decrypted,$enc['md5']))
            
insertBase($enc['encrypted'],$enc['iv'],$info,$rijndael,
                         $enc['md5'],$db['table']);
        else
            
$message 'Daten konnten nicht verschlüsselt werden!';
        
    }
}
Beispiel 12.21: rijndael.php

Entschlüsseln

Zuerst überprüfen (20) wir, ob ein Passwort übermittelt wurde. Ist das nicht der Fall, also die Variable leer, so wird die zuvor auf „FALSE“ gesetzte Error-Variable (16) auf „TRUE“ (22) gesetzt und eine Fehlermeldung generiert (23). Die nächste IF-Abfrage würde somit scheitern und der nachfolgende Programmcode nicht mehr ausgeführt.

Wurde ein Passwort übermittelt, so besitzt die Error-Variable (16) den Wert „FALSE“ und wird der Überprüfung (26) standhalten. Der nachfolgende Programmcode wird somit ausgeführt. Um nicht willkürlich eine Variable an die Datenbank zu geben, erzwingen wir eine Konvertierung unserer mit POST übergebenen Variablen in ein Integer, indem wir den Wert mit 0 (Null) addieren (28).

Somit können wir jetzt unsere Datenbankabfrage zusammensetzen (29-33) und anschließend ausführen (34). Bei der Datenbankabfrage formatieren wir direkt unser Datum, das im amerikanischen Format vorliegt, ins deutsche Format. Somit erhalten wir dann anstatt

20060404 16:57:34

eine Ausgabe in folgender Form

04.04.2006 16:57:34

und ersparen uns eine spätere Konvertierung mit PHP. Sie sollten bei Datumsabfragen aus einer Datenbank immer diesen Weg wählen, da er wesentlich effizienter ist und unnötige Programmierarbeit vermeidet.

War die Datenbankabfrage erfolgreich, und wurde ein Datensatz geliefert (36), so füllen wir unser Array (38-44) mit den Werten aus unserer Abfrage. Erst im nächsten Schritt inkludieren (46) wir unsere Datei rijndael.inc.php, die alle zuvor beschriebenen Funktionen beinhaltet.

Um den Text aus der zuvor erhaltenen Danbankabfrage weiter zu bearbeiten, übergeben wir diesen der Funktion decryptAES() (48) und erhalten, falls das Passwort richtig ist, unseren entschlüsselten Text in die Variable $decrypted zurück.

Mit einer switch-Abfrage (50) überprüfen wir jetzt, welche Aufgabe wir erledigen müssen. Mögliche Aufgaben wären:

  • case 2 IV-Tag-Download
  • case 3 Rijndael-Download – also der verschlüsselte Text
  • case 4 Datensatz löschen
  • default Datensatz entschlüsseln

Vielleicht wundern Sie sich jetzt, weshalb wir den verschlüsselten Text vor der switch-Abfrage entschlüsselt haben. Sicherlich erinnern Sie sich noch, wie wir überprüfen, ob eine Entschlüsselung funktioniert hat und eine Aufgabe, wie z. B. das Löschen, durchgeführt werden darf.

Wir überprüfen jeweils die MD5-Prüfsumme aus dem entschlüsselten Text mit der MD5-Prüfsumme, die beim Erstellen der Verschlüsselung generiert wurde.

Falls der Download der IV-Tag Datei angefordert (52) wurde, übergeben wir unseren entschlüsselten Text und die MD5-Prüfsumme aus der Datenbank an die Funktion checkDecrypt() (54). Stimmen beide Prüfsummen überein, so erhalten Sie als Rückgabewert „TRUE“, ansonsten „FALSE“.

War die Überprüfung erfolgreich (TRUE), können wir im nächsten Schritt mit der Funktion sendIV() (55) die IV-Tag Datei zum Download anbieten und brechen danach unsere switch-Abfrage mit break (56) ab.

Mit dem Download der Rijndael-Datei (57-61), also unseres verschlüsselten Textes, verfahren wir ebenso. Wir überprüfen unsere MD5-Prüfsummen und starten im Erfolgsfall den Download über die Funktion sendEncrypt().

Beim Löschen der Datei verhält es sich ebenso wie bei den vorangegangenen Aufgaben. Wir überprüfen zuerst die Prüfsummen (64) und werden im Anschluss daran den Datensatz im Erfolgsfall löschen (66). Da wir den Datensatz bereits entschlüsselt haben und ihn nicht mehr anzeigen wollen, müssen wir an dieser Stelle noch die Variable $decrypted löschen (67).

Erst am Ende, also wenn keine andere Aufgabe ausgewählt wurde, wird der eigentliche entschlüsselte Text aufbereitet (70). Aufbereitet ist wohl nicht ganz das richtige Wort, immerhin ist der Text ja schon entschlüsselt. Wir müssen trotzdem auch hier eine Überprüfung vornehmen und die Prüfsummen vergleichen. Zusätzlich speichern wir das Datum und die Uhrzeit dieses Zugriffs in die Datenbank. Je nach Fall können folgende Ereignisse gespeichert werden:

  • Das Datum und die Uhrzeit bei einer gelungenen Entschlüsselung
  • Das Datum und die Uhrzeit bei einem Fehlversuch

Die Entschlüsselung ist somit abgeschlossen, und wir können unsere HTML-Darstellung aufbauen, also unsere PHP-Variablen ausgeben. Wie bereits erwähnt, wird an dieser Stelle nicht der HTML-Quellcode angezeigt, da er nur unnötige Seiten füllen würde. An den Stellen, an denen etwas ausgegeben wird (z. B. die InfoBox), stehen einzelne PHP-Tags mit echo-Ausgaben.

016:
017:
018:
019:
020:
021:
022:
023:
024:
025:
026:
027:
028:
029:
030:
031:
032:

033:
034:
035:
036:
037:
038:
039:
040:
041:
042:
043:
044:
045:
046:
047:
048:

049:
050:
051:
052:
053:
054:
055:
056:
057:
058:
059:
060:
061:
062:
063:
064:
065:
066:

067:
068:
069:
070:
071:
072:

073:
074:
075:
076:
077:
078:
079:
080:
081:
082:
$error false;

if(isset(
$_POST['decode']))
{
    if(empty(
$_POST['password']))
    {
        
$error true;
        
$decodemessage 'Bitte geben Sie ein Passwort ein<br>';
    }
    
    if(!
$error)
    {
        
$id $_POST['decode'] + 0;
        
$sqlDecrypt =  "SELECT id, textaes, block,
                        DATE_FORMAT(encrypt,'%m.%m.%Y %H:%i:%s') AS encrypt,
                        DATE_FORMAT(decrypt,'%m.%m.%Y %H:%i:%s') AS decrypt,
                        DATE_FORMAT(decryptError,'%m.%m.%Y %H:%i:%s') 
                              AS decryptError,
                        ivTag, md5    FROM " 
$db['table'] . " WHERE id = $id";
        
$status = @mysql_query($sqlDecrypt);
        
        if(@
mysql_num_rows($status) == "1")
        {
            
$infoText['bit']          = @mysql_result($status,0,"block") . ' Bit';
            
$infoText['encrypt']      = @mysql_result($status,0,"encrypt");
            
$infoText['decrypt']      = @mysql_result($status,0,"decrypt");
            
$infoText['decryptError'] = @mysql_result($status,0,"decryptError");
            
$infoText['md5']          = @mysql_result($status,0,"md5");
            
$infoText['content']      = @mysql_result($status,0,"textaes");
            
$infoText['iv']           = @mysql_result($status,0,"ivTag");
            
            include_once(
"rijndael.inc.php");
            
            
$decrypted decryptAES($infoText['content'],$infoText['iv'],
                                     $_POST['password'],$infoText['bit']);
            
            switch (
$_POST['job']) 
            {
                case 
2:
                    
// IV-Tag Download
                       
if(checkDecrypt($decrypted,$infoText['md5']))
                        
sendIV($infoText['iv'],$infoText['md5'],$infoText['bit']);
                       break;
                case 
3:
                    
// Rijndael Download
                       
if(checkDecrypt($decrypted,$infoText['md5']))
                           
sendEncrypt($infoText['content'],$infoText['md5']);
                    break;
                case 
4:
                    
// Löschen
                       
if(checkDecrypt($decrypted,$infoText['md5']))
                       {
                           
$sqlDelete = @mysql_query("DELETE FROM "  
            
                        $db['table'] . " WHERE id = $id"); 
                           unset(
$decrypted);                           
                       }
                       break;
                default:
                    
// Entschlüsseln
                       
$decodemessage checkDecrypt($decrypted,
                                     $infoText['md5'],$id,true);
            }
            
        }
        else
        {
            
$decodemessage 'Keine Daten vorhanden!<br>';
        }
    }
    
}
Beispiel 12.22: rijndael.php

Zum Schluss werden aus der Datenbank noch alle Datensätze, also die Infotexte, geholt (149) und in einer Drop-Down-Box (155) angezeigt. Anhand dieser Infotexte können Sie jetzt gezielt den Datensatz auswählen, den Sie entschlüsseln, löschen oder sich per Download zuschicken lassen wollen.

148:
149:

150:
151:
152:
153:
154:
155:
156:
157:
// Holt alle Daten
$sqlShow = @mysql_query("SELECT id, infotext FROM " $db['table'] . 
      " ORDER BY id"
);
while(
$row = @mysql_fetch_row($sqlShow))
{
    
$selected '';
    if(
$_POST['decode'] == $row[0])
    
$selected 'selected';
    
$data .= '<option value="'.$row[0].'" '.$selected.'>'.$row[1].'</option>';
}
?>
Beispiel 12.23: rijndael.php

Wie Sie sehen, haben wir hier ein voll funktionstüchtiges Programm erstellt, das sogar unter realen Bedingungen genutzt werden kann. Wir hoffen, dieses Beispiel hat Ihnen einen Anreiz gegeben, das vorliegende Programm zu erweitern und zu modifizieren.

Ich würde mich sehr darüber freuen, wenn Sie sich derart engagieren und uns Ihr modifiziertes Skript zusenden, sodass wir es eventuell auf SELFPHP veröffentlichen können – selbstverständlich mit dem Hinweis darauf, dass Sie der Autor sind.

Wir wollen das Thema Kryptografie an dieser Stelle beenden. Es war zwar nur ein kleiner Ausblick, der Ihnen aber hoffentlich Freude gemacht hat und Sie anspornt, Ihre Kenntnisse in diesem interessanten Thema zu vertiefen.



 


Dieses Skript aus dem SELFPHP KOCHBUCH wurde von SELFPHP unter dem "Tarif Mc500" von McAc.net-Webhosting erfolgreich ausgeführt und getestet!

Auf der Übersichtseite unter "McAc.net – Webhosting zu diesem Buch" finden Sie weitere Informationen zu dem Webhostingpaket, dass durch SELFPHP getestet wurde.


 




:: Premium-Partner ::

Webhosting/Serverlösungen


Premium-Partner LeaseWeb Germany GmbH
Premium-Partner MECO Systemhaus GmbH & Co. KG
Premium-Partner PSW GROUP GmbH & Co. KG
Premium-Partner BPI-Systeme
Premium-Partner Pixel X
Premium-Partner
 

:: SELFPHP Sponsoren ::


DM Solutions
Microsoft Deutschland GmbH
Sedo - Bei uns wird PHP großgeschrieben
hostfactory.ch - OptimaNet Schweiz AG
ZEND - The PHP Company
Kaspersky Labs
HighText iBusiness
SELFPHP Sponsoren
 

Qozido


© 2001-2013 E-Mail SELFPHP OHG, info@selfphp.deImpressumKontakt