See ChangeLog: Wed Dec 23 13:34:22 CET 1998 Werner Koch
[libgcrypt.git] / cipher / blowfish.c
index 9e3c2bd..fdc4c4b 100644 (file)
@@ -5,14 +5,14 @@
  *   Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
  *   ISBN 0-471-11709-9. Pages 336 ff.
  *
- * This file is part of GNUPG.
+ * This file is part of GnuPG.
  *
- * GNUPG is free software; you can redistribute it and/or modify
+ * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * GNUPG is distributed in the hope that it will be useful,
+ * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
 #include "types.h"
 #include "blowfish.h"
 
+#define CIPHER_ALGO_BLOWFISH    4  /* blowfish 128 bit key */
+#define CIPHER_ALGO_BLOWFISH160 42  /* blowfish 160 bit key (not in OpenPGP)*/
+
+#define FNCCAST_SETKEY(f)  (int(*)(void*, byte*, unsigned))(f)
+#define FNCCAST_CRYPT(f)   (void(*)(void*, byte*, byte*))(f)
+
+#define BLOWFISH_BLOCKSIZE 8
+#define BLOWFISH_ROUNDS 16
+
+typedef struct {
+    u32 s0[256];
+    u32 s1[256];
+    u32 s2[256];
+    u32 s3[256];
+    u32 p[BLOWFISH_ROUNDS+2];
+} BLOWFISH_context;
+
+static int  bf_setkey( BLOWFISH_context *c, byte *key, unsigned keylen );
+static void encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf );
+static void decrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf );
+
+
 /* precomputed S boxes */
 static const u32 ks0[256] = {
     0xD1310BA6,0x98DFB5AC,0x2FFD72DB,0xD01ADFB7,0xB8E1AFED,0x6A267E96,
@@ -391,77 +413,41 @@ decrypt(  BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
 #undef F
 #undef R
 
-void
-blowfish_encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
+static void
+encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
 {
     u32 d1, d2;
 
-  #ifdef BIG_ENDIAN_HOST
-    d1 = ((u32*)inbuf)[0]; /* fixme: this may not be aligned */
-    d2 = ((u32*)inbuf)[1];
-  #else
-    ((byte*)&d1)[3] = inbuf[0];
-    ((byte*)&d1)[2] = inbuf[1];
-    ((byte*)&d1)[1] = inbuf[2];
-    ((byte*)&d1)[0] = inbuf[3];
-    ((byte*)&d2)[3] = inbuf[4];
-    ((byte*)&d2)[2] = inbuf[5];
-    ((byte*)&d2)[1] = inbuf[6];
-    ((byte*)&d2)[0] = inbuf[7];
-  #endif
-
+    d1 = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3];
+    d2 = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7];
     encrypt( bc, &d1, &d2 );
-
-  #ifdef BIG_ENDIAN_HOST
-    ((u32*)outbuf)[0] = d1;
-    ((u32*)outbuf)[1] = d2;
-  #else
-    outbuf[0] = ((byte*)&d1)[3];
-    outbuf[1] = ((byte*)&d1)[2];
-    outbuf[2] = ((byte*)&d1)[1];
-    outbuf[3] = ((byte*)&d1)[0];
-    outbuf[4] = ((byte*)&d2)[3];
-    outbuf[5] = ((byte*)&d2)[2];
-    outbuf[6] = ((byte*)&d2)[1];
-    outbuf[7] = ((byte*)&d2)[0];
-  #endif
+    outbuf[0] = (d1 >> 24) & 0xff;
+    outbuf[1] = (d1 >> 16) & 0xff;
+    outbuf[2] = (d1 >> 8) & 0xff;
+    outbuf[3] =  d1       & 0xff;
+    outbuf[4] = (d2 >> 24) & 0xff;
+    outbuf[5] = (d2 >> 16) & 0xff;
+    outbuf[6] = (d2 >> 8) & 0xff;
+    outbuf[7] =  d2       & 0xff;
 }
 
 
-void
-blowfish_decrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
+static void
+decrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
 {
     u32 d1, d2;
 
-  #ifdef BIG_ENDIAN_HOST
-    d1 = ((u32*)inbuf)[0]; /* fixme: this may not be aligned */
-    d2 = ((u32*)inbuf)[1];
-  #else
-    ((byte*)&d1)[3] = inbuf[0];
-    ((byte*)&d1)[2] = inbuf[1];
-    ((byte*)&d1)[1] = inbuf[2];
-    ((byte*)&d1)[0] = inbuf[3];
-    ((byte*)&d2)[3] = inbuf[4];
-    ((byte*)&d2)[2] = inbuf[5];
-    ((byte*)&d2)[1] = inbuf[6];
-    ((byte*)&d2)[0] = inbuf[7];
-  #endif
-
+    d1 = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3];
+    d2 = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7];
     decrypt( bc, &d1, &d2 );
