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