2003-07-21 Moritz Schulte <moritz@g10code.com>
[libgcrypt.git] / cipher / blowfish.c
index f5c29c6..84d8fd6 100644 (file)
@@ -1,25 +1,25 @@
 /* blowfish.c  -  Blowfish encryption
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation, Inc.
  *
- * For a description of the algorithm, see:
- *   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 Libgcrypt.
  *
- * 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.
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser general Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
  *
- * GNUPG is distributed in the hope that it will be useful,
+ * Libgcrypt 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.
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * For a description of the algorithm, see:
+ *   Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
+ *   ISBN 0-471-11709-9. Pages 336 ff.
  */
 
 /* Test values:
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
-#include "util.h"
 #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)
+#include "g10lib.h"
+#include "cipher.h"
 
 #define BLOWFISH_BLOCKSIZE 8
 #define BLOWFISH_ROUNDS 16
@@ -55,9 +49,9 @@ typedef struct {
     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 );
+static gcry_err_code_t bf_setkey (void *c, const byte *key, unsigned keylen);
+static void encrypt_block (void *bc, byte *outbuf, const byte *inbuf);
+static void decrypt_block (void *bc, byte *outbuf, const byte *inbuf);
 
 
 /* precomputed S boxes */
@@ -254,36 +248,35 @@ function_F( BLOWFISH_context *bc, u32 x )
 {
     u16 a, b, c, d;
 
-  #ifdef BIG_ENDIAN_HOST
+#ifdef WORDS_BIGENDIAN
     a = ((byte*)&x)[0];
     b = ((byte*)&x)[1];
     c = ((byte*)&x)[2];
     d = ((byte*)&x)[3];
-  #else
+#else
     a = ((byte*)&x)[3];
     b = ((byte*)&x)[2];
     c = ((byte*)&x)[1];
     d = ((byte*)&x)[0];
-  #endif
+#endif
 
     return ((bc->s0[a] + bc->s1[b]) ^ bc->s2[c] ) + bc->s3[d];
 }
 #endif
 
-#ifdef BIG_ENDIAN_HOST
-  #define F(x) ((( s0[((byte*)&x)[0]] + s1[((byte*)&x)[1]])     \
+#ifdef WORDS_BIGENDIAN
+#define F(x) ((( s0[((byte*)&x)[0]] + s1[((byte*)&x)[1]])       \
                   ^ s2[((byte*)&x)[2]]) + s3[((byte*)&x)[3]] )
 #else
-  #define F(x) ((( s0[((byte*)&x)[3]] + s1[((byte*)&x)[2]])     \
+#define F(x) ((( s0[((byte*)&x)[3]] + s1[((byte*)&x)[2]])       \
                   ^ s2[((byte*)&x)[1]]) + s3[((byte*)&x)[0]] )
 #endif
 #define R(l,r,i)  do { l ^= p[i]; r ^= F(l); } while(0)
 
-
 static void
