Mon, 28 Jan 2013 17:37:18 +0100
Correct socket error reporting improvement with IPv6 portable code,
after helpful recommendation by Saúl Ibarra Corretgé on OSips devlist.
1 #include <config.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h> /* for memcmp() */
5 #include <assert.h>
7 #include "types.h" /* for byte and u32 typedefs */
8 #include "g10lib.h"
9 #include "cipher.h"
11 /* configuration stuff */
12 #ifdef __alpha__
13 #define SIZEOF_UNSIGNED_LONG 8
14 #else
15 #define SIZEOF_UNSIGNED_LONG 4
16 #endif
18 #if defined(__mc68000__) || defined (__sparc__) || defined (__PPC__) \
19 || (defined(__mips__) && (defined(MIPSEB) || defined (__MIPSEB__)) ) \
20 || defined(__powerpc__) \
21 || defined(__hpux__) /* should be replaced by the Macro for the PA */
22 #define BIG_ENDIAN_HOST 1
23 #else
24 #define LITTLE_ENDIAN_HOST 1
25 #endif
27 #ifndef DIM
28 #define DIM(v) (sizeof(v)/sizeof((v)[0]))
29 #define DIMof(type,member) DIM(((type *)0)->member)
30 #endif
32 /* imports */
33 void g10_log_fatal( const char *fmt, ... );
36 /* local stuff */
38 #define FNCCAST_SETKEY(f) ((int(*)(void*, byte*, unsigned))(f))
39 #define FNCCAST_CRYPT(f) ((void(*)(void*, byte*, byte*))(f))
41 #define IDEA_KEYSIZE 16
42 #define IDEA_BLOCKSIZE 8
43 #define IDEA_ROUNDS 8
44 #define IDEA_KEYLEN (6*IDEA_ROUNDS+4)
46 typedef struct {
47 u16 ek[IDEA_KEYLEN];
48 u16 dk[IDEA_KEYLEN];
49 int have_dk;
50 } IDEA_context;
52 static u16
53 mul_inv( u16 x )
54 {
55 u16 t0, t1;
56 u16 q, y;
58 if( x < 2 )
59 return x;
60 t1 = 0x10001L / x;
61 y = 0x10001L % x;
62 if( y == 1 )
63 return (1-t1) & 0xffff;
65 t0 = 1;
66 do {
67 q = x / y;
68 x = x % y;
69 t0 += q * t1;
70 if( x == 1 )
71 return t0;
72 q = y / x;
73 y = y % x;
74 t1 += q * t0;
75 } while( y != 1 );
76 return (1-t1) & 0xffff;
77 }
79 static void
80 cipher( byte *outbuf, const byte *inbuf, u16 *key )
81 {
82 u16 x1, x2, x3,x4, s2, s3;
83 u16 *in, *out;
84 int r = IDEA_ROUNDS;
85 #define MUL(x,y) \
86 do {u16 _t16; u32 _t32; \
87 if( (_t16 = (y)) ) { \
88 if( (x = (x)&0xffff) ) { \
89 _t32 = (u32)x * _t16; \
90 x = _t32 & 0xffff; \
91 _t16 = _t32 >> 16; \
92 x = ((x)-_t16) + (x<_t16?1:0); \
93 } \
94 else { \
95 x = 1 - _t16; \
96 } \
97 } \
98 else { \
99 x = 1 - x; \
100 } \
101 } while(0)
103 in = (u16*)inbuf;
104 x1 = *in++;
105 x2 = *in++;
106 x3 = *in++;
107 x4 = *in;
108 #ifdef LITTLE_ENDIAN_HOST
109 x1 = (x1>>8) | (x1<<8);
110 x2 = (x2>>8) | (x2<<8);
111 x3 = (x3>>8) | (x3<<8);
112 x4 = (x4>>8) | (x4<<8);
113 #endif
114 do {
115 MUL(x1, *key++);
116 x2 += *key++;
117 x3 += *key++;
118 MUL(x4, *key++ );
120 s3 = x3;
121 x3 ^= x1;
122 MUL(x3, *key++);
123 s2 = x2;
124 x2 ^=x4;
125 x2 += x3;
126 MUL(x2, *key++);
127 x3 += x2;
129 x1 ^= x2;
130 x4 ^= x3;
132 x2 ^= s3;
133 x3 ^= s2;
134 } while( --r );
135 MUL(x1, *key++);
136 x3 += *key++;
137 x2 += *key++;
138 MUL(x4, *key);
140 out = (u16*)outbuf;
141 #ifdef LITTLE_ENDIAN_HOST
142 *out++ = (x1>>8) | (x1<<8);
143 *out++ = (x3>>8) | (x3<<8);
144 *out++ = (x2>>8) | (x2<<8);
145 *out = (x4>>8) | (x4<<8);
146 #else
147 *out++ = x1;
148 *out++ = x3;
149 *out++ = x2;
150 *out = x4;
151 #endif
152 #undef MUL
153 }
155 static void
156 expand_key( const byte *userkey, u16 *ek )
157 {
158 int i,j;
160 for(j=0; j < 8; j++ ) {
161 ek[j] = (*userkey << 8) + userkey[1];
162 userkey += 2;
163 }
164 for(i=0; j < IDEA_KEYLEN; j++ ) {
165 i++;
166 ek[i+7] = ek[i&7] << 9 | ek[(i+1)&7] >> 7;
167 ek += i & 8;
168 i &= 7;
169 }
170 }
172 static void
173 invert_key( u16 *ek, u16 dk[IDEA_KEYLEN] )
174 {
175 int i;
176 u16 t1, t2, t3;
177 u16 temp[IDEA_KEYLEN];
178 u16 *p = temp + IDEA_KEYLEN;
180 t1 = mul_inv( *ek++ );
181 t2 = -*ek++;
182 t3 = -*ek++;
183 *--p = mul_inv( *ek++ );
184 *--p = t3;
185 *--p = t2;
186 *--p = t1;
188 for(i=0; i < IDEA_ROUNDS-1; i++ ) {
189 t1 = *ek++;
190 *--p = *ek++;
191 *--p = t1;
193 t1 = mul_inv( *ek++ );
194 t2 = -*ek++;
195 t3 = -*ek++;
196 *--p = mul_inv( *ek++ );
197 *--p = t2;
198 *--p = t3;
199 *--p = t1;
200 }
201 t1 = *ek++;
202 *--p = *ek++;
203 *--p = t1;
205 t1 = mul_inv( *ek++ );
206 t2 = -*ek++;
207 t3 = -*ek++;
208 *--p = mul_inv( *ek++ );
209 *--p = t3;
210 *--p = t2;
211 *--p = t1;
212 memcpy(dk, temp, sizeof(temp) );
213 memset(temp, 0, sizeof(temp) ); /* burn temp */
214 }
216 static int
217 do_idea_setkey( IDEA_context *c, const byte *key, unsigned int keylen )
218 {
219 assert(keylen == 16);
220 c->have_dk = 0;
221 expand_key( key, c->ek );
222 invert_key( c->ek, c->dk );
223 return 0;
224 }
226 static gcry_err_code_t
227 idea_setkey (void *context, const byte *key, unsigned int keylen)
228 {
229 IDEA_context *ctx = context;
230 int rc = do_idea_setkey (ctx, key, keylen);
231 _gcry_burn_stack (23+6*sizeof(void*));
232 return rc;
233 }
235 static void
236 do_idea_encrypt( IDEA_context *c, byte *outbuf, const byte *inbuf )
237 {
238 cipher( outbuf, inbuf, c->ek );
239 }
241 static void
242 idea_encrypt (void *context, byte *out, const byte *in)
243 {
244 IDEA_context *ctx = context;
245 do_idea_encrypt (ctx, out, in);
246 _gcry_burn_stack (24+3*sizeof (void*));
247 }
249 static void
250 do_idea_decrypt( IDEA_context *c, byte *outbuf, const byte *inbuf )
251 {
252 if( !c->have_dk ) {
253 c->have_dk = 1;
254 invert_key( c->ek, c->dk );
255 }
256 cipher( outbuf, inbuf, c->dk );
257 }
259 static void
260 idea_decrypt (void *context, byte *out, const byte *in)
261 {
262 IDEA_context *ctx = context;
264 do_idea_decrypt (ctx, out, in);
265 _gcry_burn_stack (24+3*sizeof (void*));
266 }
268 gcry_cipher_spec_t _gcry_cipher_spec_idea =
269 {
270 "IDEA", NULL, NULL, IDEA_BLOCKSIZE, 128, sizeof (IDEA_context),
271 idea_setkey, idea_encrypt, idea_decrypt,
272 };