Add PowerPC extra CFLAGS also for chacha20-ppc and crc-ppc
[libgcrypt.git] / cipher / idea.c
index 65a8ec3..abfe675 100644 (file)
@@ -1,5 +1,6 @@
 /* idea.c  -  IDEA function
- *     Copyright (c) 1997, 1998, 1999, 2001 by Werner Koch (dd9jn)
+ * Copyright 1997, 1998, 1999, 2001 Werner Koch (dd9jn)
+ * Copyright 2013 g10 Code GmbH
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * used in advertising or otherwise to promote the sale, use or other dealings
  * in this Software without prior written authorization from Werner Koch.
  *
- * DUE TO PATENT CLAIMS THE DISTRIBUTION OF THE SOFTWARE IS NOT ALLOWED IN
- * THESE COUNTRIES:
- *     AUSTRIA, FRANCE, GERMANY, ITALY, JAPAN, THE NETHERLANDS,
- *     SPAIN, SWEDEN, SWITZERLAND, THE UK AND THE US.
+ * Patents on IDEA have expired:
+ *   Europe: EP0482154 on 2011-05-16,
+ *   Japan:  JP3225440 on 2011-05-16,
+ *   U.S.:   5,214,703 on 2012-01-07.
  */
 
 /*
  *
  * The code herein is based on the one from:
  *   Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
- *    ISBN 0-471-11709-9. .
- *
- * How to compile:
-       gcc -Wall -O2 -shared -fPIC -o idea idea.c
- *
- * 2001-06-08 wk  Changed distribution conditions
- * 2001-06-11 wk  Fixed invert_key (which is not used in CFB mode)
- *                Thanks to Mark A. Borgerding.  Added defintion for
- *                the PowerPC.
+ *   ISBN 0-471-11709-9.
  */
 
 
+#include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
 
-/* configuration stuff */
-#ifdef __alpha__
-  #define SIZEOF_UNSIGNED_LONG 8
-#else
-  #define SIZEOF_UNSIGNED_LONG 4
-#endif
-
-#if defined(__mc68000__) || defined (__sparc__) || defined (__PPC__) \
-    || (defined(__mips__) && (defined(MIPSEB) || defined (__MIPSEB__)) ) \
-    || defined(__powerpc__) \
-    || defined(__hpux__) /* should be replaced by the Macro for the PA */
-  #define BIG_ENDIAN_HOST 1
-#else
-  #define LITTLE_ENDIAN_HOST 1
-#endif
-
-typedef unsigned long  ulong;
-typedef unsigned short ushort;
-typedef unsigned char  byte;
-
-typedef unsigned short u16;
-typedef unsigned long  u32;
+#include "types.h"  /* for byte and u32 typedefs */
+#include "g10lib.h"
+#include "cipher.h"
 
-/* end configurable stuff */
-
-#ifndef DIM
-  #define DIM(v) (sizeof(v)/sizeof((v)[0]))
-  #define DIMof(type,member)   DIM(((type *)0)->member)
-#endif
-
-/* imports */
-void g10_log_fatal( const char *fmt, ... );
-
-
-/* local stuff */
-
-#define FNCCAST_SETKEY(f)  ((int(*)(void*, byte*, unsigned))(f))
-#define FNCCAST_CRYPT(f)   ((void(*)(void*, byte*, byte*))(f))
 
 #define IDEA_KEYSIZE 16
 #define IDEA_BLOCKSIZE 8
@@ -101,12 +61,7 @@ typedef struct {
     int have_dk;
 } IDEA_context;
 
-
-static int do_setkey( IDEA_context *c, byte *key, unsigned keylen );
-static void encrypt_block( IDEA_context *bc, byte *outbuf, byte *inbuf );
-static void decrypt_block( IDEA_context *bc, byte *outbuf, byte *inbuf );
-static void selftest(int);
-
+static const char *selftest(void);
 
 
 static u16
@@ -117,8 +72,8 @@ mul_inv( u16 x )
 
     if( x < 2 )
        return x;
-    t1 = 0x10001L / x;
-    y =  0x10001L % x;
+    t1 = 0x10001UL / x;
+    y =  0x10001UL % x;
     if( y == 1 )
        return (1-t1) & 0xffff;
 
@@ -139,7 +94,7 @@ mul_inv( u16 x )
 
 
 static void
