Suche

Kryptografie: Symmetrisch geheim

Blowfish

Das englische Wort Blowfish bezeichnet seit jeher den überaus farbenfrohen und nur für risikofreudige Individuen genießbaren Kugelfisch. Seit 1993 ist das Wort um eine Bedeutung reicher: Der bekannte Sicherheitsexperte Bruce Schneier veröffentlichte seinen gleichnamigen, vollkommen patentfreien Algorithmus in diesem Jahr zum ersten Mal. Dieser höchst speichersparende Algorithmus erfordert rund 5 KB RAM, ist sehr schnell, verarbeitet Schlüssellängen von 32 bis 448 bit und arbeitet mit einer fixen Blockgröße von 64 bit. Er wurde seit 1993 intensiv untersucht. Bis dato wurden keine nennenswerten Schwächen gefunden – dies kann allerdings auch nur an seiner – im Vergleich zu AES – geringeren „Prominenz“ liegen. An dieser Stelle muss – wie schon im ersten Teil der Artikelserie – massiv von Selbstversuchen bei der Realisierung oder Implementierung von Verschlüsselungsalgorithmen abgeraten werden. Sowohl Entwicklung als auch Kodierung von Verschlüsselungsalgorithmen gehören in die Hand von Experten. Schneier bietet auf seiner Homepage [1] geprüfte Blowfish-Implementierungen in diversen Sprachen an, die als sicher gelten und ohne Bedenken übernommen werden können. Trotzdem können wir einen kurzen Blick auf die Referenzimplementierung werfen.

Die Initialisierung des Algorithmus (Listing 2) erfolgt durch das Laden von Stellen der Zahl Pi. Mit ihnen werden zwei als P und S bezeichnete Arrays befüttert. Das P-Array wird danach durch XOR mit dem Schlüssel verwurstet. Danach wird ein leerer Datenblock „verschlüsselt“, sein Ergebnis wird in P1 und P2 gespeichert. Der Prozess wird so lange wiederholt, bis alle Bänke der Arrays P und S beackert wurden – ein Schlüsselwechsel erfordert also die Verarbeitung von rund 4 KB Daten (Listing 2).

Listing 2
#define N               16
#define subkeyfilename   "Blowfish.dat"

unsigned long P[N + 2];
unsigned long S[4][256];

short InitializeBlowfish(char key[], short keybytes)
{
   short          i;
   short          j;
   short          k;
   short          error;
   short          numread;
   unsigned long  data;
   unsigned long  datal;
   unsigned long  datar;

   /* First, open the file containing the array initialization data */
   error = opensubkeyfile();
   if (error == noErr) {
      for (i = 0; i > 24) |
    ((data & 0x00FF0000) >>  8) |
    ((data & 0x0000FF00) > 24) |
       ((data & 0x00FF0000) >>  8) |
       ((data & 0x0000FF00) = keybytes) {
         j = 0;
      }
   }
   P[i] = P[i] ^ data;
      }

  datal = 0x00000000;
      datar = 0x00000000;

      for (i = 0; i 

Die eigentliche Ver- bzw. Entschlüsselung nutzt die Arrays P und S als Substitutionstabellen, und „XORt“ die Ergebnisse immer wieder zusammen. Aus der Umkehrbarkeit der Funktionen folgt die große Ähnlichkeit zwischen der Verschlüsselungs- und der Entschlüsselungsroutine (Listing 3).

Listing 3
void Blowfish_encipher(unsigned long *xl, unsigned long *xr)
{
   unsigned long  Xl;
   unsigned long  Xr;
   unsigned long  temp;
   short          i;

   Xl = *xl;
   Xr = *xr;

   for (i = 0; i  1; --i) {
      Xl = Xl ^ P[i];
      Xr = F(Xl) ^ Xr;

      /* Exchange Xl and Xr */
      temp = Xl;
      Xl = Xr;
      Xr = temp;
   }

   /* Exchange Xl and Xr */
   temp = Xl;
   Xl = Xr;
   Xr = temp;

   Xr = Xr ^ P[1];
   Xl = Xl ^ P[0];

   *xl = Xl;
   *xr = Xr;
}

Zum Abschluss noch ein kurzer Blick auf die Funktion F – sie zerlegt ein Wort in seine Teilsequenzen und füttert diese durch die Substitutionsboxen (Listing 4).

Listing 4
unsigned long F(unsigned long x)
{
   unsigned short a;
   unsigned short b;
   unsigned short c;
   unsigned short d;
   unsigned long  y;

   d = x & 0x00FF;
   x >>= 8;
   c = x & 0x00FF;
   x >>= 8;
   b = x & 0x00FF;
   x >>= 8;
   a = x & 0x00FF;
   //y = ((S[0][a] + S[1][b]) ^ S[2]) + S[3][d];
   y = S[0][a] + S[1][b];
   y = y ^ S[2];
   y = y + S[3][d];

   return y;
}
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.