IDEA support

Ulrich Mueller ulm at gentoo.org
Wed Jan 11 07:49:14 CET 2012


>>>>> On Mon, 09 Jan 2012, Werner Koch wrote:

> Well, we could now use it but there is not much point besides
> reading of old backups. Maybe I give it a try and add IDEA
> decryption support in 2.1.

Please find a patch included below. It applies cleanly to the trunk
as well as to 1.5.0. I've tested it both with keys and files generated
with PGP 2.6.3in.

Thanks,
Ulrich


https://bugs.gentoo.org/159870
Re-add support for the IDEA cipher.

Based on a patch created by Kristian Fiskerstrand and subsequently
modified by Alon Bar-Lev:
http://www.kfwebs.net/articles/article/42/GnuPG-2.0---IDEA-support

The idea.c file is based on the idea.c file used for gnupg version 1. 
which again is based on an implementation from Bruce Schneier:
Applied Cryptography. John Wiley & Sons, 1996. ISBN 0-471-11709-9.
idea.c in gnupg version 1 was copyrighted by Werner Koch and
distributed under a MIT/X11 license.

Patents on IDEA have expired at the time of writing (2012-01-09).

--- libgcrypt-1.5.0-orig/cipher/Makefile.am
+++ libgcrypt-1.5.0/cipher/Makefile.am
@@ -51,6 +51,7 @@
 dsa.c \
 elgamal.c \
 ecc.c \
+idea.c \
 md4.c \
 md5.c \
 rijndael.c rijndael-tables.h \
--- libgcrypt-1.5.0-orig/cipher/cipher.c
+++ libgcrypt-1.5.0/cipher/cipher.c
@@ -112,6 +112,10 @@
     { &_gcry_cipher_spec_camellia256,
       &dummy_extra_spec,                  GCRY_CIPHER_CAMELLIA256 },
 #endif
+#ifdef USE_IDEA
+    { &_gcry_cipher_spec_idea,
+      &dummy_extra_spec,                  GCRY_CIPHER_IDEA },
+#endif
     { NULL                    }
   };
 