-expand_key( byte *userkey, u16 *ek )
+expand_key( const byte *userkey, u16 *ek )
 {
     int i,j;
 
@@ -197,17 +152,21 @@ invert_key( u16 *ek, u16 dk[IDEA_KEYLEN] )
     *--p = t2;
     *--p = t1;
     memcpy(dk, temp, sizeof(temp) );
-    memset(temp, 0, sizeof(temp) );  /* burn temp */
+    wipememory(temp, sizeof(temp));
 }
 
 
 static void
-cipher( byte *outbuf, byte *inbuf, u16 *key )
+cipher( byte *outbuf, const byte *inbuf, u16 *key )
 {
-    u16 x1, x2, x3,x4, s2, s3;
-    u16 *in, *out;
+    u16 s2, s3;
+    u16 in[4];
     int r = IDEA_ROUNDS;
-  #define MUL(x,y) \
+#define x1 (in[0])
+#define x2 (in[1])
+#define x3 (in[2])
+#define x4 (in[3])
+#define MUL(x,y) \
        do {u16 _t16; u32 _t32;                     \
            if( (_t16 = (y)) ) {                    \
                if( (x = (x)&0xffff) ) {            \
@@ -225,17 +184,13 @@ cipher( byte *outbuf, byte *inbuf, u16 *key )
            }                                       \
        } while(0)
 
-    in = (u16*)inbuf;
-    x1 = *in++;
-    x2 = *in++;
-    x3 = *in++;
-    x4 = *in;
-  #ifdef LITTLE_ENDIAN_HOST
+    memcpy (in, inbuf, sizeof in);
+#ifndef WORDS_BIGENDIAN
     x1 = (x1>>8) | (x1<<8);
     x2 = (x2>>8) | (x2<<8);
     x3 = (x3>>8) | (x3<<8);
     x4 = (x4>>8) | (x4<<8);
-  #endif
+#endif
     do {
        MUL(x1, *key++);
        x2 += *key++;
@@ -262,31 +217,39 @@ cipher( byte *outbuf, byte *inbuf, u16 *key )
     x2 += *key++;
     MUL(x4, *key);
 
-    out = (u16*)outbuf;
-  #ifdef LITTLE_ENDIAN_HOST
-    *out++ = (x1>>8) | (x1<<8);
-    *out++ = (x3>>8) | (x3<<8);
-    *out++ = (x2>>8) | (x2<<8);
-    *out   = (x4>>8) | (x4<<8);
-  #else
-    *out++ = x1;
-    *out++ = x3;
-    *out++ = x2;
-    *out   = x4;
-  #endif
-  #undef MUL
+#ifndef WORDS_BIGENDIAN
+    x1 = (x1>>8) | (x1<<8);
+    x2 = (x2>>8) | (x2<<8);
+    x3 = (x3>>8) | (x3<<8);
+    x4 = (x4>>8) | (x4<<8);
+#endif
+    memcpy (outbuf+0, &x1, 2);
+    memcpy (outbuf+2, &x3, 2);
+    memcpy (outbuf+4, &x2, 2);
+    memcpy (outbuf+6, &x4, 2);
+#undef MUL
+#undef x1
+#undef x2
+#undef x3
+#undef x4
 }
 
 
 static int
-do_setkey( IDEA_context *c, byte *key, unsigned keylen )
+do_setkey( IDEA_context *c, const byte *key, unsigned int keylen )
 {
     static int initialized = 0;
+    static const char *selftest_failed = 0;
 
     if( !initialized ) {
        initialized = 1;
-       selftest(0);
+       selftest_failed = selftest();
+       if( selftest_failed )
+           log_error( "%s\n", selftest_failed );
     }
+    if( selftest_failed )
+       return GPG_ERR_SELFTEST_FAILED;
+
     assert(keylen == 16);
     c->have_dk = 0;
     expand_key( key, c->ek );
@@ -294,21 +257,34 @@ do_setkey( IDEA_context *c, byte *key, unsigned keylen )
     return 0;
 }
 
+static gcry_err_code_t
+idea_setkey (void *context, const byte *key, unsigned int keylen,
+             gcry_cipher_hd_t hd)
+{
+    IDEA_context *ctx = context;
+    int rc = do_setkey (ctx, key, keylen);
+    (void)hd;
+    _gcry_burn_stack (23+6*sizeof(void*));
+    return rc;
+}
+
 static void
-encrypt_block( IDEA_context *c, byte *outbuf, byte *inbuf )
+encrypt_block( IDEA_context *c, byte *outbuf, const byte *inbuf )
 {
     cipher( outbuf, inbuf, c->ek );
 }
 
-static void
-decrypt_block( IDEA_context *c, byte *outbuf, byte *inbuf )
+static unsigned int
+idea_encrypt (void *context, byte *out, const byte *in)
 {
-    static int initialized;
+    IDEA_context *ctx = context;
+    encrypt_block (ctx, out, in);
+    return /*burn_stack*/ (24+3*sizeof (void*));
+}
 
-    if( !initialized ) {
-       initialized = 1;
-       selftest(1);
-    }
+static void
+decrypt_block( IDEA_context *c, byte *outbuf, const byte *inbuf )
+{
     if( !c->have_dk ) {
        c->have_dk = 1;
        invert_key( c->ek, c->dk );
@@ -316,9 +292,17 @@ decrypt_block( IDEA_context *c, byte *outbuf, byte *inbuf )
     cipher( outbuf, inbuf, c->dk );
 }
 
+static unsigned int
+idea_decrypt (void *context, byte *out, const byte *in)
+{
+    IDEA_context *ctx = context;
+    decrypt_block (ctx, out, in);
+    return /*burn_stack*/ (24+3*sizeof (void*));
+}
+
 
-static void
-selftest( int check_decrypt )
+static const char *
+selftest( void )
 {
 static struct {
     byte key[16];
@@ -376,101 +360,22 @@ static struct {
 
     for(i=0; i < DIM(test_vectors); i++ ) {
        do_setkey( &c, test_vectors[i].key, 16 );
-       if( !check_decrypt ) {
-           encrypt_block( &c, buffer, test_vectors[i].plain );
-           if( memcmp( buffer, test_vectors[i].cipher, 8 ) )
-               g10_log_fatal("idea encryption (%d) failed\n", i);
-       }
-       else {
-           decrypt_block( &c, buffer, test_vectors[i].cipher );
-           if( memcmp( buffer, test_vectors[i].plain, 8 ) )
-               g10_log_fatal("idea decryption (%d) failed\n", i);
-       }
+       encrypt_block( &c, buffer, test_vectors[i].plain );
+       if( memcmp( buffer, test_vectors[i].cipher, 8 ) )
+           return "IDEA test encryption failed.";
+       decrypt_block( &c, buffer, test_vectors[i].cipher );
+       if( memcmp( buffer, test_vectors[i].plain, 8 ) )
+           return "IDEA test decryption failed.";
     }
-}
-
 
-/****************
- * 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 *
-idea_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 = 128;
-    *blocksize = 8;
-    *contextsize = sizeof(IDEA_context);
-    *r_setkey = FNCCAST_SETKEY(do_setkey);
-    *r_encrypt= FNCCAST_CRYPT(encrypt_block);
-    *r_decrypt= FNCCAST_CRYPT(decrypt_block);
-    if( algo == 1 )
-       return "IDEA";
     return NULL;
 }
 
 
-
-const char * const gnupgext_version = "IDEA ($Revision: 1.11 $)";
-
-static struct {
-    int class;
-    int version;
-    int  value;
-    void (*func)(void);
-} func_table[] = {
-    { 20, 1, 0, (void(*)(void))idea_get_info },
-    { 21, 1, 1 },
-};
-
-
-
-/****************
- * Enumerate the names of the functions together with informations about
- * this function. Set sequence to an integer with a initial value of 0 and
- * do not change it.
- * If what is 0 all kind of functions are returned.
- * Return values: class := class of function:
- *                        10 = message digest algorithm info function
- *                        11 = integer with available md algorithms
- *                        20 = cipher algorithm info function
- *                        21 = integer with available cipher algorithms
- *                        30 = public key algorithm info function
- *                        31 = integer with available pubkey algorithms
- *               version = interface version of the function/pointer
- *                         (currently this is 1 for all functions)
- */
-void *
-gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
-{
-    void *ret;
-    int i = *sequence;
-
-    do {
-       if( i >= DIM(func_table) || i < 0 ) {
-           return NULL;
-       }
-       *class = func_table[i].class;
-       *vers  = func_table[i].version;
-       switch( *class ) {
-         case 11:
-         case 21:
-         case 31:
-           ret = &func_table[i].value;
-           break;
-         default:
-           ret = func_table[i].func;
-           break;
-       }
-       i++;
-    } while( what && what != *class );
-
-    *sequence = i;
-    return ret;
-}
+gcry_cipher_spec_t _gcry_cipher_spec_idea =
+  {
+    GCRY_CIPHER_IDEA, {0, 0},
+    "IDEA", NULL, NULL, IDEA_BLOCKSIZE, 128,
+    sizeof (IDEA_context),
+    idea_setkey, idea_encrypt, idea_decrypt
+  };