-
-  #ifdef BIG_ENDIAN_HOST
-    ((u32*)outbuf)[0] = d1;
-    ((u32*)outbuf)[1] = d2;
-  #else
-    outbuf[0] = ((byte*)&d1)[3];
-    outbuf[1] = ((byte*)&d1)[2];
-    outbuf[2] = ((byte*)&d1)[1];
-    outbuf[3] = ((byte*)&d1)[0];
-    outbuf[4] = ((byte*)&d2)[3];
-    outbuf[5] = ((byte*)&d2)[2];
-    outbuf[6] = ((byte*)&d2)[1];
-    outbuf[7] = ((byte*)&d2)[0];
-  #endif
+    outbuf[0] = (d1 >> 24) & 0xff;
+    outbuf[1] = (d1 >> 16) & 0xff;
+    outbuf[2] = (d1 >> 8) & 0xff;
+    outbuf[3] =  d1       & 0xff;
+    outbuf[4] = (d2 >> 24) & 0xff;
+    outbuf[5] = (d2 >> 16) & 0xff;
+    outbuf[6] = (d2 >> 8) & 0xff;
+    outbuf[7] =  d2       & 0xff;
 }
 
 
@@ -475,27 +461,27 @@ selftest()
     byte key3[] = { 0x41, 0x79, 0x6E, 0xA0, 0x52, 0x61, 0x6E, 0xE4 };
     byte cipher3[] = { 0xE1, 0x13, 0xF4, 0x10, 0x2C, 0xFC, 0xCE, 0x43 };
 
-    blowfish_setkey( &c, "abcdefghijklmnopqrstuvwxyz", 26 );
-    blowfish_encrypt_block( &c, buffer, plain );
+    bf_setkey( &c, "abcdefghijklmnopqrstuvwxyz", 26 );
+    encrypt_block( &c, buffer, plain );
     if( memcmp( buffer, "\x32\x4E\xD0\xFE\xF4\x13\xA2\x03", 8 ) )
        log_error("wrong blowfish encryption\n");
-    blowfish_decrypt_block( &c, buffer, buffer );
+    decrypt_block( &c, buffer, buffer );
     if( memcmp( buffer, plain, 8 ) )
        log_bug("blowfish failed\n");
 
-    blowfish_setkey( &c, key3, 8 );
-    blowfish_encrypt_block( &c, buffer, plain3 );
+    bf_setkey( &c, key3, 8 );
+    encrypt_block( &c, buffer, plain3 );
     if( memcmp( buffer, cipher3, 8 ) )
        log_error("wrong blowfish encryption (3)\n");
-    blowfish_decrypt_block( &c, buffer, buffer );
+    decrypt_block( &c, buffer, buffer );
     if( memcmp( buffer, plain3, 8 ) )
        log_bug("blowfish failed (3)\n");
 }
 
 
 
-void
-blowfish_setkey( BLOWFISH_context *c, byte *key, unsigned keylen )
+static int
+bf_setkey( BLOWFISH_context *c, byte *key, unsigned keylen )
 {
     int i, j;
     u32 data, datal, datar;
@@ -557,6 +543,47 @@ blowfish_setkey( BLOWFISH_context *c, byte *key, unsigned keylen )
        c->s3[i]   = datal;
        c->s3[i+1] = datar;
     }
+
+
+    /* Check for weak key.  A weak key is a key in which a value in */
+    /* the P-array (here c) occurs more than once per table.       */
+    for(i=0; i < 255; i++ ) {
+       for( j=i+1; j < 256; j++) {
+           if( (c->s0[i] == c->s0[j]) || (c->s1[i] == c->s1[j]) ||
+               (c->s2[i] == c->s2[j]) || (c->s3[i] == c->s3[j]) )
+               return G10ERR_WEAK_KEY;
+       }
+    }
+
+    return 0;
 }
 
 
+/****************
+ * Return some information about the algorithm.  We need algo here to
+ * distinguish different flavors of the algorithm.
+ * Returns: A pointer to string describing the algorithm or NULL if
+ *         the ALGO is invalid.
+ */
+const char *
+blowfish_get_info( int algo, size_t *keylen,
+                  size_t *blocksize, size_t *contextsize,
+                  int  (**r_setkey)( void *c, byte *key, unsigned keylen ),
+                  void (**r_encrypt)( void *c, byte *outbuf, byte *inbuf ),
+                  void (**r_decrypt)( void *c, byte *outbuf, byte *inbuf )
+                )
+{
+    *keylen = algo == CIPHER_ALGO_BLOWFISH ? 128 : 160;
+    *blocksize = BLOWFISH_BLOCKSIZE;
+    *contextsize = sizeof(BLOWFISH_context);
+    *r_setkey = FNCCAST_SETKEY(bf_setkey);
+    *r_encrypt= FNCCAST_CRYPT(encrypt_block);
+    *r_decrypt= FNCCAST_CRYPT(decrypt_block);
+
+    if( algo == CIPHER_ALGO_BLOWFISH )
+       return "BLOWFISH";
+    if( algo == CIPHER_ALGO_BLOWFISH160 )
+       return "BLOWFISH160";
+    return NULL;
+}
+