--- libgcrypt-1.5.0-orig/cipher/idea.c
+++ libgcrypt-1.5.0/cipher/idea.c
@@ -0,0 +1,272 @@
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> /* for memcmp() */
+#include <assert.h>
+
+#include "types.h"  /* for byte and u32 typedefs */
+#include "g10lib.h"
+#include "cipher.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
+
+#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
+#define IDEA_ROUNDS 8
+#define IDEA_KEYLEN (6*IDEA_ROUNDS+4)
+
+typedef struct {
+    u16 ek[IDEA_KEYLEN];
+    u16 dk[IDEA_KEYLEN];
+    int have_dk;
+} IDEA_context;
+
+static u16
+mul_inv( u16 x )
+{
+    u16 t0, t1;
+    u16 q, y;
+
+    if( x < 2 )
+	return x;
+    t1 = 0x10001L / x;
+    y =  0x10001L % x;
+    if( y == 1 )
+	return (1-t1) & 0xffff;
+
+    t0 = 1;
+    do {
+	q = x / y;
+	x = x % y;
+	t0 += q * t1;
+	if( x == 1 )
+	    return t0;
+	q = y / x;
+	y = y % x;
+	t1 += q * t0;
+    } while( y != 1 );
+    return (1-t1) & 0xffff;
+}
+
+static void
+cipher( byte *outbuf, const byte *inbuf, u16 *key )
+{
+    u16 x1, x2, x3,x4, s2, s3;
+    u16 *in, *out;
+    int r = IDEA_ROUNDS;
+  #define MUL(x,y) \
+	do {u16 _t16; u32 _t32; 		    \
+	    if( (_t16 = (y)) ) {		    \
+		if( (x = (x)&0xffff) ) {	    \
+		    _t32 = (u32)x * _t16;	    \
+		    x = _t32 & 0xffff;		    \
+		    _t16 = _t32 >> 16;		    \
+		    x = ((x)-_t16) + (x<_t16?1:0);  \
+		}				    \
+		else {				    \
+		    x = 1 - _t16;		    \
+		}				    \
+	    }					    \
+	    else {				    \
+		x = 1 - x;			    \
+	    }					    \
+	} while(0)
+
+    in = (u16*)inbuf;
+    x1 = *in++;
+    x2 = *in++;
+    x3 = *in++;
+    x4 = *in;
+  #ifdef LITTLE_ENDIAN_HOST
+    x1 = (x1>>8) | (x1<<8);
+    x2 = (x2>>8) | (x2<<8);
+    x3 = (x3>>8) | (x3<<8);
+    x4 = (x4>>8) | (x4<<8);
+  #endif
+    do {
+	MUL(x1, *key++);
+	x2 += *key++;
+	x3 += *key++;
+	MUL(x4, *key++ );
+
+	s3 = x3;
+	x3 ^= x1;
+	MUL(x3, *key++);
+	s2 = x2;
+	x2 ^=x4;
+	x2 += x3;
+	MUL(x2, *key++);
+	x3 += x2;
+
+	x1 ^= x2;
+	x4 ^= x3;
+
+	x2 ^= s3;
+	x3 ^= s2;
+    } while( --r );
+    MUL(x1, *key++);
+    x3 += *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
+}
+
+static void
+expand_key( const byte *userkey, u16 *ek )
+{
+    int i,j;
+
+    for(j=0; j < 8; j++ ) {
+	ek[j] = (*userkey << 8) + userkey[1];
+	userkey += 2;
+    }
+    for(i=0; j < IDEA_KEYLEN; j++ ) {
+	i++;
+	ek[i+7] = ek[i&7] << 9 | ek[(i+1)&7] >> 7;
+	ek += i & 8;
+	i &= 7;
+    }
+}
+
+static void
+invert_key( u16 *ek, u16 dk[IDEA_KEYLEN] )
+{
+    int i;
+    u16 t1, t2, t3;
+    u16 temp[IDEA_KEYLEN];
+    u16 *p = temp + IDEA_KEYLEN;
+
+    t1 = mul_inv( *ek++ );
+    t2 = -*ek++;
+    t3 = -*ek++;
+    *--p = mul_inv( *ek++ );
+    *--p = t3;
+    *--p = t2;
+    *--p = t1;
+
+    for(i=0; i < IDEA_ROUNDS-1; i++ ) {
+	t1 = *ek++;
+	*--p = *ek++;
+	*--p = t1;
+
+	t1 = mul_inv( *ek++ );
+	t2 = -*ek++;
+	t3 = -*ek++;
+	*--p = mul_inv( *ek++ );
+	*--p = t2;
+	*--p = t3;
+	*--p = t1;
+    }
+    t1 = *ek++;
+    *--p = *ek++;
+    *--p = t1;
+
+    t1 = mul_inv( *ek++ );
+    t2 = -*ek++;
+    t3 = -*ek++;
+    *--p = mul_inv( *ek++ );
+    *--p = t3;
+    *--p = t2;
+    *--p = t1;
+    memcpy(dk, temp, sizeof(temp) );
+    memset(temp, 0, sizeof(temp) );  /* burn temp */
+}
+
+static int
+do_idea_setkey( IDEA_context *c, const byte *key, unsigned int keylen )
+{
+    assert(keylen == 16);
+    c->have_dk = 0;
+    expand_key( key, c->ek );
+    invert_key( c->ek, c->dk );
+    return 0;
+}
+
+static gcry_err_code_t
+idea_setkey (void *context, const byte *key, unsigned int keylen)
+{
+  IDEA_context *ctx = context;
+  int rc = do_idea_setkey (ctx, key, keylen);
+  _gcry_burn_stack (23+6*sizeof(void*));
+  return rc;
+}
+
+static void
+do_idea_encrypt( IDEA_context *c, byte *outbuf, const byte *inbuf )
+{
+    cipher( outbuf, inbuf, c->ek );
+}
+
+static void
+idea_encrypt (void *context, byte *out, const byte *in)
+{
+  IDEA_context *ctx = context;
+  do_idea_encrypt (ctx, out, in);
+  _gcry_burn_stack (24+3*sizeof (void*));
+}
+
+static void
+do_idea_decrypt( IDEA_context *c, byte *outbuf, const byte *inbuf )
+{
+    if( !c->have_dk ) {
+       c->have_dk = 1;
+       invert_key( c->ek, c->dk );
+    }
+    cipher( outbuf, inbuf, c->dk );
+}
+
+static void
+idea_decrypt (void *context, byte *out, const byte *in)
+{
+  IDEA_context *ctx = context;
+
+  do_idea_decrypt (ctx, out, in);
+  _gcry_burn_stack (24+3*sizeof (void*));
+}
+
+gcry_cipher_spec_t _gcry_cipher_spec_idea =
+  {
+    "IDEA", NULL, NULL, IDEA_BLOCKSIZE, 128, sizeof (IDEA_context),
+    idea_setkey, idea_encrypt, idea_decrypt,
+  };
--- libgcrypt-1.5.0-orig/configure.ac
+++ libgcrypt-1.5.0/configure.ac
@@ -156,7 +156,7 @@
 
 # Definitions for symmetric ciphers.
 available_ciphers="arcfour blowfish cast5 des aes twofish serpent rfc2268 seed"
-available_ciphers="$available_ciphers camellia"
+available_ciphers="$available_ciphers camellia idea"
 enabled_ciphers=""
 
 # Definitions for public-key ciphers.
@@ -1047,6 +1047,12 @@
    AC_DEFINE(USE_CAMELLIA, 1, [Defined if this module should be included])
 fi
 
+LIST_MEMBER(idea, $enabled_ciphers)
+if test "$found" = "1" ; then
+   GCRYPT_CIPHERS="$GCRYPT_CIPHERS idea.lo"
+   AC_DEFINE(USE_IDEA, 1, [Defined if this module should be included])
+fi
+
 LIST_MEMBER(dsa, $enabled_pubkey_ciphers)
 if test "$found" = "1" ; then
    GCRYPT_PUBKEY_CIPHERS="$GCRYPT_PUBKEY_CIPHERS dsa.lo"
--- libgcrypt-1.5.0-orig/src/cipher.h
+++ libgcrypt-1.5.0/src/cipher.h
@@ -135,6 +135,7 @@
 extern gcry_cipher_spec_t _gcry_cipher_spec_camellia128;
 extern gcry_cipher_spec_t _gcry_cipher_spec_camellia192;
 extern gcry_cipher_spec_t _gcry_cipher_spec_camellia256;
+extern gcry_cipher_spec_t _gcry_cipher_spec_idea;
 
 extern cipher_extra_spec_t _gcry_cipher_extraspec_tripledes;
 extern cipher_extra_spec_t _gcry_cipher_extraspec_aes;
--- libgcrypt-1.5.0-orig/tests/basic.c
+++ libgcrypt-1.5.0/tests/basic.c
@@ -1494,6 +1494,9 @@
     GCRY_CIPHER_CAMELLIA192,
     GCRY_CIPHER_CAMELLIA256,
 #endif
+#if USE_IDEA
+    GCRY_CIPHER_IDEA,
+#endif
     0
   };
   static int algos2[] = {



More information about the Gcrypt-devel mailing list