-encrypt(  BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
+do_encrypt(  BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
 {
-  #if BLOWFISH_ROUNDS == 16
+#if BLOWFISH_ROUNDS == 16
     u32 xl, xr, *s0, *s1, *s2, *s3, *p;
 
     xl = *ret_xl;
@@ -317,7 +310,7 @@ encrypt(  BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
     *ret_xl = xr;
     *ret_xr = xl;
 
-  #else
+#else
     u32 xl, xr, temp, *p;
     int i;
 
@@ -341,14 +334,14 @@ encrypt(  BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
 
     *ret_xl = xl;
     *ret_xr = xr;
-  #endif
+#endif
 }
 
 
 static void
 decrypt(  BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
 {
-  #if BLOWFISH_ROUNDS == 16
+#if BLOWFISH_ROUNDS == 16
     u32 xl, xr, *s0, *s1, *s2, *s3, *p;
 
     xl = *ret_xl;
@@ -382,7 +375,7 @@ decrypt(  BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
     *ret_xl = xr;
     *ret_xr = xl;
 
-  #else
+#else
     u32 xl, xr, temp, *p;
     int i;
 
@@ -407,20 +400,20 @@ decrypt(  BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
 
     *ret_xl = xl;
     *ret_xr = xr;
-  #endif
+#endif
 }
 
 #undef F
 #undef R
 
 static void
-encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
+do_encrypt_block ( BLOWFISH_context *bc, byte *outbuf, const byte *inbuf )
 {
     u32 d1, d2;
 
     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 );
+    do_encrypt( bc, &d1, &d2 );
     outbuf[0] = (d1 >> 24) & 0xff;
     outbuf[1] = (d1 >> 16) & 0xff;
     outbuf[2] = (d1 >> 8) & 0xff;
@@ -431,9 +424,17 @@ encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
     outbuf[7] =  d2       & 0xff;
 }
 
+static void
+encrypt_block (void *context, byte *outbuf, const byte *inbuf)
+{
+  BLOWFISH_context *bc = (BLOWFISH_context *) context;
+  do_encrypt_block (bc, outbuf, inbuf);
+  _gcry_burn_stack (64);
+}
+
 
 static void
-decrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
+do_decrypt_block (BLOWFISH_context *bc, byte *outbuf, const byte *inbuf)
 {
     u32 d1, d2;
 
@@ -450,9 +451,17 @@ decrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
     outbuf[7] =  d2       & 0xff;
 }
 
-
 static void
-selftest()
+decrypt_block (void *context, byte *outbuf, const byte *inbuf)
+{
+  BLOWFISH_context *bc = (BLOWFISH_context *) context;
+  do_decrypt_block (bc, outbuf, inbuf);
+  _gcry_burn_stack (64);
+}
+
+
+static const char*
+selftest(void)
 {
     BLOWFISH_context c;
     byte plain[] = "BLOWFISH";
@@ -461,36 +470,42 @@ selftest()
     byte key3[] = { 0x41, 0x79, 0x6E, 0xA0, 0x52, 0x61, 0x6E, 0xE4 };
     byte cipher3[] = { 0xE1, 0x13, 0xF4, 0x10, 0x2C, 0xFC, 0xCE, 0x43 };
 
-    bf_setkey( &c, "abcdefghijklmnopqrstuvwxyz", 26 );
-    encrypt_block( &c, buffer, plain );
+    bf_setkey( (void *) &c, "abcdefghijklmnopqrstuvwxyz", 26 );
+    encrypt_block( (void *) &c, buffer, plain );
     if( memcmp( buffer, "\x32\x4E\xD0\xFE\xF4\x13\xA2\x03", 8 ) )
-       log_error("wrong blowfish encryption\n");
-    decrypt_block( &c, buffer, buffer );
+       return "Blowfish selftest failed (1).";
+    decrypt_block( (void *) &c, buffer, buffer );
     if( memcmp( buffer, plain, 8 ) )
-       log_bug("blowfish failed\n");
+       return "Blowfish selftest failed (2).";
 
-    bf_setkey( &c, key3, 8 );
-    encrypt_block( &c, buffer, plain3 );
+    bf_setkey( (void *) &c, key3, 8 );
+    encrypt_block( (void *) &c, buffer, plain3 );
     if( memcmp( buffer, cipher3, 8 ) )
-       log_error("wrong blowfish encryption (3)\n");
-    decrypt_block( &c, buffer, buffer );
+       return "Blowfish selftest failed (3).";
+    decrypt_block( (void *) &c, buffer, buffer );
     if( memcmp( buffer, plain3, 8 ) )
-       log_bug("blowfish failed (3)\n");
+       return "Blowfish selftest failed (4).";
+    return NULL;
 }
 
 
 
-static int
-bf_setkey( BLOWFISH_context *c, byte *key, unsigned keylen )
+static gcry_err_code_t
+do_bf_setkey (BLOWFISH_context *c, const byte *key, unsigned keylen)
 {
     int i, j;
     u32 data, datal, datar;
     static int initialized;
+    static const char *selftest_failed;
 
     if( !initialized ) {
        initialized = 1;
-       selftest();
+       selftest_failed = selftest();
+       if( selftest_failed )
+           log_error ("%s\n", selftest_failed );
     }
+    if( selftest_failed )
+      return GPG_ERR_SELFTEST_FAILED;
 
     for(i=0; i < BLOWFISH_ROUNDS+2; i++ )
        c->p[i] = ps[i];
@@ -502,44 +517,44 @@ bf_setkey( BLOWFISH_context *c, byte *key, unsigned keylen )
     }
 
     for(i=j=0; i < BLOWFISH_ROUNDS+2; i++ ) {
-      #ifdef BIG_ENDIAN_HOST
+#ifdef WORDS_BIGENDIAN
        ((byte*)&data)[0] = key[j];
        ((byte*)&data)[1] = key[(j+1)%keylen];
        ((byte*)&data)[2] = key[(j+2)%keylen];
        ((byte*)&data)[3] = key[(j+3)%keylen];
-      #else
+#else
        ((byte*)&data)[3] = key[j];
        ((byte*)&data)[2] = key[(j+1)%keylen];
        ((byte*)&data)[1] = key[(j+2)%keylen];
        ((byte*)&data)[0] = key[(j+3)%keylen];
-      #endif
+#endif
        c->p[i] ^= data;
        j = (j+4) % keylen;
     }
 
     datal = datar = 0;
     for(i=0; i < BLOWFISH_ROUNDS+2; i += 2 ) {
-       encrypt( c, &datal, &datar );
+       do_encrypt( c, &datal, &datar );
        c->p[i]   = datal;
        c->p[i+1] = datar;
     }
     for(i=0; i < 256; i += 2 ) {
-       encrypt( c, &datal, &datar );
+       do_encrypt( c, &datal, &datar );
        c->s0[i]   = datal;
        c->s0[i+1] = datar;
     }
     for(i=0; i < 256; i += 2 ) {
-       encrypt( c, &datal, &datar );
+       do_encrypt( c, &datal, &datar );
        c->s1[i]   = datal;
        c->s1[i+1] = datar;
     }
     for(i=0; i < 256; i += 2 ) {
-       encrypt( c, &datal, &datar );
+       do_encrypt( c, &datal, &datar );
        c->s2[i]   = datal;
        c->s2[i+1] = datar;
     }
     for(i=0; i < 256; i += 2 ) {
-       encrypt( c, &datal, &datar );
+       do_encrypt( c, &datal, &datar );
        c->s3[i]   = datal;
        c->s3[i+1] = datar;
     }
@@ -551,39 +566,28 @@ bf_setkey( BLOWFISH_context *c, byte *key, unsigned keylen )
        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 GPG_ERR_WEAK_KEY;
        }
     }
 
-    return 0;
+    return GPG_ERR_NO_ERROR;
 }
 
 
-/****************
- * 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 )
-                )
+static gcry_err_code_t
+bf_setkey (void *context, const byte *key, unsigned keylen)
 {
-    *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;
+  BLOWFISH_context *c = (BLOWFISH_context *) context;
+  gcry_err_code_t rc = do_bf_setkey (c, key, keylen);
+  _gcry_burn_stack (64);
+  return rc;
 }
 
+\f
+
+gcry_cipher_spec_t cipher_spec_blowfish =
+  {
+    "BLOWFISH", NULL, NULL, BLOWFISH_BLOCKSIZE, 128,
+    sizeof (BLOWFISH_context),
+    bf_setkey, encrypt_block, decrypt_block,
+  };