michael@107: #include michael@107: #include michael@107: #include michael@107: #include /* for memcmp() */ michael@107: #include michael@107: michael@107: #include "types.h" /* for byte and u32 typedefs */ michael@107: #include "g10lib.h" michael@107: #include "cipher.h" michael@107: michael@107: /* configuration stuff */ michael@107: #ifdef __alpha__ michael@107: #define SIZEOF_UNSIGNED_LONG 8 michael@107: #else michael@107: #define SIZEOF_UNSIGNED_LONG 4 michael@107: #endif michael@107: michael@107: #if defined(__mc68000__) || defined (__sparc__) || defined (__PPC__) \ michael@107: || (defined(__mips__) && (defined(MIPSEB) || defined (__MIPSEB__)) ) \ michael@107: || defined(__powerpc__) \ michael@107: || defined(__hpux__) /* should be replaced by the Macro for the PA */ michael@107: #define BIG_ENDIAN_HOST 1 michael@107: #else michael@107: #define LITTLE_ENDIAN_HOST 1 michael@107: #endif michael@107: michael@107: #ifndef DIM michael@107: #define DIM(v) (sizeof(v)/sizeof((v)[0])) michael@107: #define DIMof(type,member) DIM(((type *)0)->member) michael@107: #endif michael@107: michael@107: /* imports */ michael@107: void g10_log_fatal( const char *fmt, ... ); michael@107: michael@107: michael@107: /* local stuff */ michael@107: michael@107: #define FNCCAST_SETKEY(f) ((int(*)(void*, byte*, unsigned))(f)) michael@107: #define FNCCAST_CRYPT(f) ((void(*)(void*, byte*, byte*))(f)) michael@107: michael@107: #define IDEA_KEYSIZE 16 michael@107: #define IDEA_BLOCKSIZE 8 michael@107: #define IDEA_ROUNDS 8 michael@107: #define IDEA_KEYLEN (6*IDEA_ROUNDS+4) michael@107: michael@107: typedef struct { michael@107: u16 ek[IDEA_KEYLEN]; michael@107: u16 dk[IDEA_KEYLEN]; michael@107: int have_dk; michael@107: } IDEA_context; michael@107: michael@107: static u16 michael@107: mul_inv( u16 x ) michael@107: { michael@107: u16 t0, t1; michael@107: u16 q, y; michael@107: michael@107: if( x < 2 ) michael@107: return x; michael@107: t1 = 0x10001L / x; michael@107: y = 0x10001L % x; michael@107: if( y == 1 ) michael@107: return (1-t1) & 0xffff; michael@107: michael@107: t0 = 1; michael@107: do { michael@107: q = x / y; michael@107: x = x % y; michael@107: t0 += q * t1; michael@107: if( x == 1 ) michael@107: return t0; michael@107: q = y / x; michael@107: y = y % x; michael@107: t1 += q * t0; michael@107: } while( y != 1 ); michael@107: return (1-t1) & 0xffff; michael@107: } michael@107: michael@107: static void michael@107: cipher( byte *outbuf, const byte *inbuf, u16 *key ) michael@107: { michael@107: u16 x1, x2, x3,x4, s2, s3; michael@107: u16 *in, *out; michael@107: int r = IDEA_ROUNDS; michael@107: #define MUL(x,y) \ michael@107: do {u16 _t16; u32 _t32; \ michael@107: if( (_t16 = (y)) ) { \ michael@107: if( (x = (x)&0xffff) ) { \ michael@107: _t32 = (u32)x * _t16; \ michael@107: x = _t32 & 0xffff; \ michael@107: _t16 = _t32 >> 16; \ michael@107: x = ((x)-_t16) + (x<_t16?1:0); \ michael@107: } \ michael@107: else { \ michael@107: x = 1 - _t16; \ michael@107: } \ michael@107: } \ michael@107: else { \ michael@107: x = 1 - x; \ michael@107: } \ michael@107: } while(0) michael@107: michael@107: in = (u16*)inbuf; michael@107: x1 = *in++; michael@107: x2 = *in++; michael@107: x3 = *in++; michael@107: x4 = *in; michael@107: #ifdef LITTLE_ENDIAN_HOST michael@107: x1 = (x1>>8) | (x1<<8); michael@107: x2 = (x2>>8) | (x2<<8); michael@107: x3 = (x3>>8) | (x3<<8); michael@107: x4 = (x4>>8) | (x4<<8); michael@107: #endif michael@107: do { michael@107: MUL(x1, *key++); michael@107: x2 += *key++; michael@107: x3 += *key++; michael@107: MUL(x4, *key++ ); michael@107: michael@107: s3 = x3; michael@107: x3 ^= x1; michael@107: MUL(x3, *key++); michael@107: s2 = x2; michael@107: x2 ^=x4; michael@107: x2 += x3; michael@107: MUL(x2, *key++); michael@107: x3 += x2; michael@107: michael@107: x1 ^= x2; michael@107: x4 ^= x3; michael@107: michael@107: x2 ^= s3; michael@107: x3 ^= s2; michael@107: } while( --r ); michael@107: MUL(x1, *key++); michael@107: x3 += *key++; michael@107: x2 += *key++; michael@107: MUL(x4, *key); michael@107: michael@107: out = (u16*)outbuf; michael@107: #ifdef LITTLE_ENDIAN_HOST michael@107: *out++ = (x1>>8) | (x1<<8); michael@107: *out++ = (x3>>8) | (x3<<8); michael@107: *out++ = (x2>>8) | (x2<<8); michael@107: *out = (x4>>8) | (x4<<8); michael@107: #else michael@107: *out++ = x1; michael@107: *out++ = x3; michael@107: *out++ = x2; michael@107: *out = x4; michael@107: #endif michael@107: #undef MUL michael@107: } michael@107: michael@107: static void michael@107: expand_key( const byte *userkey, u16 *ek ) michael@107: { michael@107: int i,j; michael@107: michael@107: for(j=0; j < 8; j++ ) { michael@107: ek[j] = (*userkey << 8) + userkey[1]; michael@107: userkey += 2; michael@107: } michael@107: for(i=0; j < IDEA_KEYLEN; j++ ) { michael@107: i++; michael@107: ek[i+7] = ek[i&7] << 9 | ek[(i+1)&7] >> 7; michael@107: ek += i & 8; michael@107: i &= 7; michael@107: } michael@107: } michael@107: michael@107: static void michael@107: invert_key( u16 *ek, u16 dk[IDEA_KEYLEN] ) michael@107: { michael@107: int i; michael@107: u16 t1, t2, t3; michael@107: u16 temp[IDEA_KEYLEN]; michael@107: u16 *p = temp + IDEA_KEYLEN; michael@107: michael@107: t1 = mul_inv( *ek++ ); michael@107: t2 = -*ek++; michael@107: t3 = -*ek++; michael@107: *--p = mul_inv( *ek++ ); michael@107: *--p = t3; michael@107: *--p = t2; michael@107: *--p = t1; michael@107: michael@107: for(i=0; i < IDEA_ROUNDS-1; i++ ) { michael@107: t1 = *ek++; michael@107: *--p = *ek++; michael@107: *--p = t1; michael@107: michael@107: t1 = mul_inv( *ek++ ); michael@107: t2 = -*ek++; michael@107: t3 = -*ek++; michael@107: *--p = mul_inv( *ek++ ); michael@107: *--p = t2; michael@107: *--p = t3; michael@107: *--p = t1; michael@107: } michael@107: t1 = *ek++; michael@107: *--p = *ek++; michael@107: *--p = t1; michael@107: michael@107: t1 = mul_inv( *ek++ ); michael@107: t2 = -*ek++; michael@107: t3 = -*ek++; michael@107: *--p = mul_inv( *ek++ ); michael@107: *--p = t3; michael@107: *--p = t2; michael@107: *--p = t1; michael@107: memcpy(dk, temp, sizeof(temp) ); michael@107: memset(temp, 0, sizeof(temp) ); /* burn temp */ michael@107: } michael@107: michael@107: static int michael@107: do_idea_setkey( IDEA_context *c, const byte *key, unsigned int keylen ) michael@107: { michael@107: assert(keylen == 16); michael@107: c->have_dk = 0; michael@107: expand_key( key, c->ek ); michael@107: invert_key( c->ek, c->dk ); michael@107: return 0; michael@107: } michael@107: michael@107: static gcry_err_code_t michael@107: idea_setkey (void *context, const byte *key, unsigned int keylen) michael@107: { michael@107: IDEA_context *ctx = context; michael@107: int rc = do_idea_setkey (ctx, key, keylen); michael@107: _gcry_burn_stack (23+6*sizeof(void*)); michael@107: return rc; michael@107: } michael@107: michael@107: static void michael@107: do_idea_encrypt( IDEA_context *c, byte *outbuf, const byte *inbuf ) michael@107: { michael@107: cipher( outbuf, inbuf, c->ek ); michael@107: } michael@107: michael@107: static void michael@107: idea_encrypt (void *context, byte *out, const byte *in) michael@107: { michael@107: IDEA_context *ctx = context; michael@107: do_idea_encrypt (ctx, out, in); michael@107: _gcry_burn_stack (24+3*sizeof (void*)); michael@107: } michael@107: michael@107: static void michael@107: do_idea_decrypt( IDEA_context *c, byte *outbuf, const byte *inbuf ) michael@107: { michael@107: if( !c->have_dk ) { michael@107: c->have_dk = 1; michael@107: invert_key( c->ek, c->dk ); michael@107: } michael@107: cipher( outbuf, inbuf, c->dk ); michael@107: } michael@107: michael@107: static void michael@107: idea_decrypt (void *context, byte *out, const byte *in) michael@107: { michael@107: IDEA_context *ctx = context; michael@107: michael@107: do_idea_decrypt (ctx, out, in); michael@107: _gcry_burn_stack (24+3*sizeof (void*)); michael@107: } michael@107: michael@107: gcry_cipher_spec_t _gcry_cipher_spec_idea = michael@107: { michael@107: "IDEA", NULL, NULL, IDEA_BLOCKSIZE, 128, sizeof (IDEA_context), michael@107: idea_setkey, idea_encrypt, idea_decrypt, michael@107: };